ラムダ関数の話 loss_W=lambda W: self.loss(x,t)
こんなラムダ関数がでてきます。loss_W=lambda W: self.loss(x,t)
loss_Wの引数Wはloss(x,t)の引数となっていない?
すると引数Wに何を入れてもloss_Wには影響がない?
ネットで検索すると、同じような質問といろんな角度からの回答がいっぱい出てきます。やはり、この本は人気なんだな、と納得。しかし回答はいくつか読んでみたものの、しっくり頭に入らなかったので、単純化したクラスを作ってみてようやく理解できました。まとめておきます。
2層ニューラルネットワークの仕組み
全体はざっくりとこんな感じ。
TwoLayerNet クラス
numerical_gradient(x,t)
【関数の定義】loss_W = lambda W : self.loss(x,t)
【勾配】grads[W1] = numerical_gradient(loss_W, params[W1])
loss(x,t)
y=self.predict(x)
return cross_entropy_error(y,t)
predict(x)
a1=np.dot(x,params[W1])+b1
z1=sigmoid(a1)
a2=np.dot(z1,params[W2])+b2
y=softmax(a2)
return y
関数
numerical_gradient(loss_W, params[W1])
params[W1]の要素ごとに数値微分を計算
【勾配】return grads[W1]
cross_entropy_error(y,t)
return -np.sum(t*np.log(y+1e-7))/batch_size *スカラー値を返す
足し算ネットワーク
loss_W=lambda W: self.loss(x,t)
これを2層ニューラルネットワークで理解しようとするとなかなか頭に入りません。
そこで『足し算ネットワーク』に単純化してみました。
def numerical_gradient_test(f,x):
print("numerical_gradient_test")
print(" ・fに101を入れても変わらない:f(101)={}".format(f([[101]])))
x[0][0]=101
print(" ・x(=w)を{}に変更すると変わる".format(x[0][0]))
return f(x)
class NetTest:
def __init__(self):
self.w=[[100]]
def predict(self,x):
return x+self.w[0][0]
def loss(self,x,t):
y=self.predict(x)
return y+t
def net_numerical_gradient(self,x,t):
loss_W=lambda W: self.loss(x,t)
print("loss(x,t) = x({}) + t({}) + w({}) = {}".\
format(x,t,self.w[0][0],self.loss(x,t)))
return numerical_gradient_test(loss_W,self.w)
loss_W=lambda W: self.loss(x,t)
loss_Wの引数Wはloss(x,t)の引数となっていないので、loss_Wは引数Wに何を入れても一見影響がないように見えますが、
numerical_gradient(loss_W,self.w)
lossで計算されるpredictの計算要素wを引数にして、
numerical_gradient_test(f,x)
ここでx(=w)を変更すると、lossの引数ではないけど計算要素なので、lossの計算結果が変わります。
ここで、『足し算ネットワーク』に数字を入れて試してみます。
n=NetTest()
x=2
t=5
n.net_numerical_gradient(x,t)
≪出力≫
loss(x,t) = x(2) + t(5) + w(100) = 107
numerical_gradient_test
・fに101を入れても変わらない:f(101)=107
・x(=w)を101に変更すると変わる
108
x,t,wに2,5,100を与えると
loss=2+5+100=107
numerical_gradient_testの中でwを101に変更すると
loss=2+5+101=108
となります。なるほど😉