Chainer:変数に配列を与えて微分してみよう


2017年 01月 19日

前回、特定の値に対する微分係数を求めた。
式で書けば, 関数 f(x) に 対して x=a のときの微分係数 f'(a) を求めた。
そのとき、
x = Variable(np.array([5.0],dtype=np.float16))
として変数xを用意したのだが、np.array([5.0])で、スカラーを要素数1個の配列でわざわざ与えた。
ということは、配列に対しても、そのまま動くのではないだろうか。

ということで、 sin(x) を -np.pi <= x <= np.pi の区間内の複数の点に対して一気に計算してみよう。

まず、配列の生成を確認。
>>> np.array(np.linspace(-np.pi, np.pi, 21))
array([-3.14159265, -2.82743339, -2.51327412, -2.19911486, -1.88495559,
-1.57079633, -1.25663706, -0.9424778 , -0.62831853, -0.31415927,
0.        ,  0.31415927,  0.62831853,  0.9424778 ,  1.25663706,
1.57079633,  1.88495559,  2.19911486,  2.51327412,  2.82743339,
3.14159265])
この配列を与えて、chainerの変数xを配列で作ってしまおう。
>>> x = Variable(np.array(np.linspace(-np.pi, np.pi, 21), dtype=np.float16))
>>> x.data
array([-3.140625  , -2.828125  , -2.51367188, -2.19921875, -1.88476562,
-1.5703125 , -1.25683594, -0.94238281, -0.62841797, -0.31420898,
0.        ,  0.31420898,  0.62841797,  0.94238281,  1.25683594,
1.5703125 ,  1.88476562,  2.19921875,  2.51367188,  2.828125  ,
3.140625  ], dtype=float16)
値が少々違うが、これはnp.float16としたため、精度が落ちているのでやむを得ないだろう。

F.sin(x)にて配列xの各値に対して、まとめてsin(x)が求まるはずである。
>>> y = F.sin(x)
>>> y.data
array([ -9.67502594e-04,  -3.08349609e-01,  -5.87402344e-01,
-8.09082031e-01,  -9.51171875e-01,  -1.00000000e+00,
-9.51171875e-01,  -8.09082031e-01,  -5.87890625e-01,
-3.09082031e-01,   0.00000000e+00,   3.09082031e-01,
5.87890625e-01,   8.09082031e-01,   9.51171875e-01,
1.00000000e+00,   9.51171875e-01,   8.09082031e-01,
5.87402344e-01,   3.08349609e-01,   9.67502594e-04], dtype=float16)
yの値は、 -1 <= sin(x) <= 1 に収まっているようだ。


次に、y.backward() で微分してみよう。
>>> y.backward()
Traceback (most recent call last):
File "", line 1, in 
File "/home/fuji/anaconda3/lib/python3.5/site-packages/chainer/variable.py", line 388, in backward
gxs = func.backward(in_data, out_grad)
File "/home/fuji/anaconda3/lib/python3.5/site-packages/chainer/function.py", line 382, in backward
return self.backward_cpu(inputs, grad_outputs)
File "/home/fuji/anaconda3/lib/python3.5/site-packages/chainer/functions/math/trigonometric.py", line 25, in backward_cpu
gx *= gy[0]
TypeError: ufunc 'multiply' output (typecode 'O') could not be coerced to provided output parameter (typecode 'e') according to the casting rule ''same_kind'
>>>
ということで、backward()したとたんに叱られた。
要素数1だと大丈夫だったのだが、複数個に対してはダメなんだ。
何か悪いことをしたらしい。
 
次回までに原因を考えることにし、今日はここまで。