Pythonニューラルネットワークパート2:勾配降下

パート1



コードをすぐに提供してください!



import numpy as np X = np.array([ [0,0,1],[0,1,1],[1,0,1],[1,1,1] ]) y = np.array([[0,1,1,0]]).T alpha,hidden_dim = (0.5,4) synapse_0 = 2*np.random.random((3,hidden_dim)) - 1 synapse_1 = 2*np.random.random((hidden_dim,1)) - 1 for j in xrange(60000): layer_1 = 1/(1+np.exp(-(np.dot(X,synapse_0)))) layer_2 = 1/(1+np.exp(-(np.dot(layer_1,synapse_1)))) layer_2_delta = (layer_2 - y)*(layer_2*(1-layer_2)) layer_1_delta = layer_2_delta.dot(synapse_1.T) * (layer_1 * (1-layer_1)) synapse_1 -= (alpha * layer_1.T.dot(layer_2_delta)) synapse_0 -= (alpha * XTdot(layer_1_delta))
      
      





パート1:最適化



最初の部分では、単純なニューラルネットワークでの逆伝播の基本原理について説明しました。 ネットワークにより、各ネットワークの重みがエラーにどのように寄与するかを測定できました。 そしてこれにより、別のアルゴリズムである勾配降下法を使用して重みを変更できました。



何が起こっているかの本質は、逆伝播はネットワークに最適化を導入しないということです。 ネットワークの端から内部のすべての重みに誤った情報を移動するため、別のアルゴリズムがすでにこれらの重みを最適化してデータに一致させることができます。 しかし、原則として、逆伝播で使用できる非線形最適化の他の方法が豊富にあります。



いくつかの最適化方法:





差異の視覚化:





さまざまな方法がさまざまなケースに適しており、場合によっては組み合わせることもできます。 このレッスンでは、勾配降下を検討します。これは、最も単純で最も一般的なニューラルネットワーク最適化アルゴリズムの1つです。 したがって、設定とパラメーター化によりニューラルネットワークを改善します。



パート2:勾配降下



丸いバスケットに赤いボールがあるとしましょう(下の写真)。 ボールは底を見つけようとしています。 これは最適化です。 この例では、ボールはバケット内の最低点を探して、左から右にその位置を最適化します。



ボールには、左または右の2つの移動オプションがあります。 目標は、可能な限り低い位置を取ることです。 キーボードからボールを​​制御する場合は、ボタンを左右に押す必要があります。



画像



この場合、ボールは、現在の位置(壁に接している、青で表示)でのバケットの側面の勾配のみを認識しています。 傾きが負の場合、ボールは右に移動する必要があることに注意してください。 正の場合-左側。 明らかに、この情報は数回の繰り返しでバケットの底を見つけるのに十分です。 この種の最適化は、勾配最適化と呼ばれます。



画像



HSの最も単純なケース:





問題は、各ステップでボールがどれだけ動くかです。 写真は、下から遠くなるほど、勾配が急になることを示しています。 この知識を使用してアルゴリズムを改善します。 また、バケットは平面(x、y)上にあると仮定します。 したがって、ボールの位置はx座標によって決まります。 xを大きくすると、ボールが右に移動します。



最も単純な勾配降下法:





このアルゴリズムは既に少し最適化されています。これは、大きな勾配の場合は大幅なシフトを行い、小さな勾配の場合は小さなシフトを行うためです。 その結果、バスケットの底に近づくと、ボールは傾きがゼロのポイントに到達するまで、すべての減少する変動を行います。 これが収束点になります。



パート3:時々うまくいかない



勾配降下は不完全です。 彼の問題と人々がそれらをどうやって回避するかを考えてください。



問題1:勾配が大きすぎる


私たちのステップは、斜面の大きさに依存します。 大きすぎる場合、必要なポイントを飛び越えることができます。 あまり激しくジャンプしなくても怖くない。 しかし、あなたはそれを非常にジャンプすることができるので、以前よりもさらに遠くなるでしょう。



画像



そして、すでにそこに、私たちはもちろん、より大きなバイアスを見つけ、さらにジャンプし、分岐を取得します。



解決策1:バイアスを減らす


0から1の数字(たとえば、0.01)で乗算します。 この定数をアルファと呼びましょう。 そのような削減の後、ネットワークは収束します。これは、目的のポイントにそれほどジャンプしないためです。



画像



勾配降下の改善:



alpha = 0.1(または0〜1の任意の数)





問題2:ローカル低


時々、バケツは非常にcな形をしており、斜面をたどるだけでは絶対的な最小値にならないことがあります。



画像



これが最も難しい勾配降下問題です。 それを回避する方法はたくさんあります。 通常、彼らはバケットのさまざまな部分を試し、ランダム検索を使用します。



解決策2:複数のランダムな開始点


さて、しかし、グローバル最小値を見つけるためにランダム性を使用する場合、なぜ最適化を行う必要があるのでしょうか? ランダムに解決策を模索するでしょうか?



画像



このチャートを検討してください。 ラインに100の目標を設定し、それらの最適化を開始したとしましょう。 その結果、それらは色付きの円でマークされた5つの位置になります。 色付きの領域は、各ローカルミニマムの所有権を示します。 たとえば、ボールが青い領域に落ちた場合、青い最小値になります。 つまり、空間全体を探索するために、ランダムに5箇所だけを見つける必要があります。 これは、行のすべての場所を試行する完全にランダムな検索よりもはるかに優れています。



ニューラルネットワークに関しては、これは非常に大きな隠れレベルを設定することで実現できます。 レベル内の各非表示ノードは、ランダムな状態で動作を開始します。 次に、各ノードは何らかの最終状態に収束します。 そのサイズにより、ネットワークユーザーは同じネットワーク上で数千または数百万の異なるローカルミニマムを試すことができます。



注1:これらはニューラルネットワークであり、有益です。 スペース全体を計算することなく、スペースを検索する機会があります。 5つのボールと少数の反復を使用して、上の図の黒い線全体を検索できます。 ブルートフォース検索では、数桁のプロセッサー能力が必要になります。



注2:好奇心reader盛な読者は、「なぜ、多数の異なるノードを同じポイントに収束させるべきなのでしょうか?」と尋ねます。 これは計算能力の無駄です!」 いい質問です。 隠されたノードを回避するアプローチもあります-これらはドロップアウトとドロップ接続です。これについては後で説明します。



問題3:勾配が小さすぎる



斜面は時々小さすぎます。 そのようなスケジュールを検討してください。



画像



ボールが詰まっています。 これは、アルファが小さすぎる場合に発生します。 彼はすぐに局所的な最小値を見つけ、他のすべてを無視します。 そして、もちろん、このような小さな動きでは、収束には非常に長い時間がかかります。



画像



解決策3:アルファを増やす


明らかに、アルファを増やすことができ、デルタに1より大きい数値を掛けることさえできます。これはめったに使用されませんが、実際に起こります。



パート4:ニューラルネットワークの確率的勾配降下


では、これらのボールとラインは、ニューラルネットワークと逆伝播にどのように関係していますか? このトピックは複雑であると同時に重要です。



画像



ニューラルネットワークでは、重みに関するエラーを最小限に抑えようとします。 この線は、スケールの1つの位置に関するネットワークエラーを表します。 重みのいずれかの可能な値のネットワークエラーを計算した場合、結果はそのような線で表されます。 次に、最小誤差(曲線の最低部分)に対応する重み値を選択します。 グラフは2次元なので、1つの重みを言います。 xは重み値、yは重みがxの値に含まれる瞬間のニューラルネットワークのエラーです。



では、このプロセスが単純な2レベルのニューラルネットワークでどのように機能するかを見てみましょう。



 import numpy as np #    def sigmoid(x): output = 1/(1+np.exp(-x)) return output #      def sigmoid_output_to_derivative(output): return output*(1-output) #   X = np.array([ [0,1], [0,1], [1,0], [1,0] ]) #   y = np.array([[0,0,1,1]]).T #     np.random.seed(1) #      0 synapse_0 = 2*np.random.random((2,1)) - 1 for iter in xrange(10000): #   layer_0 = X layer_1 = sigmoid(np.dot(layer_0,synapse_0)) #   ? layer_1_error = layer_1 - y #      #    l1 layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1) synapse_0_derivative = np.dot(layer_0.T,layer_1_delta) #   synapse_0 -= synapse_0_derivative print "  :" print layer_1
      
      







この例では、出力に1行のエラーがあり、35行目でカウントされます(layer_1_error = layer_1-y)。 2つの重みがあるため、エラーのあるチャートは3次元空間に配置されます。 これはスペース(x、y、z)になり、エラーが垂直に移動します。xとyはsyn0の重みの値です。



データセットのエラーサーフェスを描画してみましょう。 特定の重みセットの誤差をどのように計算しますか? このカウントは、行31、32、および35にあります。



 layer_0 = X layer_1 = sigmoid(np.dot(layer_0,synapse_0)) layer_1_error = layer_1 - y
      
      







重みのセットに対して一般的なエラー(xおよびyの場合は-10〜10)を描画すると、次のようになります。



画像



実際、すべてが単純です-可能なすべての重みの組み合わせと、各セットでネットワークによって生成されたエラーを計算します。 xはsynapse_0の最初の重みであり、yはsynapse_0の2番目の重みです。 zはエラーです。 ご覧のとおり、出力は最初の入力セットと正の相関があります。 したがって、xが大きい場合、エラーは最小になります。 どう? いつ最適ですか?



2層ネットワークはどのように最適化されていますか?


そのため、示された3行でエラーをカウントする場合、次はネットワークを最適化してエラーを減らします。 これは、勾配降下が発生する場所です。



 layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1) synapse_0_derivative = np.dot(layer_0.T,layer_1_delta) synapse_0 -= synapse_0_derivative
      
      







擬似コードを思い出してください:





これだ。 変更は、1つの重みではなく2つの重みを最適化することだけです。 論理は同じです。



パート5:ニューラルネットワークの改善



改善1:アルファの追加とカスタマイズ


アルファとは? 前述のように、このオプションは各反復更新のサイズを縮小します。 最後の時点で、重みを更新する前に、更新サイズにアルファ(通常は0〜1)を掛けます。 そして、このような最小限のコード変更は、彼のトレーニング能力に大きく影響します。



前の記事の3レベルのネットワークに戻り、alphaパラメーターを適切な場所に追加しましょう。 次に、アルファに関するすべてのアイデアを実際のコードに合わせるための実験を行います。







 import numpy as np alphas = [0.001,0.01,0.1,1,10,100,1000] #    def sigmoid(x): output = 1/(1+np.exp(-x)) return output #      def sigmoid_output_to_derivative(output): return output*(1-output) X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) y = np.array([[0], [1], [1], [0]]) for alpha in alphas: print "\n  Alpha:" + str(alpha) np.random.seed(1) #      0 synapse_0 = 2*np.random.random((3,4)) - 1 synapse_1 = 2*np.random.random((4,1)) - 1 for j in xrange(60000): #     0, 1  2 layer_0 = X layer_1 = sigmoid(np.dot(layer_0,synapse_0)) layer_2 = sigmoid(np.dot(layer_1,synapse_1)) #   ? layer_2_error = layer_2 - y if (j% 10000) == 0: print "  "+str(j)+" :" + str(np.mean(np.abs(layer_2_error))) #    ? #   ?  ,       layer_2_delta = layer_2_error*sigmoid_output_to_derivative(layer_2) #     l1     l2 (   )? layer_1_error = layer_2_delta.dot(synapse_1.T) #     l1? #   ?  ,       layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1) synapse_1 -= alpha * (layer_1.T.dot(layer_2_delta)) synapse_0 -= alpha * (layer_0.T.dot(layer_1_delta))
      
      







   alpha:0.001   0 :0.496410031903   10000 :0.495164025493   20000 :0.493596043188   30000 :0.491606358559   40000 :0.489100166544   50000 :0.485977857846   alpha:0.01   0 :0.496410031903   10000 :0.457431074442   20000 :0.359097202563   30000 :0.239358137159   40000 :0.143070659013   50000 :0.0985964298089   alpha:0.1   0 :0.496410031903   10000 :0.0428880170001   20000 :0.0240989942285   30000 :0.0181106521468   40000 :0.0149876162722   50000 :0.0130144905381   alpha:1   0 :0.496410031903   10000 :0.00858452565325   20000 :0.00578945986251   30000 :0.00462917677677   40000 :0.00395876528027   50000 :0.00351012256786   alpha:10   0 :0.496410031903   10000 :0.00312938876301   20000 :0.00214459557985   30000 :0.00172397549956   40000 :0.00147821451229   50000 :0.00131274062834   alpha:100   0 :0.496410031903   10000 :0.125476983855   20000 :0.125330333528   30000 :0.125267728765   40000 :0.12523107366   50000 :0.125206352756   alpha:1000   0 :0.496410031903   10000 :0.5   20000 :0.5   30000 :0.5   40000 :0.5   50000 :0.5
      
      







異なるアルファ値からどのような結論を引き出すことができますか?



アルファ= 0.001

非常に低い値では、ネットワークはまったく収束しません。 スケールの更新が小さすぎます。 60,000回の反復後でもほとんど変化はありません。 これが私たちの問題#3:勾配が小さすぎるときです。



アルファ= 0.01

良好な収束。60,000回の繰り返しをスムーズに通過しますが、他の場合ほど目標に近く収束しませんでした。 同じ問題番号3。



アルファ= 0.1

最初は非常に速く歩きましたが、その後は遅くなりました。 これはまだ3番目の問題です。



アルファ= 1

好奇心reader盛な読者は、この場合の収束がアルファがない場合とまったく同じであることに気付くでしょう。 1を掛けます。



アルファ= 10

サプライズ-アルファが1を超えると、結果は10,000人になりました。 そのため、これまでのスケールの更新は小さすぎました。 そのため、ウェイトは正しい方向に移動していましたが、その直前にはウェイトが動きすぎていました。



アルファ= 100

値が大きすぎると逆効果になります。 ネットワークのステップが非常に大きいため、エラーの表面で最低点を見つけることができません。 これが私たちの一番の問題です。 ネットワークはエラーの表面を単に前後にジャンプし、どこにも最小値を見つけません。



アルファ= 1000

減少ではなくエラーの増加が発生し、値0.5で停止します。 これは、問題番号3のより極端なバージョンです。



結果を詳しく見てみましょう



 import numpy as np alphas = [0.001,0.01,0.1,1,10,100,1000] #    def sigmoid(x): output = 1/(1+np.exp(-x)) return output #      def sigmoid_output_to_derivative(output): return output*(1-output) X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) y = np.array([[0], [1], [1], [0]]) for alpha in alphas: print "\n  alpha:" + str(alpha) np.random.seed(1) #      0 synapse_0 = 2*np.random.random((3,4)) - 1 synapse_1 = 2*np.random.random((4,1)) - 1 prev_synapse_0_weight_update = np.zeros_like(synapse_0) prev_synapse_1_weight_update = np.zeros_like(synapse_1) synapse_0_direction_count = np.zeros_like(synapse_0) synapse_1_direction_count = np.zeros_like(synapse_1) for j in xrange(60000): #     0, 1  2 layer_0 = X layer_1 = sigmoid(np.dot(layer_0,synapse_0)) layer_2 = sigmoid(np.dot(layer_1,synapse_1)) #   ? layer_2_error = y - layer_2 if (j% 10000) == 0: print "Error:" + str(np.mean(np.abs(layer_2_error))) #    ? #   ?  ,       layer_2_delta = layer_2_error*sigmoid_output_to_derivative(layer_2) #     l1     l2 (   )? layer_1_error = layer_2_delta.dot(synapse_1.T) #     l1? #   ?  ,       layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1) synapse_1_weight_update = (layer_1.T.dot(layer_2_delta)) synapse_0_weight_update = (layer_0.T.dot(layer_1_delta)) if(j > 0): synapse_0_direction_count += np.abs(((synapse_0_weight_update > 0)+0) - ((prev_synapse_0_weight_update > 0) + 0)) synapse_1_direction_count += np.abs(((synapse_1_weight_update > 0)+0) - ((prev_synapse_1_weight_update > 0) + 0)) synapse_1 += alpha * synapse_1_weight_update synapse_0 += alpha * synapse_0_weight_update prev_synapse_0_weight_update = synapse_0_weight_update prev_synapse_1_weight_update = synapse_1_weight_update print "Synapse 0" print synapse_0 print "Synapse 0 Update Direction Changes" print synapse_0_direction_count print "Synapse 1" print synapse_1 print "Synapse 1 Update Direction Changes" print synapse_1_direction_count
      
      







   alpha:0.001 Error:0.496410031903 Error:0.495164025493 Error:0.493596043188 Error:0.491606358559 Error:0.489100166544 Error:0.485977857846 Synapse 0 [[-0.28448441 0.32471214 -1.53496167 -0.47594822] [-0.7550616 -1.04593014 -1.45446052 -0.32606771] [-0.2594825 -0.13487028 -0.29722666 0.40028038]] Synapse 0 Update Direction Changes [[ 0. 0. 0. 0.] [ 0. 0. 0. 0.] [ 1. 0. 1. 1.]] Synapse 1 [[-0.61957526] [ 0.76414675] [-1.49797046] [ 0.40734574]] Synapse 1 Update Direction Changes [[ 1.] [ 1.] [ 0.] [ 1.]]   alpha:0.01 Error:0.496410031903 Error:0.457431074442 Error:0.359097202563 Error:0.239358137159 Error:0.143070659013 Error:0.0985964298089 Synapse 0 [[ 2.39225985 2.56885428 -5.38289334 -3.29231397] [-0.35379718 -4.6509363 -5.67005693 -1.74287864] [-0.15431323 -1.17147894 1.97979367 3.44633281]] Synapse 0 Update Direction Changes [[ 1. 1. 0. 0.] [ 2. 0. 0. 2.] [ 4. 2. 1. 1.]] Synapse 1 [[-3.70045078] [ 4.57578637] [-7.63362462] [ 4.73787613]] Synapse 1 Update Direction Changes [[ 2.] [ 1.] [ 0.] [ 1.]]   alpha:0.1 Error:0.496410031903 Error:0.0428880170001 Error:0.0240989942285 Error:0.0181106521468 Error:0.0149876162722 Error:0.0130144905381 Synapse 0 [[ 3.88035459 3.6391263 -5.99509098 -3.8224267 ] [-1.72462557 -5.41496387 -6.30737281 -3.03987763] [ 0.45953952 -1.77301389 2.37235987 5.04309824]] Synapse 0 Update Direction Changes [[ 1. 1. 0. 0.] [ 2. 0. 0. 2.] [ 4. 2. 1. 1.]] Synapse 1 [[-5.72386389] [ 6.15041318] [-9.40272079] [ 6.61461026]] Synapse 1 Update Direction Changes [[ 2.] [ 1.] [ 0.] [ 1.]]   alpha:1 Error:0.496410031903 Error:0.00858452565325 Error:0.00578945986251 Error:0.00462917677677 Error:0.00395876528027 Error:0.00351012256786 Synapse 0 [[ 4.6013571 4.17197193 -6.30956245 -4.19745118] [-2.58413484 -5.81447929 -6.60793435 -3.68396123] [ 0.97538679 -2.02685775 2.52949751 5.84371739]] Synapse 0 Update Direction Changes [[ 1. 1. 0. 0.] [ 2. 0. 0. 2.] [ 4. 2. 1. 1.]] Synapse 1 [[ -6.96765763] [ 7.14101949] [-10.31917382] [ 7.86128405]] Synapse 1 Update Direction Changes [[ 2.] [ 1.] [ 0.] [ 1.]]   alpha:10 Error:0.496410031903 Error:0.00312938876301 Error:0.00214459557985 Error:0.00172397549956 Error:0.00147821451229 Error:0.00131274062834 Synapse 0 [[ 4.52597806 5.77663165 -7.34266481 -5.29379829] [ 1.66715206 -7.16447274 -7.99779235 -1.81881849] [-4.27032921 -3.35838279 3.44594007 4.88852208]] Synapse 0 Update Direction Changes [[ 7. 19. 2. 6.] [ 7. 2. 0. 22.] [ 19. 26. 9. 17.]] Synapse 1 [[ -8.58485788] [ 10.1786297 ] [-14.87601886] [ 7.57026121]] Synapse 1 Update Direction Changes [[ 22.] [ 15.] [ 4.] [ 15.]]   alpha:100 Error:0.496410031903 Error:0.125476983855 Error:0.125330333528 Error:0.125267728765 Error:0.12523107366 Error:0.125206352756 Synapse 0 [[-17.20515374 1.89881432 -16.95533155 -8.23482697] [ 5.70240659 -17.23785161 -9.48052574 -7.92972576] [ -4.18781704 -0.3388181 2.82024759 -8.40059859]] Synapse 0 Update Direction Changes [[ 8. 7. 3. 2.] [ 13. 8. 2. 4.] [ 16. 13. 12. 8.]] Synapse 1 [[ 9.68285369] [ 9.55731916] [-16.0390702 ] [ 6.27326973]] Synapse 1 Update Direction Changes [[ 13.] [ 11.] [ 12.] [ 10.]]   alpha:1000 Error:0.496410031903 Error:0.5 Error:0.5 Error:0.5 Error:0.5 Error:0.5 Synapse 0 [[-56.06177241 -4.66409623 -5.65196179 -23.05868769] [ -4.52271708 -4.78184499 -10.88770202 -15.85879101] [-89.56678495 10.81119741 37.02351518 -48.33299795]] Synapse 0 Update Direction Changes [[ 3. 2. 4. 1.] [ 1. 2. 2. 1.] [ 6. 6. 4. 1.]] Synapse 1 [[ 25.16188889] [ -8.68235535] [-116.60053379] [ 11.41582458]] Synapse 1 Update Direction Changes [[ 7.] [ 7.] [ 7.] [ 3.]]
      
      







上記のコードでは、微分が方向を変える回数を数えます。 これは、「方向変更の更新」の結論に対応します。 バイアス(微分)が方向を変える場合、ローカルミニマムを超えているため、戻る必要があります。 方向が変わらない場合は、おそらくあまり進んでいません。



私たちが見るもの:





改善2:非表示レベルのサイズのパラメーター化


非表示レベルのサイズを大きくすると、繰り返しごとに収束する検索スペースのサイズが大きくなります。そのようなネットワークとその結論を検討してください。



 import numpy as np alphas = [0.001,0.01,0.1,1,10,100,1000] hiddenSize = 32 #    def sigmoid(x): output = 1/(1+np.exp(-x)) return output #      def sigmoid_output_to_derivative(output): return output*(1-output) X = np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) y = np.array([[0], [1], [1], [0]]) for alpha in alphas: print "\n  alpha:" + str(alpha) np.random.seed(1) # randomly initialize our weights with mean 0 synapse_0 = 2*np.random.random((3,hiddenSize)) - 1 synapse_1 = 2*np.random.random((hiddenSize,1)) - 1 for j in xrange(60000): #     0, 1  2 layer_0 = X layer_1 = sigmoid(np.dot(layer_0,synapse_0)) layer_2 = sigmoid(np.dot(layer_1,synapse_1)) #   ? layer_2_error = layer_2 - y if (j% 10000) == 0: print "  "+str(j)+" :" + str(np.mean(np.abs(layer_2_error))) #    ? #   ?  ,       layer_2_delta = layer_2_error*sigmoid_output_to_derivative(layer_2) #     l1     l2 (   )? layer_1_error = layer_2_delta.dot(synapse_1.T) #     l1? #   ?  ,       layer_1_delta = layer_1_error * sigmoid_output_to_derivative(layer_1) synapse_1 -= alpha * (layer_1.T.dot(layer_2_delta)) synapse_0 -= alpha * (layer_0.T.dot(layer_1_delta))
      
      







   alpha:0.001   0 :0.496439922501   10000 :0.491049468129   20000 :0.484976307027   30000 :0.477830678793   40000 :0.46903846539   50000 :0.458029258565   alpha:0.01   0 :0.496439922501   10000 :0.356379061648   20000 :0.146939845465   30000 :0.0880156127416   40000 :0.065147819275   50000 :0.0529658087026   alpha:0.1   0 :0.496439922501   10000 :0.0305404908386   20000 :0.0190638725334   30000 :0.0147643907296   40000 :0.0123892429905   50000 :0.0108421669738   alpha:1   0 :0.496439922501   10000 :0.00736052234249   20000 :0.00497251705039   30000 :0.00396863978159   40000 :0.00338641021983   50000 :0.00299625684932   alpha:10   0 :0.496439922501   10000 :0.00224922117381   20000 :0.00153852153014   30000 :0.00123717718456   40000 :0.00106119569132   50000 :0.000942641990774   alpha:100   0 :0.496439922501   10000 :0.5   20000 :0.5   30000 :0.5   40000 :0.5   50000 :0.5   alpha:1000   0 :0.496439922501   10000 :0.5   20000 :0.5   30000 :0.5   40000 :0.5   50000 :0.5
      
      







32個のノードでの最良のエラーは0.0009ですが、4つの非表示ノードでの最良のエラーは0.0013です。これは十分に重要です。データセットを表すために、3つ以上のノードは必要ありません。しかし、より多くのノードがあったため、繰り返しごとに大きなスペースを検索し、収束が速くなりました。私たちの場合、違いはわずかですが、複雑なデータセットを扱う場合、それは非常に重要です。



All Articles