以下は、私がニューラル ネットワークをいじっていたときに設計とコードをどのように整理したかです。ここのコードは (明らかに) 疑似コードであり、おおよそオブジェクト指向の規則に従っています。
ボトムアップから始めて、ニューロンがあります。各ニューロンは、着信接続にかける重み、着信接続データを保持するためのバッファー、および発信エッジのリストを保持できる必要があります。各ニューロンは、次の 3 つのことを実行できる必要があります。
- 着信エッジからデータを受け入れる方法
- 入力データと重みを処理して、このニューロンが送信する値を定式化する方法
- 発信エッジでこのニューロンの値を送信する方法
コード的には、これは次のように変換されます。
// Each neuron needs to keep track of this data
float in_data[]; // Values sent to this neuron
float weights[]; // The weights on each edge
float value; // The value this neuron will be sending out
Neuron out_edges[]; // Each Neuron that this neuron should send data to
// Each neuron should expose this functionality
void accept_data( float data ) {
in_data.append(data); // Add the data to the incoming data buffer
}
void process() {
value = /* result of combining weights and incoming data here */;
}
void send_value() {
foreach ( neuron in out_edges ) {
neuron.accept_data( value );
}
}
次に、ニューロンのリストを保持する Layer クラスを作成すると、最も簡単であることがわかりました。(このクラスをスキップして、NeuralNetwork にニューロンのリストのリストを保持させることは十分に可能です。Layer クラスを使用すると、組織的にもデバッグ的にも簡単であることがわかりました。) 各レイヤーは、次の機能を公開する必要があります。
- 各ニューロンを「発火」させる
- このレイヤーがラップするニューロンの生の配列を返します。(これは、ニューラル ネットワークの最初の層に入力データを手動で入力する必要がある場合に便利です。)
コード的には、これは次のように変換されます。
//Each layer needs to keep track of this data.
Neuron[] neurons;
//Each layer should expose this functionality.
void fire() {
foreach ( neuron in neurons ) {
float value = neuron.process();
neuron.send_value( value );
}
}
Neuron[] get_neurons() {
return neurons;
}
最後に、レイヤーのリストを保持する NeuralNetwork クラス、初期データを使用して最初のレイヤーをセットアップする方法、学習アルゴリズム、およびニューラル ネットワーク全体を実行する方法を作成します。私の実装では、すべての受信データを単純にバッファリングしてそれを返す単一の偽のニューロンで構成される 4 番目のレイヤーを追加して、最終的な出力データを収集しました。
// Each neural network needs to keep track of this data.
Layer[] layers;
// Each neural network should expose this functionality
void initialize( float[] input_data ) {
foreach ( neuron in layers[0].get_neurons() ) {
// do setup work here
}
}
void learn() {
foreach ( layer in layers ) {
foreach ( neuron in layer ) {
/* compare the neuron's computer value to the value it
* should have generated and adjust the weights accordingly
*/
}
}
}
void run() {
foreach (layer in layers) {
layer.fire();
}
}
おそらく実装が最も簡単であると思われるため、学習アルゴリズムとして後方伝播から始めることをお勧めします。私がこれに取り組んでいたとき、アルゴリズムの非常に簡単な説明を見つけるのに非常に苦労しましたが、私のメモはこのサイトを良い参考文献としてリストしています.
始めるにはこれで十分だと思います!