物理ベースのキャラ(アクティブラグドール)を、模倣学習でヒトの歩き方に近づける試みです。
関連
- ◯
- 物理ベースのキャラを、強化学習で自律的に歩かせる:Unity (ML-Agents (Walker)), UnityChan, VRM (VRoid) , DAZ
- ◯
- 物理ベースのキャラにアニメーションをコピーする:Unity (ConfigurableJoint) , UnityChan, VRM (VRoid) , DAZ
模倣学習で、ヒトの歩く姿勢に近づける
既存のスクリプトでは、ヒトが歩くのと同じ姿勢にはなかなかなりません:[※1]
- ※1
- 重心を不安定にさせないためでしょうけど、摺り足ぎみになります。そのため上体を大きく反らすことになりますが、そのリンボーダンスっぽい姿勢を保ち続けるのが人間ばなれしてますよね。
ここでは模倣学習で、キャラクタの姿勢の調整を試みてみます。[※2]
まず既存のスクリプト(WalkerAgent.cs)は、それぞれの関節の地面(=スタビライザ)に対する位置や速度を、観察の対象にしています。そしてキャラクタ自体には物理演算が効いていて、重力の作用を受けています。
なので理屈からいえば、このキャラクタに<地面(=スタビライザ)に対し直立して歩く動作>を与えるだけで、重量に逆らってその姿勢を保とうとするはずです。うまくすれば、その姿勢で歩き出すかもしれません。[※3]
- ※2
- 強化学習は、エージェント(=キャラクタ)が状態と報酬から学ぶことを特徴とします……ただそれだと、学ばせる側が<こうさせたい>というカタチを実現するのが難しい、という側面があります。それで、逆に<こうさせたい>というカタチから学ばせる、という手法もいろいろと考えられています。これらを模倣学習といいます。
- ※3
- もちろん、それで物理ベースのキャラが模倣元のとおりに動くわけではありません。重力に抗いつつ立とうとするわけなので、そこには模倣と重心のバランスのトレードオフがあります。
歩くアニメーションを模倣する
まず<歩く>アニメーションを物理ベースのキャラにコピーすることで、その動作を真似させてみます:[※1]
- ※1
- 向かって右側がコピー元(通常の3Dキャラ)、左側がコピー先(物理ベースのキャラ)です……右足が引っかかっているのは、コライダの干渉のせいです……
歩行のアニメーションは、たとえばUnityChan / SD_UnityChanなどに付属するアニメーション・クリップを使います:
- ・
- UnityChan/Animations/unitychan_WALK00_F/Character1_Reference/WALK00_F
- ・
- UnityChan/SD_unitychan/Animations/SD_unitychan_motion_humanoid/Character1_Reference/Walking@loop
既存のスクリプトには、模倣させるためのメソッド(Heuristic() )がないので、次の記述を加えます(メソッド内にはなにも記述しません。ここでは、アニメーションをコピーすることでアクションを与えるので):
public override void Heuristic(in ActionBuffers actionBuffers) {}
報酬を与える記述(AddReward() )は、その計算箇所もふくめいったん削除(コメントアウト)します(これでキャラクタは、目標に向かうことはなくなりますが、歩く動作を再現することに集中するはずです):
void FixedUpdate() { //AddReward(matchSpeedReward * lookAtTargetReward); public void TouchedTarget() { //AddReward(1f);
アニメーションのコピーは、次の手順に沿って進めます:
- ・
- ラグドール化前の3Dキャラを、シーンに配置(=コピー元キャラ)
- ・
- 物理ベースのキャラを、シーンに配置(ただし倒れないよう、事前に準備したフックなどに固定)
- ・
- コピー元キャラに、アニメーション・クリップを設定し動かす
- ・
- コピー元キャラのアニメーションを、物理ベースのキャラにコピー
模倣動作のデモファイルへの記録は、次の手順に沿って進めます:
- ・
- 物理ベースのキャラに、コンポーネント「DemonstrationRecorder 」を取り付け
- ・
- コンポーネント「DemonstrationRecorder 」の引数「record」を有効化[※2]
- ・
- ゲームを実行し、適当なステップ数(5〜10ステップ)だけ実行してストップ
これで模倣動作を記録したデモファイルが、次に生成されます:[※3]
- ・
- ${DIR_ML_AGENTS}/ml-agents/Project/Assets/Demonstrations/${ID_DEMO}.demo
ハイパーパラメータ群を、次のように変更します。まず外部環境からの報酬(extrinsic )は、いったん削除(コメントアウト)します。そして内的要因(BCとGAIL)の記述を加えます。このうち、BCは訓練前に適用され、GAILは訓練中に適用(報酬が配分)されます。それぞれのアルゴリズムに、デモファイルのパスを加えます:
... reward_signals: #extrinsic: #gamma: 0.995 #strength: 0.125 gail: gamma: 0.99 strength: 1.0 network_settings: normalize: true hidden_units: 128 num_layers: 2 vis_encode_type: simple learning_rate: 0.0003 use_actions: true use_vail: false demo_path: Project/Assets/Demonstrations/${ID_DEMO}.demo ... behavioral_cloning: steps: 100000 strength: 1.0 samples_per_update: 0 demo_path: Project/Assets/Demonstrations/${ID_DEMO}.demo ...
- ※2
- アニメーションを物理ベースのキャラにコピーするときは、最初の数フレームが不安定になりがちです(意図しない揺れが起きる、など)。この部分をデモファイルに記録しないようにするには、コピーを開始したのちに(つまりランタイム時に)、コンポーネント「DemonstrationRecorder 」の引数「record」を有効にします。こうすることで、有効にした時点からの動作を、デモファイルに残すことができます。
- ※3
- もしエディタでリフレッシュ(データベースの更新やスクリプトのコンパイル)のタイミングを制御しているなら、リフレッシュ(Assets > Refresh)を実行することで、デモファイルが生成されます。
あとは通常の手順で学習を行い、動きを模倣元に近づけます。[※4][※5]
- ※4
- この試みでは、リンボーダンスっぽさは多少なくなっていますが、やはりデモの歩き方にはほど遠いというか……腕がさかんに上下するのは、デモを模倣して下げようとする力と、バランスを保つために上げてしまう力が拮抗しているからかもしれません(ただ目標に向かう報酬はゼロにしているはずなのに、なぜか向かっています……どこか元のスクリプトを理解していないところがありそうですが)。