研究

REINFORCE Algorithm でジャンプアクションを学習させてみた

こんにちは. TRSasasusu です.今回は前回に引き続き強化学習の話です.

スクリーンショット 2017-08-07 4.17.50

前回のQ学習は行動価値関数を更新していくことで学習を進めましたが,今回の REINFORCE Algorithm は直接方策を更新していくことで学習を進める方策勾配に基づくアルゴリズムの一種です.

方策勾配に基づく強化学習は状態空間や行動空間が連続であっても取り扱うことができます.ですが,なんとなく連続な状態空間における離散的な行動空間を持つ問題をやってみました.具体的には,ジャンプで穴を飛び越えることを学習していきます.ジャンプするのが早すぎてもタイミングが合わず落ちますし,ジャンプしなくてももちろん落ちます.行動はジャンプするかしないかで,横方向への移動に関しては自動で右へ一定の早さで進ませます.穴との距離と方策の確率モデルのパラメータの関係式をソフトマックス関数に入れ,これを計算して勾配を求めてパラメータを更新しました.


$$ \nabla_{\theta}J(\theta) = \sum^M_{m=1}\sum^T_{t=1}(R^m_t – \overline{b})\nabla_{\theta}\log{\pi_{\theta}}(a^m_t|s^m_t) $$
$$ \theta_{t+1} = \theta_t + \eta\nabla_{\theta}J(\theta) $$

また,報酬については,ジャンプしたら減点(疲れるから),落ちたら大きく減点,穴を越えたら大きく加点という形にしました.

結果は以下のようになりました.

実際にプログラムを動かしてみると,パラメータとしては初期値に関わらずジャンプアクションができそうな値になるのですが,うまくいかない場合も散見されました.REINFORCE Algorithm よりも工夫された手法もあるのでそちらに変更するのも良さそうです.

ところで, REINFORCE Algorithm ってすごく調べづらいのですが… そもそも強化学習は Reinforcement Learning なのでこちらばかり出てきますね.

あと,未だに上に挙げた式でベースラインを引いて良い理由がわからないので,誰か教えてください.

迷路にQ学習を使ってみた

お久しぶりです.ユーザ名を今回から Twitter に合わせて TRSasasusu にしました.

スクリーンショット 2017-08-03 4.06.12

記事にできるような活動があまりできなかったため,気がついたら前回の何か作った系の投稿から7ヶ月も経ってしまいました.今回の投稿は去年UMU氏が投稿したものを大いに参考にしています.(というか,ほぼ同じ.違う点は迷路が大きくなったことくらい)

Q学習は


$$ Q(S_t, A_t) = Q(S_t, A_t) + \alpha(R_{t+1} + \gamma \max_{a’ \in A(s’)} Q(S_{t+1}, a’) – Q(S_t, A_t)) $$

に従って行動価値関数を更新します.そもそも行動価値関数とは,といったことはこちらもUMU氏がまとめてくださっています.ありがとうございます.

方策決定には ε を固定した ε-greedy 法を用いています.これにより局所解を抜け出せるようにします.パラメータについては,


$$ \varepsilon = 0.1 $$
$$ 学習率\ \alpha = 0.1 $$
$$ 割引率\ \gamma = 0.9 $$

としています.

やっぱり途中で戻ったりするようになってしまいますね…何ででしょうね.

あと,Pygame 便利ですね.

今回のスクリプト(q_maze2.py, moyf/ml/rl/q.py)

流体シミュレーション実装(Position Based Fluids)

巷で話題のPosition Based Fluidという物理計算モデルをUnityで実装した.
速度を弄るのではなく,位置を直接弄ることでなんちゃら.

結果

水です.

GitHubにUnityのSceneごとソースを上げてあるので,詳しく知りたい方はどうぞ.
(CUDAを使っているので,Nvidia製のグラボがないと動かないです.)

問題点

.SPHより安定!とか言っておきながら,たまに天空に焦点する粒子がいる.
・壁沿いに動かない粒子がいる.すみっこ好きかよ.

感想

割と軽いので良い.

Assemblyコードの最小化(?)

どうも、チョコです。Assemblyちょっとやってたら調子に乗って記事書きました。誤りがあったら訂正お願いします。

この間、BootLoaderを書いていたが、ファイルサイズが1Sectorの512バイト(-署名2バイト)に入らなければいけなかったため、最適化を行った。(もちろん、ほかのSectorを呼び出して実行はできるが、それでは面白くないから。)

BootLoader#とは?

パソコンが起動したとき、BIOSが初めて実行する512バイトのプログラムをMBRと呼び、このコードがWindowsなどのOSの起動(Boot)をすればBootLoaderと呼ばれる。

最小化#とは?

ここでは、RAMとかStackの最適化とかせずに、実際にコードが保存されているバイト数の節約をする。512バイトしか使ってはいけないので、油断するとすぐ使えないプログラムになってしまう。なんでC++で書かないかのも、このためである。(gcc使えないからとかは黙っておこう)

(ただし、MBRはRealModeで実行するので、Registerは最大32ビットである。)

512バイトで何ができる?

例えば、テトリスのゲームを作ろう。こんな感じの。(最適化の話なので、実際のプログラムはどうでもいいかと)

DA0a29XVoAAfyv6

(作り方を詳しく聞きたい人は、これが完成したら記事を書くので、お楽しみに。)

ここで、移動の処理だけのコードを書くと、なんと100バイトくらい使った。ブロックを積み重ねる判定付けたら180バイト使った。残りのバイトでクレアとか回転とかを実装できそうにないなぁと。

では、プログラムのバイト数を削ってみよう(実際の処理内容は変わらない)。

1.一回しか使わない関数はinlineで書く。逆に、2回以上使う長い処理は関数にまとめる(こっちは常識だな)。call[address] … retは6バイト消化してしまうため、重複処理が6バイト以上であるときだけ関数を使うべき。またRegisterはGlobal変数なので、関数内で宣言もできる。

2.xorを使う(Assemblyでは常識かな)。Registerを0にしたいときにmov EAX,0を書くと4バイト使ってしまうが、xor EAX,EAXを書けば2バイトになる。

3.sub-registerを用いる。EAXの後半がAXで、AXがAHとALの合成など、必要な所を読み、変更できる。例えば、AXは最初が0であれば、mov AX,1とmov AL,1は両方1になるが、AXの場合は2バイトなので結局mov AX,0x0001となり、1バイト無駄になる。

いまは大体こんな感じ。使っている定数に対するregisterのバイト数を気にすると結構バイト数減らせた。以上のことをやるとなんと20バイト以上減らせた。わーい。

(まだ現在進行形ですが、)ソース

では。

BlenderでXray目の再現

どうも、チョコです。多く知られているMultipassのやり方を(今更)理解したので共有したいと思います。

BlenderではMultipassのことをRenderLayerといい、Compositorで組み合わせができる。

ラムのモデルでデモしよう。

Screenshot (1226)

 

髪の毛の前に目を出したいので、まず目と髪の毛を別のオブジェクトにして、髪の毛をレイヤ2にする。

RenderLayerを2個作り、それぞれのマスクを設定する(Hairはレイヤ2しかレンダしない)。

Screenshot (1221)

これをレンダすると、髪の毛が消えた。さて、Compositorで合成しよう。InputNodeを2個使えば両方のRenderLayer画像が入手できる。

 

レイヤ1から目の部分を切り取りたいので、ObjectIDマスクで分離する(目のObjectID1にした)。

Screenshot (1224)

最後に、二つのレイヤをCombineZで合成し、さらに上から切り取った目をAlphaOverする。

Screenshot (1225)

完成。では。

 

OpenGlでスポットライトを実装

チョコです。

エンジン作ってますが照明システムが必要となりました。そこでスポットライトが一番簡単なのでまずそれを実装しました。

Screenshot (1141)

プロセスを説明します。

Deferredなので、まずオブジェクトのパスを出します。zバッファーを使います。

Screenshot (792)
そして、光パスで画面スペース→世界スペースに変換し、光からの距離、角度を出します。割と簡単な数学演算なので省略。
そこで、影がないとおかしいので、影も実装しました。
光パスの前に、光を視点としたMVP行列をかけ、画面をもう一度レンダ―し、マップに保存します。
Screenshot (1142)

光の行列をシェーダーに渡し、世界スペース→陰スペースを算出します。そこのz値を出します。

Screenshot (1143)

陰スペースの自分のz位置と比べて、影かどうかを判断します。完成。biasなど全然かけてないのに割といい結果を出せました。

シェーダーコードも載せときます(フラグメントだけ)

 

これからはポイントライトやら一方向ライトやらの陰も実装しますが、意外と面倒なのでゆっくりやります。では。

Unity でブラックホールのシミュレーション

GPGPUの練習を兼ねて,Unityでブラックホール(っぽいの)をリアルタイムシミュレーションしてみました.

結果

説明

今回はUnityのComputeShaderを利用して並列処理を実装しましたが,CUDAに移植中なので,移植が完了したら別に記事を上げる予定です.
(C#でCUDAを記述する為に,managedCUDAというライブラリを使用しています.)

粒子の数は,上の動画では2の16乗(65536)個ですが,2^20乗でも遅延なく動きました.
GPUはGTX950を使用しています.

以下はComputeShaderのソースです.

結局やっているのは万有引力の計算だけです.しかもかなり省略してます.

CustomShaderとかUnity側のコードは面倒なので載せません.
本当はクソ汚いソースコードを見られたくないだけです.

Unity側やってることはComputeShaderに粒子の初期座標を与えているだけです.
上のComputeShaderではそのデータをもとにフレーム毎の計算を行っています.
そのデータをCustomShaderが受け取って,粒子を描画しているという感じです.
データのやり取りはComputeBufferを介して行っています.

CUDAに移植

移植してます.ぶっちゃけこっちが一番やりたいことで,ComputeShaderはオマケです.

[追記]CUDAに移植した.

全体的に雑.
粒子数:2^20個
ComputeBufferのポインタをそのままCUDAのKernelに渡せるようになったら終わり.
CUDAに移植したら別に記事を書く予定だったけど,面倒なので追記で済ませる.

パラレルデータを用いない多対1声質変換

久しぶりに声質変換の活動を行ったので記録します。以前の記事から半年ほどが経ちました。

https://kcs1959.jp/archives/2432/research/フレーム独立gmm-based-mappingによる声質変換

今回参考にした論文はAI班の記事でも紹介されていますが、以下のような手法です。本文はこちら


声質変換は研究者の数が少ないので他のAI分野に比べて勢いがなく発展が遅れていますが、この手法は2016年8月に発表された画期的な手法です。この手法の凄いところは主に以下のような点です。

  • 同じ内容を話している音声データが必要ない
  • 学習で使った人以外の声からも変換できる
  • 実装が比較的楽にできる

今までの多くの声質変換手法では、同じ内容を話している音声のデータが必要で、学習で使用した人からの変換しかできませんでした。また、最近の手法はなかなか実装が難しいことも個人的には悩みどころでした。

今回の実装ではSPTKという音声分析ツール、Kerasというニューラルネットワークライブラリを主に使用しました。また、音声コーパスはPASDというものを使わせてもらっています。

声質変換の結果は以下のようになりました。
まずは変換元(入力)の声です。改めて強調しておくと、この人の声は声質変換を学習する(変換器をつくる)ときには全く使っていません。

そして変換結果が以下の音声です。変換先の声の目標は水瀬いのりさんという声優の声を使用しています。ラジオの音声を私的に録音したものです。水瀬いのりさんの実際の声はこちらなどを参照してください。

まだ不自然な部分や合成音感が残ってしまっていますが、少なくとも女性らしい声に変換されているのがわかります。今回は論文で使用された5分の1程度の時間の音声を使って学習したため、学習データを増やすことでもう少し質が向上すると思います。データが少ない中で精度を向上するために論文で示されているモデルから多少の変更をしています。詳しい内容は僕の個人的なブログも参照してみてください。

近年ではGANなどの生成モデルが盛んに研究されていて、音声の生成もGoogleのWaveNetに代表されるように数多くの新しい手法が提案されています。この潮流の中での声質変換の発展も期待しつつ、僕も引き続き研究していきたいと思います。