
前回の記事では、ニューラルネットワークのトピックを理解するための基礎について検討しました。 結果として得られたシステムは、本格的なニューラルネットワークではなく、単に探索的なものでした。 その中の意思決定メカニズムは「ブラックボックス」であり、詳細には説明されていません。
これは、彼らがこの記事の枠組みで議論されることです。 この記事の結果は、1つのパーセプトロンからの本格的なニューラルネットワークとなり、入力データを認識でき、それ自体を訓練することができます。
プログラミング言語、今回-C#。
猫の下で興味を持ってください。
プレゼンテーションは単純な言語で行われるため、専門家に用語を批判しないようお願いします。
最初の記事では、特定の数字を認識するための要素は特定の「ニューロン」でした(実際には完全ではありませんが、簡単にするために採用されました)。
それが何であるかを検討してください。

入力に画像を再度送信するため、入力データは2次元配列になります。 さらに、入力データの各部分は、特別な接続(シナプス)-図の赤い線を使用してニューロンに接続されます。 しかし、これらは単純な接続ではありません。 それらはそれぞれ、ニューロンにとって重要です。
私は人間との類推をします。 私たちはさまざまな感覚で情報を知覚します-見る、聞く、嗅ぐ、触れる。 しかし、これらの感情には、優先度(ビジョン)がより高く、感覚(タッチ)が低いものがあります。 さらに、それぞれの生活状況について、経験に基づいて感覚器官ごとに優先順位を設定します。見慣れない製品を食べるために、視覚と嗅覚を最優先にしていますが、聴覚は役割を果たしません。 そして、群衆の中に友人を見つけようとして、私たちは目と耳が私たちに与える情報に注意を払い、残りは道を行く。
ニューロン内の独立した器官の最も単純な外観はシナプスです。 状況が異なると、シナプスの意味も異なります。 この重要性は、結合の重みと呼ばれます。
なぜなら 画像が白黒で入力される場合、軸索の入力では1または0のみが可能です。

そして、出力は重み値または0のいずれかです。
大ざっぱに言えば、入り口に何かがあると、脚は「痙攣」し始め、ニューロンにその情報があることを伝えます。 それがどれだけ「ぴくぴくする」かによって、ネットワークが下す決定は異なります。
軸索の数は、入力配列の要素の数に対応します。 この記事では、入力として3x5ピクセルのサイズを使用します。 したがって、ニューロンに入る接続の数は3 x 5 = 15になります。
結合重み係数でスケーリングされた信号はニューロンに到達し、他のシナプスからの残りの信号に追加されます。
ある数字が判明します。 この数は、事前に決定されたしきい値と比較されます-受信された値がしきい値よりも高い場合、ニューロンが出力したと見なされます。
しきい値は、次の考慮事項から選択されます。値が高いほど、ニューロンの精度は高くなりますが、トレーニングする時間が長くなります。

ソフトウェアの実装に移りましょう。
ニューロンクラスを作成します。
class Web { public int[,] mul; // public int[,] weight; // public int[,] input; // public int limit = 9; // - , public int sum ; // public Web(int sizex, int sizey,int[,] inP) // { weight = new int[sizex, sizey]; // ( ) mul = new int[sizex, sizey]; input = new int[sizex, sizey]; input = inP; // }
はい、信号を重みで乗算し、信号を加算し、しきい値と比較し、結果を出力する手順を1か所で組み合わせることができることを知っています。 しかし、各操作を個別に実行し、それらを1つずつ呼び出すと、より明確になるように思えました。
スケーリング:
public void mul_w() { for (int x = 0; x <= 2; x++) { for (int y = 0; y <= 4; y++) // { mul[x, y] = input[x,y]*weight[x,y]; // (0 1) . } } }
追加:
public void Sum() { sum = 0; for (int x = 0; x <= 2; x++) { for (int y = 0; y <= 4; y++) { sum += mul[x, y]; } } }
比較:
public bool Rez() { if (sum >= limit) return true; else return false; }
プログラムは、この種類の画像ファイルを開きます。

すべてのピクセルを実行し、この番号が認識を教えられたものであるかどうかを判断してください。
なぜなら ニューロンは1つだけなので、1つのシンボルしか認識できません。 私は5番を選択しました。言い換えると、プログラムは、与えられた写真が5番の画像であるかどうかを教えてくれます。
シャットダウン後もプログラムが動作し続けることができるように、テキストファイルに重みの値を保存します。
private void Form1_Load(object sender, EventArgs e) { NW1 = new Web(3, 5,input); // openFileDialog1.Title = " "; openFileDialog1.ShowDialog(); string s = openFileDialog1.FileName; StreamReader sr = File.OpenText(s); // string line; string[] s1; int k = 0; while ((line = sr.ReadLine()) != null) { s1 = line.Split(' '); for (int i = 0; i < s1.Length; i++) { listBox1.Items.Add(""); if (k < 5) { NW1.weight[i, k] = Convert.ToInt32(s1[i]); // listBox1.Items[k] += Convert.ToString(NW1.weight[i, k]); // , } } k++; } sr.Close(); }
次に、入力データの配列を作成する必要があります。
Bitmap im = pictureBox1.Image as Bitmap; for (var i = 0; i <= 5; i++) listBox1.Items.Add(" "); for (var x = 0; x <= 2; x++) { for (var y = 0; y <= 4; y++) { int n = (im.GetPixel(x, y).R); if (n >= 250) n = 0; // , else n = 1; listBox1.Items[y] = listBox1.Items[y] + " " + Convert.ToString(n); input[x, y] = n; // } }
上記のクラスメソッドを呼び出して、文字を認識します。
public void recognize() { NW1.mul_w(); NW1.Sum(); if (NW1.Rez()) listBox1.Items.Add(" - True, Sum = "+Convert.ToString(NW1.sum)); else listBox1.Items.Add( " - False, Sum = "+Convert.ToString(NW1.sum)); }
それだけです これで、プログラムはすでにニューラルネットワークと呼ばれ、何かを決定できます。
しかし、彼女は完全に愚かであり、常に偽を与えます。
彼女を訓練する必要があります。 最も簡単なアルゴリズムを使用してトレーニングします。
ネットワークが正しい答えを提供する場合、私たちは喜んで何もしません。
そして、彼が間違っている場合、それに応じて彼女を罰します。
-彼女の間違った答えがFalseの場合、入力の値を各脚の重みに追加します(脚1-画像のポイント[0,0]などの値)。
public void incW(int[,] inP) { for (int x = 0; x <= 2; x++) { for (int y = 0; y <= 4; y++) { weight[x, y] += inP[x, y]; } } }
-彼女の間違った答えがTrueの場合、各脚の重みから入力の値を減算します。
public void decW(int[,] inP) { for (int x = 0; x <= 2; x++) { for (int y = 0; y <= 4; y++) { weight[x, y] -= inP[x, y]; } } }
次に、受け取った変更を重みの配列に保存し、トレーニングを続けます。
私が言ったように、私はサンプルのために5番を取った:

さらに、残りの数字と、数字5自体のいくつかのオプションを用意しました。

6番が最も問題になると予想されますが、トレーニングを通じてこれを克服します。
3x5のゼロで満たされたテキストファイルを作成します-ネットワークのネットメモリ:
000
000
000
000
000
プログラムを起動して、このファイルをポイントします。
番号5の画像をダウンロードします。

当然、答えは間違っています。 「正しくない」をクリックします。
重みが再計算されます(ファイルで結果を確認できます)。
1 1 1
1 0 0
1 1 1
0 0 1
1 1 1
これで、プログラムはこの画像を正しく認識します。
私たちはプログラムの写真を送り続け、間違った答えに対して彼女を罰します。
最終的に、彼女はセット内のすべての写真を正しく認識します。
完全に構成されたネットワークによってファイルに保存された総重量は次のとおりです。
1 2 1
1 0 -4
1 2 1
-4 0 1
1 1 0

したがって、6つは正しく決定されます。
プログラムのソースコード、実行可能ファイル、重みのファイル、3x5の写真は、ここから取得できます 。
他のキャラクターとプレイしたり、ネットワークを再度トレーニングしたい場合は、w.txtファイルのすべての数字をリセットすることを忘れないでください
これでこの記事は終わりです。 最も簡単なパーセプトロンを作成、構成、トレーニングする方法を学びました。
記事がホットレビューを満たしている場合、次回はより複雑で多層的なものを実装しようとします。 さらに、最適な(高速)ネットワーク学習の問題は未踏のままでした。
シムについては、お辞儀をして、読んでくれてありがとう。