iPX社員によるブログ

iPX社員が"社の動向"から"自身の知見や趣味"、"セミナーなどのおすすめ情報"に至るまで幅広い話題を投下していくブログ。社の雰囲気を感じ取っていただけたら幸いです。

UE4で強化学習環境を動かし、学習状況を可視化する(Part2)

はじめに

ご無沙汰しております。iPXのabikoです。
あれよあれよという間に、気がつけば年の瀬が近づいて参りました。
皆さまお体に気をつけて、よいお年をお迎えください。

前回までのあらすじ

前回強化学習の学習状況の可視化をやってみようとUnrealEnginePythonを導入しました。
そして、UnrealEnginePython付属のPythonEditorでコードを実行し、いつものアニメーションが再生するところまで確認できました。

今回はUE4内にオブジェクトを作成して、学習中のカートの位置・ポールの角度を反映し、実際に可視化まで行っていきます。
※前回に引き続き、学習自体は行いません。可視化がメインです。
 強化学習環境にはOpenAI Gymを使用し、行動はランダムで与えます。

では、張り切っていきましょう!

PyActorと連携して、ゲームプレイで動作させる

1. PythonEditorを開き、新規にファイルを作成して次のコードを記述します。

f:id:ipx-writer:20191226063618p:plain
PythonEditorの起動

import unreal_engine as ue
ue.log('Hello UnrealEnginePython!')

class ViewGym:
    def begin_play(self):
        ue.log('ViewGymClass begin play')
    def tick(self, delta_time):
        ue.log('delta_time: %s' % delta_time)

f:id:ipx-writer:20191226063715p:plain
EditCode1

2. PyActorクラスを作成して、1. で作成したファイル名とコード内のクラス名を指定します。
 ここでは、ファイル名はPythonScript3、クラス名はViewGymです。
 (PyActorクラスの名前はBP_ViewGymとしました)

f:id:ipx-writer:20191226063847p:plain
Select PyActor

f:id:ipx-writer:20191226065342p:plain
Setting PyActor


3. 連携できているかを確認します。
 作成したPyActorクラス(BP_ViewGym)をレベル内に配置します。
 アウトプットログウィンドウを表示し、ゲームプレイを実行してみます。
 
 ログを"LogPython"でフィルタし、下記のような結果が得られていれば正しく連携できています。
 表示しているのは前回フレームからの経過時間です。
 60fpsで動作していれば、下記のように16ms付近の値が出力されます。

LogPython: Hello UnrealEnginePython!
LogPython: ViewGymClass begin play
LogPython: delta_time: 0.01666729897260666
LogPython: delta_time: 0.14368070662021637
LogPython: delta_time: 0.016666699200868607
LogPython: delta_time: 0.0166671983897686
LogPython: delta_time: 0.01666710153222084
LogPython: delta_time: 0.016667399555444717

f:id:ipx-writer:20191226072251p:plain
Log

Gymのコードをゲームプレイで実行できるように変更

つづいて、PythonScript3の記述を以下のように変更します。

import unreal_engine as ue
import gym

ue.log('Hello UnrealEnginePython!')

class ViewGym:
    def begin_play(self):
        ue.log('ViewGymClass begin play')
        self.env = gym.make('CartPole-v0')
        self.observation = self.env.reset()
        self.done = False

    def end_play(self, reason):
        ue.log('ViewGymClass end play')
        self.env.close()

    def tick(self, delta_time):
        ue.log('ViewGymClass event tick')

        if self.done:
            self.observation = self.env.reset()
            self.done = False

        self.env.render()
        action = self.env.action_space.sample()
        self.observation, reward, self.done, info = self.env.step(action)

ゲームプレイの実行によって、いつものアニメーションが再生されるようになれば成功です。

UE4にCartPole(台車と棒)を作成

1. BP_ViewGymに次のようにキューブとシリンダーコンポーネントを追加して簡易な外観を作成します。

f:id:ipx-writer:20191226071820p:plain
Add Component

2. スケールを変更してそれらしい形に変更します。
 また、今回Poleの角度はオブジェクトのRotatorで表現します。
 オブジェクトの中心が回転軸になるため、適当な位置に配置しましょう。
 ※台車を突き抜けてしまってますが、床上に配置すれば隠れて見えないのでよしとします(笑)

f:id:ipx-writer:20191226065530p:plain
UE4 CartPole

いざ可視化へ

Python側からコールする可視化イベントをBPで記述します。
環境で観測できる値(台車の位置、棒の角度)を引数で渡すと、アクター自身の位置・棒の角度が変更されるように書いています。

f:id:ipx-writer:20191226065612p:plain
Render BP

※環境で扱われている角度の単位がradianなので注意が必要です。(R2Dでdegreesへ変換)
 また、位置の値をそのまま利用すると値が小さすぎて変化がわからない(±2.4)ので100倍して利用しています。

PythonScript3の最後の部分にBPのイベントを呼び出す連携コードを追記します。

        self.env.render()
        # ↓ この行を追記
        self.uobject.Render(self.observation[0], self.observation[2])
        # ↑
        action = self.env.action_space.sample()
        self.observation, reward, self.done, info = self.env.step(action)


ゲームプレイ実行します。
.....

f:id:ipx-writer:20191226071047g:plain
UE4 CartPole Anim

無事可視化できました!
いつものアニメーションと同じように動いていることがわかります。

結び

次は別の環境についても可視化してみたいですね。
行動が連続空間である場合の基本的な環境、Pendulumなどはぜひ挑戦してみたいところです。

最後まで読んでいただき、ありがとうございました。
よいお年を。2020年にまた、お会いしましょう。