あかすくぱるふぇ

同人サークル「あかすくぱるふぇ」のブログです。

強化学習について調べると、具体的な手法の説明は理解できるのですが、より一般化された議論から始めているページを見ると、「なんでこんな回りくどい議論になるんだろう?」と迷子になってしまいます。
一方で、具体的な手法の説明だけを見ていると、「どうしてこういう手法を用いるんだろう? 他に方法はないの?」とやはり悩んでしまいます。

そこで本記事では、具体的なQ学習の説明からスタートし、それを一般化するという逆の流れで強化学習の基礎について解釈してみようと思います。

以下のページを参考にしていますので、合わせてお読みください。
http://blog.brainpad.co.jp/entry/2017/02/24/121500
https://qiita.com/icoxfog417/items/242439ecd1a477ece312
https://qiita.com/Hironsan/items/56f6c0b2f4cfd28dd906

まず、Q学習の式は以下のように表せます。
Q(s_t, a_t) ← Q(s_t, a_t) + α(r_t+1 + γ*max_a_t+1(Q(s_t+1, a_t+1)) - Q(s_t, a_t))
t : 時刻
s : 状態
Q : Q値
a : 行動
α : 学習率
r : 即時報酬
γ : 割引率
max_a_t+1(x) : a_t+1に関するxの最大値

この式は、現在のQ値の推定値Q(s_t, a_t)を、より確からしい推定値r_t+1 + γ*max_a_t+1(Q(s_t+1, a_t+1))に近づけるよう、学習率αで更新するものです。
ここで右側の式は、「遷移先状態s_t+1における即時報酬r_t+1」と「遷移先状態s_t+1におけるQ値の最大値(最適と思われる行動a_t+1をとった時のQ値)」を足したものです。

重要な点は、Q(s, a)には最初デタラメな値が入っているし、それによって、上記「最適と思われる行動a_t+1」も実際は最適ではなく、デタラメな行動になってしまうということです。

では、どうやって学習が進むのでしょうか?
それは、(たまたま)状態s_t+1がゴールだった場合に即時報酬r_t+1によってQ(s_t, a_t)の値が大きくなり、ゴールの一個前の状態sにおいて最適な行動aをとるようになることから始まります。
そこからだんだんとゴールから遠い状態sにも学習が進んでいきます。



以上がQ学習の説明です。
では、ここから議論を一般化します。

問題は、状態s_tで行動a_tをとった場合の遷移先状態s_t+1は実際には確率的なものになるということです。
むつかしく言うと、遷移先状態s_t+1は遷移確率P(s_t+1 | s_t, a_t)によって決まります。
例えばテトリスであれば、テトリスの駒を動かす行動による状態の遷移は確定的ですが、上からどんな駒が落ちてくるかは確率的です。
つまり、上記式のQ(s_t+1, a_t+1)は、実際はE[Q(s_t+1, a_t+1)] = ΣP(s_t+1 | s_t, a_t)*Q(s_t+1, a_t+1)となります。
しかも、遷移確率P(s_t+1 | s_t, a_t)は未知であることがほとんどです。

この問題をQ学習はどう考慮しているのでしょうか?
その答えは、「実際に行動a_tをとってみて、その結果の状態s_t+1によってQ値を更新する」というものです。
状態s_t+1は遷移確率P(s_t+1 | s_t, a_t)によって決まる(遷移されてくる確率が高い状態s_t+1はたくさん試行される)ので、Q(s_t+1, a_t+1)は試行を繰り返すほど実際の期待値に近づいていきます。

このようにP(s_t+1 | s_t, a_t)がわからない状態で、環境のモデル化を行わずに学習する方法をModel-Freeな学習方法と呼びます。
(※モデルを仮定して行う学習をModel-Basedな学習方法と呼ぶようですが、勉強不足でよくわからないです)
Model-Freeな学習方法としてQ学習の他にSarsaやモンテカルロ方などがあり、手法ごとに期待値計算の代用方法が異なります。
つまり、強化学習の問題設定は、環境(遷移確率)がわからない状態でいかにQ値を学習させるかというものであり、手法ごとに工夫が異なるということです。

なお、遷移確率P(s_t+1 | s_t, a_t)が分かっている場合は、実際に期待値を計算して、イテレーションを回すだけです。


以上、強化学習の基礎を具体的→一般化の流れで解釈してみました。

・URDFの基本形
<robot name="">
    <link name="">
       <visual>
           <geometry></geometry>
       </visual>
       <collision>
           <geometry></geometry>
       </collision>
       <inertial>
         <mass>
         <inertia>
       </inertial>
    </link>
    <joint name="" type="">
        <axis>
        <parent link="">
        <child link="">
        <origin>
    </joint>
</robot>

robot nameはGazeboにモデルをspawnする時などに使う
linkの位置はjointで親リンクとの相対位置として指定する


・関節情報のやり取り
パラメーターサーバーはURDFモデルをrobot_descriptionという名前で読み込む
  <param name="robot_description" textfile="$(find tortoisebot)/urdf/tortoisebot.urdf>
/joint_state_publisherノードは、関節状態を/joint_statesトピックとして配信する
  <gazebo>
   <plugin name="joint_state_publisher">
    <jointName></jointName>
   </plugin>
  </gazebo>
/robot_state_publisherノードは、パラメーターサーバーからURDFモデルを読み込み、/joint_statesを購読して順運動学を実行し、/tfトピックとして配信する
  <node name="robot_state_publisher" pkg="" type=""/>
rvizは、パラメーターサーバーからURDFモデルを読み込み、/tfを購読して、ロボットを可視化する


・ロボットの動かし方
移動ロボットなら、cmd_velトピックをdifferential_drive_controllerプラグインに購読させて動かす(p.307)
アームロボットなら、follow_joint_trajectoryアクションをros_controllプラグインに受信させて動かす(p.343)
 controller_managerがJointTrajectoryトピックを購読してfollow_joint_trajectoryアクションをros_controllに投げる

・設定
~/.emacsで設定

・保存
C-x C-s

・コピペ
コピー:M-w
ペースト:C-y
切り取り:C-w

・アンドゥ
C-x u

・検索
下へ:C-s
上へ:C-r

・ウィンドウ分割
縦分割:C-x 2
横分割:C-x 3
消去:C-x 0

・ウィンドウ幅変更
ウィンドウの下の方をドラッグ

↑このページのトップヘ