Chainer:簡単な微分をしてみよう


2017年 01月 16日

DLするためには、微分して勾配を求める必要がある。
ということで、まず、簡単な微分をしてみよう。

Chainerを動かすためには、まず最初に色々なものをimportしなければならない。
とりあえず、「おまじない」だと思って、プログラムの最初に書いておこう。

# おまじない
import numpy as np
import chainer
from chainer import cuda, Function, gradient_check, Variable
from chainer import optimizers, serializers, utils
from chainer import Link, Chain, ChainList
import chainer.functions as F
import chainer.links as L
微分するためには、まず変数を作らないといけない。
それも、Pythonの変数ではなく、Chainerの変数として作らないといけない。
そのために、ちゃんとVariableをimportしているので、さっそくやってみよう。

>>> x = Variable( 5.0 )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/fuji/anaconda3/lib/python3.5/site-packages/chainer/variable.py", line 95, in __init__
raise TypeError(msg)
TypeError: numpy.ndarray or cuda.ndarray are expected.
Actual: <class 'float'>
>>>
エラーメッセージから、Variableに直接5.0を与えてはだめで、型がnumpy.ndarrayかcuda.ndarrayになっていないとダメらしい。
ということで、要素数1個だけの配列にして、変数xを作って、y=x**2-2x+1 を与え微分してみた。
微分は、y.backward()にて行われている。
>>> x = Variable(np.array([5.0]))
>>> y = x**2 - 2 * x + 1
>>> y.data
array([ 16.])
>>> y.backward()
>>> x.grad
array([ 8.])
x=5のときのy=f(x)の値は、
y = x**2 – 2 * x + 1 にてforward処理が行われ、y.dataに値が求まっていて、f(5)=16が確認できる。

微分はy.backward()で行われ、結果は x.gradに入り、yのメンバーの何かに入るのではない。
今回は、yに含まれる変数がxただ1つだったが、DLでは多変数の微分(偏微分)が行われ、それぞれの変数の.gradに偏微分(微分係数)が入る。

y = x**2 – 2 * x + 1 をxで微分すると、dy/dx = 2*x – 2 なのだが、x=5のときの微分係数が求まるだけである。
x=5のときの微分係数が8であることは、次のようにしても確かめられる。

>>> dy = 2 * x - 2
>>> dy.data
array([ 8.])

何も指定しなかったので、
>>> type(x.data[0])
&lr;class 'numpy.float64'>
>>> type(y.data[0])
<class 'numpy.float64'&l\gt;
>>> type(x.grad[0])
<class 'numpy.float64'>
という風に、全部float64になってしまった。
DLでは精度はそれほど要らないので、とりあえずfloat32と思ったが、float16も用意されているので、使ってみた。
>>> x = Variable(np.array([5.0],dtype=np.float16))
>>> y = x**2 - 2 * x + 1
>>> y.backward()
>>> x.grad[0]
8.0
>>> type(x.grad[0])
<class 'numpy.float16'>

今回は簡単過ぎる微分だったので、次はもうちょっと高度な微分をやらせてみよう。