次回より『ヒデログ』とご検索ください

loss_W = lambda W: self.loss(x, t)の解説:ゼロから作るDeep Learning

ゼロから作るDeep Learning」の5章P159ページのクラスTwoLayerNetの中にあるloss_W = lambda W: self.loss(x, t)がどういう意味なのか理解できなかったので、デバックを繰り返し、簡単なサンプルを使ってようやく理解できたので解説します。

この記事を読むと分かる事
loss_W = lambda W: self.loss(x, t)
がどうしているのか?が分かります。

「ゼロから作るDeep Learning」の問題のポイント

    # x:入力データ, t:教師データ
class  TwoLayerNet:
‥‥‥‥‥‥‥‥‥
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads

def numerical_gradient(f, x):
    # h = 1e-4 # 0.0001
    h=100
    grad = np.zeros_like(x)
    
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x) # f(x+h)
        
        x[idx] = tmp_val - h 
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
        x[idx] = tmp_val # 値を元に戻す
        it.iternext()   
        
    return grad

この部分ですよね。どうなっているのか分からないです。

loss_W = lambda W: self.loss(x, t)を理解するサンプルコード

loss_W = lambda W: self.loss(x, t)を理解するためのン簡単なサンプルを作ったので、それで解説したいと思います。デバックすると尚よくわかります。

class TwoLayerNet:
    def __init__(self):
        self.param={}
        self.param[0]=[1,2]
    def loss(self,x,t):
        y=x*t
        n=self.param[0]
        return y
    def numerical_gredient(self,x,t):
        loss_w=lambda W:self.loss(x,t)
        a= numerical_gredient(loss_w,self.param[0])
        return a

def numerical_gredient(f,x):
    x[0]=x[0]+100
    b=f(x)
    return b

network=TwoLayerNet()
network.numerical_gredient(5,30)
print(network.param)

分かりやすいようにクラス名やメソッドは、サンプルプログラムと同じ名称にしています。

コード解説

19行目でオブジェクトを宣言。

20行目でオブジェクトのメソッドnumerical_gredientを呼び出しています。

9行目が呼び出されたメソッドnumerical_gredientです。※14行目の関数numerical_gredientとは違うので要注意です(サンプルプログラムでも同じ名称になっていました、この点はあまりよくないかと思います)。再帰関数と間違える人もいたでしょう。

10行目
のでloss_wself:loss(x,t)の関数であることが宣言されています。

11行目(関数,変数)を引数とする関数numerical_gradientが呼び出されています。

この時network.numerical_gradient(5,30)での(5,30)は全く関係ない外の変数となっている点に注意です。あくまでxself.param[0]です。

15行目x[0](=self.param[0])に+100されます。

16行目で関数f(=loss_w)x(=self.param[0])が渡されているのかと思いきやloss_wの引数は(x,t)(=(5,30))ですのでこの場合(5,30)が渡されてx(=self.param[0])は関数の引数としては渡されていません。ただし、配列なので参照変数としてすでにself.param[0]の値が変わっていて、また、クラスの中に戻るので変数として内側からアクセスできます。

このように入れ子になりすぎているような感じもしますので、この簡易サンプルコードデバックしていただければどうなっているのか分かるかと思います。

元のサンプルコードですと、変数の配列のサイズが多すぎてデバックで見ていくことが極めて大変でしょうから。

愚痴

著者が頭がいいのは分かったけど、なんで読者のレベルに合わせてサンプルプログラムを作らなかったのか?そこの点は評価が下がります。正直のこのステップだけで1日以上理解するのにかかってしまった私のレベルが低いのでしょうか・・・まだまだ、勉強が必要ですね。

続きを勉強したい人は「ゼロから作る Deep Learning ❷」と「ゼロから作る Deep Learning ❸」が出ていますので挑戦してみてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です