89156


初めまして．私は今，「ゼロから始めるdeep learning １巻」を学んでいます．そこでGoogle
Colbにて早速自分でコードを作ってみたのですが，runを押すと全く同じデータでもうまく類推できるときと，（誤差関数が突然０になるせいで）学習が止まる時があります．そして色々動かしているうちに，Numpyの中で数値演算の時に何かしら異常があると思い至りました．以下，ソースコードを添付します．やっていることはとても単純で，

「入力x=[4,3,2,1]を与えるから,20を出力するようにパラメタを勾配降下法で探索してください」というものです．（コードが長く複雑に見えますが，ブロックごとにざっくりと流し見していただければわかると思います．コードが質問のエッセンスではないので注視しなくともいいと思います）

問題なく動くのですが，これを何度か実行してみてください．すると全く学習が進んでいない回が現れるはずです．表れなければ入力を少し変えて実行してみてください，例えばx_test=np.array([
4.0034, 3.02,2.00156,1.00009],dtype="float32"
)など微少量変えて．私の環境では，５回に２回くらいの割合で全く学習が進んでいない回が現れます．

x_testに小数点をつけたりするとこのようなことがよく起きたことから，私はNumpyの演算でどこか無理をさせてしまっているのかと思いました（オバーフローやアンダーフローのような）  
対策に演算が困らぬように一律でfloat32型に統一しているのですが，それでもこの不思議な現象は起こります．どうか一緒に原因を考えてはいただけませんでしょうか．よろしくお願いします

[code]

    from numpy.core.multiarray import result_type
    import matplotlib.pyplot as plt
    import numpy as np
    from scipy import linalg
    
    def relu(x):　#活性化関数にRelu
      return np.maximum(0.00,x)
    def sum_squared_error(y,t): #損失関数に二乗和誤差を採用
      return 0.5*np.sum((y-t)**2)
    
    
    
    　　#勾配を出すための偏微分を定義
    def numerical_gradient(f, x):
        h = 1e-4 # 0.0001
        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] = 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
    #--------クラス定義--------
        class testNet:
      def __init__(self):
        self.params={}
        self.params["W"]=0.01*np.random.randn(4,1)
    
    
      def predict(self,x):
        W=self.params["W"]
        a1= np.dot(x, W)
        z1=relu(a1)
        return z1
      
      def loss(self,x, t):
        y=self.predict(x)
        loss=sum_squared_error(y,t)
        return loss
    
      def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x,t)
        grads={}
        grads["W"]=numerical_gradient( loss_W, self.params["W"])
     
    
        return grads
    #------------------------------
    
    x_test=np.array([ 4, 3,2,1],dtype="float32"  )　#入力と
    t_test=np.array([20.0], dtype="float32") #期待する出力
    
    train_loss_list=[]
    iter_list=[]
    pre_list=[]
    net=testNet()
    
    for i in range(100):　#勾配降下法
    
      grads=net.numerical_gradient(x_test, t_test)
      net.params["W"]= net.params["W"]- 0.01*grads["W"]
    
    
      train_loss_list.append(net.loss(x_test,t_test))
      iter_list.append(i)
      pre_list.append(net.predict(x_test) )
    
    
    #結果をプロット
    plt.plot(iter_list, train_loss_list)
    print(pre_list)
    print( net.predict( x_test)  )
    
[/code]


CC BY-SA 4.0
2022-05-30T08:11:52.060
89136
2022-05-31T04:49:40.950
2022-05-31T01:03:07.643
41334
41334
question
python numpy 深層学習 google-colaboratory
簡単なニューラルネットワークにおいて誤差が突然０になって学習が止まる現象について~ Numpyの数値の型との因果関係~


ReLU関数は `x < 0` で勾配が0になります。  
質問のコードでは教師データが `[4, 3, 2, 1]`
の1パターンで、パラメーターは`np.random.randn(4,1)`の正規分布なので、1/2の確率で `f(4, 3, 2, 1) < 0`
になり結果的に`grads = 0`でそれ以上学習が進みません。

実際的なディープラーニングのモデルでは、パラメーター数が多く、教師データも多数ありミニバッチ学習によって変化するため、このような教師データすべてについて勾配が0になることは稀です。

データやパラメーター数を増やすか、勾配が0にならない活性化関数を使うと解決します。

例えば実装が単純なLeakyReLUを使って試すと、10回試行して10回とも20に収束しました。

[code]

    def lrelu(x, alpha=0.3):
      return np.where(x >= 0.0, x, alpha * x)
    
[/code]


CC BY-SA 4.0
2022-05-31T04:19:38.780
89156
2022-05-31T04:49:40.950
2022-05-31T04:49:40.950
3060
241
89136
answer