7

ANN に興味があるという理由だけで、人工ニューラル ネットワークを使用して動作する Connect 4 エンジンを構築したいと考えています。

ANN 構造の次のドラフトが作成されます。それはうまくいくでしょうか?そして、これらの接続は正しいですか (交差したものでも)?

代替テキスト

この ANN の UML クラス図を作成するのを手伝ってくれませんか?

ボードの表現を ANN の入力として提供したいと考えています。そして、アウトプットは選択した動きでなければなりません。

後で強化学習を使用して学習を行い、シグモイド関数を適用する必要があります。エンジンは人間のプレイヤーと対戦します。そして、ゲームの結果に応じて、重みを調整する必要があります。

私が探しているもの...

... 主にコーディングの問題です。抽象的思考からコーディングに移行すればするほど、より良いものになります。

4

4 に答える 4

3

以下は、私がニューラル ネットワークをいじっていたときに設計とコードをどのように整理したかです。ここのコードは (明らかに) 疑似コードであり、おおよそオブジェクト指向の規則に従っています。

ボトムアップから始めて、ニューロンがあります。各ニューロンは、着信接続にかける重み、着信接続データを保持するためのバッファー、および発信エッジのリストを保持できる必要があります。各ニューロンは、次の 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();
    }
}

おそらく実装が最も簡単であると思われるため、学習アルゴリズムとして後方伝播から始めることをお勧めします。私がこれに取り組んでいたとき、アルゴリズムの非常に簡単な説明を見つけるのに非常に苦労しましたが、私のメモはこのサイトを良い参考文献としてリストしています.

始めるにはこれで十分だと思います!

于 2011-01-09T06:58:46.763 に答える
3

シンプルでわかりやすいものから高度に最適化されたものまで、さまざまな方法でニューラル ネットワークを実装できます。あなたがリンクした逆伝播に関するウィキペディアの記事には、 C++C#Javaなどの実装へのリンクがあり、他の人がどのようにそれを行ったかに興味がある場合は、参考になる可能性があります。

1 つの単純なアーキテクチャーは、ノードと接続の両方を別個のエンティティーとしてモデル化します。ノードには、アクティブ化レベルとエラー値だけでなく、他のノードへの着信接続と発信接続の可能性がありますが、接続には重み値があります。

別の方法として、これらのノードと接続を表すより効率的な方法があります。たとえば、レイヤーごとに編成された浮動小数点値の配列などです。これにより、コーディングが少し難しくなりますが、非常に多くのオブジェクトとオブジェクトへのポインターを作成することは避けられます。

1 つの注意: 多くの場合、通常の入力ノードに加えて、すべての非表示ノードと出力ノードに一定の値を提供するバイアス ノードが含まれます。

于 2010-12-30T21:50:13.143 に答える
2

以前にニューラル ネットワークを実装したことがありますが、提案されたアーキテクチャにはいくつかの問題があります。

  1. 典型的な多層ネットワークには、すべての入力ノードからすべての隠しノードへの接続すべての隠しノードからすべての出力ノードへの接続があります。これにより、すべての入力からの情報を組み合わせて、各出力に貢献できます。各入力に 4 つの隠しノードを割り当てると、入力と出力の間の関係を識別するネットワークの能力がいくらか失われます。

  2. ネットワークをトレーニングするための値をどのように考え出しますか? ネットワークは、ボードの位置と最適な次の動きの間のマッピングを作成するため、これを提供するトレーニング例のセットが必要です。ゲーム終盤の動きは簡単に識別できますが、ゲーム中盤の動きが「最適」であるとどのように判断しますか? (強化学習はここで役立ちます)

最後の 1 つの提案は、バイポーラ入力 (false の場合は -1、true の場合は +1) を使用することです。これにより、学習がスピードアップします。また、Nate Kohl は良い点を指摘しています。すべての非表示ノードと出力ノードは、バイアス接続を持つことでメリットが得られます (「1」の固定値を持つ別の入力ノードと考えてください)。

于 2011-01-02T19:20:38.430 に答える
1

設計は、使用する予定の強化学習の特定のタイプに大きく依存します。

最も簡単な解決策は、逆伝播を使用することです。これは、エラーをネットワークに (逆の方法で) フィードバックし、(シグモイド) 関数の逆関数を使用して各重みの調整を決定することによって行われます。何度か繰り返した後、重みは入力に合わせて自動的に調整されます。

遺伝的アルゴリズムは逆伝播法に代わるもので、より良い結果が得られます (ただし、少し遅くなります)。これは、重みを簡単に挿入および削除できるスキーマとして扱うことによって行われます。適合するものが見つかるまで、スキーマは (自然選択の原則を使用して) 変異したバージョンに数回置き換えられます。

ご覧のとおり、これらのそれぞれの実装は大幅に異なります。各タイプの実装に適応するのに十分なほどネットワークを汎用的にしようとすることもできますが、それはそれを過度に複雑にする可能性があります。本番環境に入ると、通常は 1 つの形式のトレーニングしかありません (または、ネットワークが既にトレーニングされていることが理想的です)。

于 2011-01-08T23:39:42.677 に答える