- 今回は、ゲーム「Snake」が選択されています。
- Goネットワーク用のライブラリが作成されました。
- 記憶の「深さ」に応じた学習の原理が見つかります。
- サーバーは開発者間のゲーム用に作成されています。
ゲームの本質
おそらく、多くの人がノキアの携帯電話の標準アプリケーションである「Snake」というゲームを覚えているでしょう。 その本質は次のとおりです。ヘビはフィールドを横切って移動し、食べ物が見つからない場合は減少し、見つかった場合は増加します。 ヘビが障害物に衝突すると、死んでしまいます。
私はルールを少し変更しました。ヘビがクラッシュしても死ぬことはなく、単に停止し、減少し続けます。 さらに、ヘビは半分に分割できます。 ヘビの体に細胞が1つ残っていて、10回の動きで食べ物が見つからなかった場合、彼女は死んで食べ物に変わります。
ヘビを制御するボットを訓練します。 ヘビが分裂した場合、ボットは別のヘビを制御し、そのヘビも分裂する可能性があります。
サイバー生物学者ミハイル・ツァルコフのヘビを使った実験が基礎として採用されています。
ニューラルネットワーク
タスクの一部として、ニューラルネットワークのライブラリがGo言語で記述されました。 ニューラルネットワークの動作を研究するために、
foo52ruビデオ日記とTariq Rashidの本-ニューラルネットワークを作成します。
CreateLayer(L []int)
関数
CreateLayer(L []int)
は、必要な層数とそのサイズでニューラルネットワークを作成します。 最後のレイヤーを除く各レイヤーに、変位ニューロンが追加されます。 最初のレイヤーにデータをフィードし、最後のレイヤーから結果を取得します。
例:
CreateLayer([]int{9, 57, 3, 1})
ここでは、9つの入力を持つニューラルネットワークを作成しました。 57および3ニューロンの2つの隠れ層と結果を得るための1つのニューロン。 変位ニューロンは、設定したニューロンにプラス記号によって自動的に追加されます。
ライブラリでは次のことができます。
- ネットワーク入力にデータを送信します。
- 最後のレイヤーにアクセスして結果を取得します。
- 正しい答えを求め、ネクタイの重みを調整してトレーニングを実施します。
最初の結合の重みは、ゼロに近いランダムな値で与えられます。 アクティベーションには、ロジスティック関数を使用しました。
ボットトレーニング
ボットは入り口で9x9の正方形のフィールドを受け取り、その中央にはヘビの頭があります。 したがって、ニューラルネットワークには81個の入力があります。 入力に供給されるセルの順序は重要ではありません。 トレーニング中、ネットワークは、それがどこにあるかを「把握」します。
障害物やその他の蛇を示すために、-1から0までの値(包括的ではない)を使用しました。 空のセルは値0.01、食品0.99で示されました。
ニューラルネットワークの出力では、アクションに5つのニューロンが使用されました。
- X軸に沿って左に移動します。
- 右へ。
- y軸上;
- ダウン;
- 半分に分割します。
ボットの動きは、出力で最大の値を持つニューロンによって決定されました。
ステップ0。ランダマイザー
最初に、ボットランダマイザーが作成されました。 そこで、ランダムに歩くボットを呼び出します。 ニューラルネットワークの有効性を検証する必要があります。 適切なトレーニングを行えば、ニューラルネットワークは簡単に打ち負かすことができます。
ステップ1.記憶なしで学習する
各移動の後、最高値を示す出力ニューロンの結合の重みを調整します。 他の出力ニューロンには触れません。
トレーニングには次の値が与えられました。
- 見つかった食べ物:0.99
- 任意の方向に移動しました:0.5
- 食べ物を見つけることなく体の細胞を失った(これには10回の動きが与えられる):0.2
- 立ち止まる(障害物にぶつかるか、立ち往生する):0.1
- じっと立って、体の細胞が1つ:0.01
このようなトレーニングの後、ボットはすぐにランダマイザーに勝ち始め、私はタスクを設定しました:これらを打つボットを作成します。
A / Bテスト
このタスクを達成するために、ニューラルネットワークの構成に応じて、蛇を2つの部分に分割するプログラムが作成されました。 フィールドでは、各構成の20匹のヘビが生産されました。
1つのボットによって制御されるすべてのヘビは、同じニューラルネットワークを持っていました。 彼の経営陣のヘビが多くなり、さまざまなタスクに直面する頻度が高くなるほど、より迅速なトレーニングが行われました。 たとえば、あるヘビが行き止まりに達したときにデッドロックを回避したり、半分に分割したりした場合、このボットのすべてのヘビが自動的にこれらのスキルを獲得しました。
ニューラルネットワークの構成を変更することで、良い結果を得ることができますが、これでは十分ではありません。 アルゴリズムをさらに改善するために、いくつかの動きにメモリを使用することにしました。
ステップ2.記憶で学ぶ
ボットごとに、8つの移動用のメモリを作成しました。 ボットが示唆したフィールドの状態と動きはメモリに記録されました。 その後、移動前の8つの州すべての重みを調整しました。 これを行うために、移動の深さに関係なく、単一の補正係数を使用しました。 したがって、それぞれの動きは重みの調整に一度ではなく、8回を導きました。
予想どおり、メモリボットは、メモリなしでトレーニングを行ったボットをすばやく倒し始めました。
ステップ3.メモリーの深さに応じて補正係数を減らす
次に、メモリの深さに応じて、補正係数を削減しようとしました。 最後の動きについて、重みを調整するための最大係数が確立されました。 それに先行するコースでは、メモリ全体で補正係数が減少しました。
記憶の深さに応じて補正係数が直線的に減少したため、新しいボットが単一の係数を使用したボットを打ち負かすようになりました。
次に、補正係数の対数削減を使用してみました。 各動きのメモリの深さに応じて、係数は半分に減少しました。 したがって、「ずっと前に」行われた動きは、「新鮮な」動きよりも学習への影響が大幅に小さくなりました。
補正係数が対数的に減少したボットは、線形関係でボットを打ち負かし始めました。
ボット用サーバー
判明したように、「ポンピング」ボットのレベルを改善することは無限です。 そして、私は開発者が(プログラミング言語に関係なく)Snakesの効果的なアルゴリズムを作成する際に競争できるサーバーを作成することにしました。
プロトコル
承認するには、GETリクエストを「game」ディレクトリに送信し、ユーザー名を指定する必要があります。次に例を示します。
.../game/?user=masterdak
「...」の代わりに、サーバーをデプロイするサイトアドレスとポートを指定する必要があります。
次に、サーバーはセッションを示すJSON応答を発行します。
{"answer":"Hellow, masterdak!","session":"f4f559d1d2ed97e0616023fb4a84f984"}
その後、マップとフィールド上のヘビの座標をリクエストし、リクエストにセッションを追加できます。
.../game/?user=masterdak&session=f4f559d1d2ed97e0616023fb4a84f984
サーバーは次のようなものを表示します。
{ "answer": "Sent game data.", "data": { "area": [ ["... ..."] ], "snakes": [ { "num": 0, "body": [ { "x": 19, "y": 24 }, { "x": 19, "y": 24 }, { "x": 19, "y": 24 } ], "energe": 4, "dead": false } ] } }
エリアフィールドは、以下の値で競技場のステータスを示します。
0
これに続いて、あなたの制御下にある蛇の配列が続きます。
ヘビの体は
体の配列にあります。 ご覧のとおり、先頭のヘビの体全体(頭-最初のセルを含む)は同じ位置にあります。「x」:19、「y」:24。 。 さらに、体と頭の座標は異なります。
次の構造(Goの例)は、すべてのサーバー応答オプションを定義しています。
type respData struct { Answer string Session string Data struct { Area [][]int Snakes []struct { Num int Body []Cell Energe int Dead bool } } } type Cell struct { X int Y int }
次に、GET要求に
移動を追加して、ヘビが行う移動を送信する必要があります。次に例を示します。
...&move=u
u-コマンドアップを意味します;
d-ダウン;
l-左へ。
r-右側。
/ -半分に分割。
いくつかのヘビ(たとえば7匹)のコマンドは次のようになります。
...&move=ud/urld
1つのキャラクター-1つのチーム。 答えには、あなたの制御下にあるすべてのヘビに対するコマンドが含まれている必要があります。 そうしないと、一部のヘビはコマンドを受け取らず、古いアクションを続行します。
フィールドは150ミリ秒間隔で更新されます。 60秒以内にコマンドが受信されない場合、サーバーは接続を閉じます。
参照資料
habraeffectを避けるために、見たい人のために、私にメッセージを送ってください。 応答として、サーバーのIPアドレスを送信します。 または、プログラムのソースコードを使用してサーバーを展開できます。
私はプログラミングの専門家でも、ニューラルネットワークの専門家でもありません。 したがって、私は失敗することができます。 コードを「そのまま」拡散しました。 もっと経験豊かな開発者が犯した間違いを見せてくれたら嬉しいです。
- ゲーム「Tic Tac Toe」を使用したニューラルネットワーク用ライブラリ
- スネークマスター-サーバー
- スネークマスター-ボット
- Snakeworld2
UPDサーバーのIPアドレスを一時的にアップロード
します 。 現在、1つのボットランダマイザー(SnakeBot0)のみが起動されています。 サーバーがそれほど速くクラッシュしないことを願っています。