こんにちは、えんせきです。
時差ボケじゃないとは思うんですが、正月と異なる稼働時間の長さなのか
1万歩歩くために帳尻合わせでやってる散歩のせいかとても眠いです。
つまりなにしたの?
前回はUnityが用意してくれたサンプルを動かしたけど、今回はしょぼくなってもいいから自分のシーンで強化学習してみた。

用意するObject
- Agent
各エージェントは、それぞれ状態と観測結果を持っていて別々に動いてくれる。ただBrain(脳)は1対1ではなく用意する。
今回のAgentは棒。箒を倒れないようにバランス取る的なやつで、探せば当然出てくるレベルのしょぼいやつ。

これにScriptを追加する。スクリプトについては前回のを参考に作ってみた。
ensekitt.hatenablog.com
- Brain
Agentにアクションを渡したり動作結果を受け取ってAcademyに渡すところみたい。動かし方は4種類ある。
ExternalはPythonとかと繋ぐためのコミュニケータ(API)を持っている。
Internalは学習済のモデルを使って自律動作させる。
Playerはキーボードとかジョイスティックをアサインしておくことで人が動かせる。(デバッグの時に使う)
Heuristicはコードによって動きを定義することができる。(テストだと思ってるけど、他の用途があるかもしれない)
- Academy
Brainを子オブジェクトとして持つ。これはシーンに対して1つ作れば良いみたい。
Engine Configurationはトレーニングモードと推論モード(動かすモード)でレンダリングの品質を指定する。トレーニングの時は凄い小さい画面で時間スケールを大きくして、フレームレートは可能な限り早くするみたいなことをする。
グローバルエピソードの長さ。各エージェントがDone(終了)にならなくてもシーンの長さが設定値になったらDoneにする。
シーンの構成
Main Camera Directional Light EventSystem Academy +Brain Agent +Base +Stick
エージェントは出来上がってからいっぱいコピペして増やしてる。
用意するスクリプトは2つ
Academy
今回の使い方だけだったらクラス名だけ更新してAcademyを継承すれば良い。
Agent
受け取った値をどう反映させるかを決める。入力値はぶっ飛んだ値が来ることもあるので値域の制限とかも入れている。
報酬系もここで定義して今回であれば、倒れたら報酬-1にしたりしている。
Decision
Heuristicで実行する時はDecisionを継承したもので作るけど今回はPlayerとInternalとExternalなのでいらない。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FurikoAgent : Agent {
[Header("Specific to Furiko")]
public GameObject stick;
private Rigidbody rb;
public override List<float> CollectState()
{
List<float> state = new List<float> ();
state.Add (gameObject.transform.localPosition.x);
state.Add (stick.transform.localRotation.z);
state.Add (stick.GetComponent<Rigidbody> ().angularVelocity.z);
return state;
}
public override void InitializeAgent(){
rb = GetComponent<Rigidbody> ();
}
public override void AgentStep(float[] act)
{
// アクションを受け取って値の範囲を決める。
if (brain.brainParameters.actionSpaceType == StateType.continuous) {
float action_x = act [0];
if (action_x > 1f) {
action_x = 1f;
}
if (action_x < -1f) {
action_x = -1f;
}
if ((gameObject.transform.localPosition.x < 10f && action_x > 0f) ||
(gameObject.transform.localPosition.x > -10f && action_x < 0f)) {
// ベースを左右に動かすところ
gameObject.transform.Translate (action_x, 0, 0);
}
}
// 報酬を決める。継続していたら+0.01、一定角度以上になったら-1にして停止
if (done == false) {
reward = 0.01f;
}
float angle_z;
angle_z = stick.transform.localRotation.eulerAngles.z;
if ((angle_z > 60f) && (angle_z < 300)) {
done = true;
reward = -1f;
}
}
public override void AgentReset()
{
//エージェントの状態をリセットする
gameObject.transform.localPosition = new Vector3 (0f, -3f, 0f);
stick.transform.localPosition = new Vector3(0f, 0f, 0f);
stick.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
stick.GetComponent<Rigidbody>().velocity = new Vector3(0f, 0f, 0f);
stick.GetComponent<Rigidbody> ().angularVelocity = new Vector3 (0f, 0f, Random.Range (-0.5f, 0.5f));
}
}
15Agentで50万回学習した結果がこちら

あれ、お互いにあたってね…?
環境はこちら
ensekitt.hatenablog.com
使い方とかはこちらと同じ
ensekitt.hatenablog.com