👾

NeuralNetwork on Scratch(隠れ層の増やし方)

2022/05/22に公開

いままでの記事はこちら。
https://zenn.dev/fuji_t/articles/44f3113e0a14ae
https://zenn.dev/fuji_t/articles/f616de5627642a

NeuralNetwork on Scratch(隠れ層の増やし方)

NeuralNetwork on Scratchは初期状態では隠れ層は「隠れ層_1」と「隠れ層_n」の2層ですが、増やすこともできます。今回はその方法を説明します。

学習機 スプライト

変数の作成

学習機スプライトに隠れ層2用の変数を作成します。「変数を作る」で [隠れ層_2の数] 変数を作成してください。変数のスコープは「このスプライトのみ」にしておきます。

また、「リストを作る」で次のリストを作りましょう。スコープは「すべてのスプライト用」にします。

リスト名 スコープ 意味
G_隠れ層_2_U すべてのスプライト用 隠れ層2の出力(活性化前)
G_隠れ層_2_Z すべてのスプライト用 隠れ層2の出力(活性化後)
G_隠れ層_2_バイアス すべてのスプライト用 隠れ層2のバイアス
G_隠れ層_2_重み すべてのスプライト用 隠れ層2の重み


変数の表示

[隠れ層_2の数] は表示状態にし「大きな表示」で表示しておきましょう。場所はこのあたりで。

「初期化」定義

「初期化」 のブロック定義に 「[隠れ層_2の数]を()にする」 ブロックを追加します。初期値は適当な値にします。今回は「5」にしました。

「隠れ層_2の重みとバイアスを初期化」定義を作成

「隠れ層_2の重みとバイアスを初期化」 定義を作成してください。

定義の中身は 「隠れ層_nの重みとバイアスを初期化」 定義を複製しましょう。複製したら 「隠れ層_n」 の部分をすべて 「隠れ層_2」 に変更します。また、「隠れ層_nの重みとバイアスを初期化」 定義内の 「隠れ層_1の数」「隠れ層_2の数」 に変更してください。(2か所あります。)

最後に 「重みとバイアスを初期化」 定義に 「隠れ層_2の重みとバイアスを初期化」 定義ブロックを追加しましょう。

順伝播、逆伝播の処理に組み込む

新しいメッセージ 「順伝播_隠れ層_2」「逆伝播_更新_隠れ層_2」 を作って、順伝播と逆伝播の処理に組み込みましょう。作ったメッセージの処理内容は後で作成します。

「順伝播」 定義と 「逆伝播と更新」 定義に作ったメッセージの呼び出しブロック 「(順伝播_隠れ層_2)を送って待つ」「(逆伝播_更新_隠れ層_2)を送って待つ」 を組み込みます。あわせて 「[呼び出し元]を(順_隠れ層_2)にする」 ブロック、「[呼び出し元]を(逆_隠れ層_2)にする」 ブロックも追加しておきます。これは、行列の次元数が合わなくて計算できなかった時に、どの部分の処理でエラーとなったかを特定する際に利用するためのものです。

順_隠れ層 スプライト

上で作成した 「順伝播_隠れ層_2」 の処理を作っていきましょう。

「リストコピー(隠れ層_2)」の作成

「リストコピー(隠れ層_2)」 定義を作成してください。

定義の中身は 「リストコピー(隠れ層_1)」 定義の内容を複製しましょう。複製したら 「G_隠れ層_1_重み」「G_隠れ層_2_重み」 に、「G_隠れ層_1_バイアス」「G_隠れ層_2_バイアス」 に変更します。

「結果をコピー(隠れ層_2)」の作成

「結果をコピー(隠れ層_2)」 定義を作成してください。

定義の中身は 「結果をコピー(隠れ層_1)」 定義の内容を複製しましょう。複製したら 「G_隠れ層_1_U」「G_隠れ層_2_U」 に、「G_隠れ層_1_Z」「G_隠れ層_2_Z」 に変更します。

「[順伝播_隠れ層_2]を受け取ったとき」イベント

「[順伝播_隠れ層_2]を受け取ったとき」 の処理を次のように作成してください。

これで、順_隠れ層 スプライトの修正は完了です。

逆_隠れ層 スプライト

最後に 「逆伝播_更新_隠れ層_2」 の処理を作っていきましょう。

「リストコピー(隠れ層_2)」の作成

「リストコピー(隠れ層_2)」 定義を作成してください。

定義の中身は 「リストコピー(隠れ層_n)」 定義の内容を複製してください。複製したら 「G_隠れ層_n_重み」「G_隠れ層_2_重み」 に、「G_隠れ層_n_バイアス」「G_隠れ層_2_バイアス」 に、「G_隠れ層_n_U」「G_隠れ層_2_U」 に変更します。

「リストコピー(隠れ層_n)」の修正

「リストコピー(隠れ層_n)」 定義の中身を一部修正します。「G_隠れ層_1_Z」「G_隠れ層_2_Z」 に変更してください。逆伝播では「出力層」→「隠れ層_n」→「隠れ層_2」→「隠れ層_1」の順に誤差が伝播するためです。

「結果をコピー(隠れ層_2)」の作成

「結果をコピー(隠れ層_2)」 定義を作成してください。

定義の中身は 「結果をコピー(隠れ層_n)」 定義の内容を複製しましょう。複製したら 「G_隠れ層_n_重み」「G_隠れ層_2_重み」 に、「G_隠れ層_n_バイアス」「G_隠れ層_2_バイアス」 に変更します。

「[逆伝播_更新_隠れ層_2]を受け取ったとき」イベント

「[逆伝播_更新_隠れ層_2]を受け取ったとき」 の処理を次のように作成してください。

これで、逆_隠れ層 スプライトの修正は完了です。

完成

これで隠れ層が3層のニューラルネットワークができました!この方法で層をもっと増やすこともできますが、その分、学習に時間がかかるようになりますのでご注意くださいね。
試しに何かのデータを学習させてみましょう。まずは「アヤメの分類」あたりがよいと思います。(やり方は前の記事を参照。)

動きがおかしかったら…

正しく計算できていない可能性があります。順_隠れ層 スプライトと逆_隠れ層 スプライトを表示状態にして再度[学習開始]してみましょう。

行列計算が正しくできていないと下のようなメッセージが表示されます。ここでは、順伝播の隠れ層2層目の行列和の計算が正しくできていないと言われています。5x10行列と3x10行列を足そうとしていて、次元数が異なるためエラーとなっています。(行列の足し算は同じ次元でなければいけないので、両方とも 5x10次元 もしくは 3x10次元 になっていないといけません。なお、ここで「10」はバッチサイズです。)

「U=行列和(U, バイアス)」 定義を見ると、Uバイアス を足そうとしているので、隠れ層2_U もしくは 隠れ層_2_バイアス の次元数がおかしそうだとあたりがつきます。隠れ層2のユニット数は今回「5」にしているので、バイアスも 5xバッチサイズ 次元になっていなければいけないところ、なぜか 3x10 になっています。どうやら 隠れ層2のバイアス の設定が誤ってるみたいですね。「隠れ層_2の重みとバイアスを初期化」 定義ブロックを確認してみましょう。

隠れ層_2の数 とすべきところが 隠れ層_nの数 になっちゃってますね。「隠れ層_nの重みとバイアスを初期化」 定義を複製して隠れ層2用に修正する際に修正し忘れてしまったようです。正しく修正しましょう。

修正したら[学習開始]してみましょう。今度はちゃんと学習できましたね。


【関連記事】

https://zenn.dev/fuji_t/articles/44f3113e0a14ae

https://zenn.dev/fuji_t/articles/f616de5627642a

https://zenn.dev/fuji_t/articles/97032fd2eb11ad


【Scratchプロジェクト】

NeuralNetwork_on_Scratch_2 (全部入り)
https://scratch.mit.edu/projects/690096830

Base_NeuralNetwork_on_Scratch_2 (基本部分のみ)
https://scratch.mit.edu/projects/694599958/

Discussion