ゼロから作るDeep Learning ❸ ―フレームワーク編
- 作者:斎藤 康毅
- 発売日: 2020/04/20
- メディア: 単行本(ソフトカバー)
ゼロから作るDeep Learning ③を買った。DezeroのPython実装をRubyに移植する形で独自に勉強している。次はステップ3とステップ4。
- ステップ3:関数を連結する。
関数を連結するために、新しくExp
クラスを作った。
class Exp < Function def forward(x) return x.map{|i| Math.exp(i)} end
さらにcall
が呼ばれたときはforward
が実行されるようにメソッドを変更している。
class Function def call(input) x = input.data y = forward(x) output = Variable.new(y) return output end ...
これを使ってテストをしてみる。Square
とExp
を使って連結して関数を作った。
A = Square.new() B = Exp.new() C = Square.new() x = Variable.new([0.5]) a = A.call(x) b = B.call(a) y = C.call(b) puts(y.data)
1.648721270700128
上手く行った。
- ステップ4:合成微分
次にnumerial_diff
関数を実装した。単純に差分を取って数値微分を行う関数だ。
def numerical_diff(f, x, eps=1e-4) x0 = Variable.new(x.data.map{|i| i - eps}) x1 = Variable.new(x.data.map{|i| i + eps}) y0 = f.call(x0) y1 = f.call(x1) return (y1.data.zip(y0.data).map{|i1, i0| i1 - i0}).map{|i| i / (2 * eps)} end
結構ややこしいことになっている。配列を受け取ることを前提に作っているので、各配列にmap
を使ったりzip
を使ったりしないといけないのがつらいが、どうにか動くようになった。
f = Square.new() x = Variable.new([2.0]) dy = numerical_diff(f, x) puts(dy)
4.000000000004
さらにこれらの関数オブジェクトを合成するためのf_func
を作ったのだが、これをnumerial_diff
に渡すためにはどうすればよいのかはたと困ってしまった。
def f_func(x) a = Square.new() b = Exp.new() c = Square.new() return c.call(b.call(a.call(x))) end
しかしRubyにはmethod
がある。関数をメソッドとしてオブジェクト化し引数としてnumerial_diff
に渡してしまうという作戦だ。
def f_func(x) a = Square.new() b = Exp.new() c = Square.new() return c.call(b.call(a.call(x))) end x = Variable.new([0.5]) dy = numerical_diff(method(:f_func), x) puts dy
3.2974426293330694
上手く行ったようだ。