9. 計算グラフの例例
l このグラフは z = x ** 2 + 2 * x * y + y という式を表す
9
x
y
_ ** 2
2 * _ _ * _ _ + _ z
_ + _
10. 誤差逆伝播(後退型⾃自動微分)
l 合成関数の微分を計算するには連鎖律律 (chain rule) をつかう
l たとえば を微分すると
– ヤコビ⾏行行列列の掛け算になっている
l ニューラルネットの最適化では、⽬目的関数はスカラーで、微分したいパラメー
タや中間変数は⾼高次元のベクトル
l 上の式でいえば がスカラーで、 はベクトル
l この場合(上の式で)左からかけていったほうが効率率率が良良い
– つまり (出⼒力力)から (⼊入⼒力力)に向けてヤコビ⾏行行列列を順にかけていく
– もとの関数と逆順なので誤差逆伝播法という
10
z
z = h(y), y = g(x), x = f(w)
z
w
=
z
y
y
x
x
w
= Dh(y)Dg(x)Df (w)
w, x, y
z w
18. 順伝播
l 今まで「変数」と呼んでいたものは、Chainer では Variable オブジェクト
l Variable オブジェクトを特殊な「関数」に⼊入れると、順伝播を実⾏行行しながら計
算グラフが構築される
– 「関数」は Function オブジェクト
– 簡単な四則演算などは Variable オブジェクト⾃自体に定義されている
– ほかの Function は chainer.functions(F と略略記)にたくさん⽤用意さ
れている
x = Varaible(...)
y = Variable(...)
z = x ** 2 + 2 * x * y + y
18
x
y
_**2
2*_ _*_ _+_ z
_+_
25. Chainer を使う場合の全体の流流れ
1. FunctionSet にパラメータ付き関数を定義する
2. Optimizer を定義して、FunctionSet を設定する
3. forward 関数を定義する
4. データセットを読み込み、訓練⽤用と評価⽤用にわける
5. 訓練ループを回す
a. 勾配をゼロ初期化
b. forward 関数を呼び、得られたロス値の backward メソッドを呼ぶ
c. 正則化処理理をして、update
6. 適当な頻度度で評価ループを回す
a. forward 関数を呼んで結果を記録
25
26. 例例:MNIST
# Model definition
model = FunctionSet(
l1=F.Linear(784, 100),
l2=F.Linear(100, 100),
l3=F.Linear(100, 10))
opt = optimizers.SGD()
opt.setup(model)
# Forward computation
def forward(x, t):
h1 = F.relu(model.l1(x))
h2 = F.relu(model.l2(h1))
y = model.l3(h2)
return F.softmax_cross_entropy(
y, t)
# Training loop
for epoch in xrange(n_epoch):
for i in xrange(0, N, batchsize):
x = Variable(...)
t = Variable(...)
opt.zero_grads()
loss = forward(x, t)
loss.backward()
opt.update()
27. 新しい Function を⾃自分で定義する
l Function は Python で新しく作ることができる
l forward(_̲cpu/_̲gpu) と backward(_̲cpu/_̲gpu) を実装する必要がある
l これらは配列列のタプルを受け取って、配列列のタプルを返す
class SquaredDiff(Function):
def forward_cpu(self, inputs):
x, y = inputs
z = x – y
return z * z,
def backward_cpu(self, inputs, grad_outputs):
x, y = inputs
gz = grad_outputs
gx = 2 * (x – y) * gz
return gx, -gx
27
33. 単語埋め込み
l 単語を ID で表したものを対応する密ベクトルに変換する
– この密ベクトルも学習の対象
l F.EmbedID がこれを実装している
– パラメータ付きの Function
– つくるときに ID の範囲と密ベクトルの次元を指定する
– int32 配列列が⼊入った Variable を受け取って、float32 配列列が⼊入った
Variable を返す
l 例例えば 1 万語彙を 200 次元に埋め込みたい場合は以下のようにする
embedder = F.Embed(10000, 200)
word_arr = np.ndarray((10,), dtype=np.int32)
word = Variable(word_arr)
x = embedder(word) #=> サイズ 10 x 200 の配列列が⼊入った変数
33
34. Recurrent Net
l 時刻を 1 ステップ分だけ実⾏行行する関数を書いて、それを for ⽂文の中から呼び出
す
l リカレントな部分は、状態を保持する変数を持っておいてループの中でつかう
l 内部的には展開された DAG が作られる
def forward_one_step(x, h, t):
h = F.tanh(model.input(x) + model.lateral(h))
y = model.output(h)
return F.softmax_cross_entropy(y, t), h
h = Variable(np.zeros((1, 200), dtype=np.float32))
accum_loss = 0
for x, t in input_seq:
loss, h = forward_one_step(x, h, t)
accum_loss += loss
34
35. 例例:RNN ⾔言語モデル
# Model definition
model = FunctionSet(
emb=F.EmbedID(1000, 50),
h2h=F.Linear( 50, 50),
h2y=F.Linear( 50, 1000))
opt = optimizers.SGD()
opt.setup(model)
# Forward computation of one step
def fwd1step(h, w, t):
x = model.emb(w)
h = F.tanh(x + model.h2h(h))
y = model.h2y(h)
return F.softmax_cross_entropy(
y, t), h
# Full RNN forward computation
def forward(seq):
h = Variable(...) # init state
accum_loss = 0
for curw, nextw in
zip(seq, seq[1:]):
x = Variable(curw)
t = Variable(nextw)
loss, h = fwd1step(h, x, t)
accum_loss += loss
return accum_loss