36363


オライリー・ジャパンの「ゼロから作る Deep Learning」という本についての質問です。

疑問は、「定数関数を微分してるから結果はゼロになるんじゃないか？」というものですが、とりあえず関数を見てください。本を持ってる人は、p.159ページです。

[code]

    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)
    
    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
    
[/code]

問題はnumerical_gradientで、これにxとtを代入すると、まずself.loss(x,
t)が定数として確定します(これをcとおきます)。次に、loss_W = lambda W: self.loss(x,
t)は、Wに関係なく定数cを返す定数関数として確定します。これに対してnumerical_gradientをしてもcの微分なので0しか返ってこないのでは？

numerical_gradientの中身は次のようになります。

[code]

    def numerical_gradient(f, x):
        h = 1e-4
        grad = np.zeros_like(x)
    
        for idx in range(x.size):
            tmp_val=x[idx]
            # f(x+h)の計算
            x[idx] = tmp_val + h
            fxh1 = f(x)
    
            #f(x-h)の計算
            x[idx] = tmp_val - h
            fxh2 = f(x)
    
            grad[idx] = (fxh1 - fxh2) / (2*h)
            x[idx] = tmp_val
    
        return grad
    
[/code]

つまり、numerical_gradient(loss_W,
self.params['W1'])は、loss_W(Wij+h)やloss_W(Wij-h)を計算して(loss_W(Wij+h) -
loss_W(Wij-h))/ (2*h)とかを出力しますが、loss_W(Wij+h)=loss_W(Wij-h)=self.loss(x,
t)=cなので、ゼロしか返さないのでは？ということです。

わかる方お願いします！


CC BY-SA 3.0
2017-07-14T10:46:39.937
36359
2017-07-14T13:07:53.587
question
python 深層学習 機械学習
ゼロから作るDeep Learning：定数関数の微分


私もその本をたまたま持ってます。

> 次に、`loss_W = lambda W: self.loss(x, t)`は、Wに関係なく定数cを返す定数関数として確定します。

これが違いますね。`loss_W`は`self`つまりインスタンスオブジェクトのデータに依存して計算します。つまり`self`の持つデータが変われば`loss_W`の返す値も変わりうるのです。

そして、どこで`self`の持つデータが変わっているのかというと、それは`numerical_gradient`の中です。

[code]

    grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
    
[/code]

ここで`self.params['W1']`が引数`x`として渡されています。`self.params['W1']`は、本を見るとわかりますが`ndarray`(numpyの配列)です。

次に `numerical_gradient`の定義を見ると、

[code]

    x[idx] = tmp_val + h
    
[/code]

ここで`x`のmutationが起きています。これによって、`self`の持つデータが変わったわけです。  
このあとに

[code]

    fxh1 = f(x)
    
[/code]

で`f`つまり`loss_W`が実行されて、`self.params['W1']`が少しだけ増えたときの値が返るというわけです。


CC BY-SA 3.0
2017-07-14T13:07:53.587
36363
2017-07-14T13:07:53.587
20206
36359
answer