0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[PyBullet] [強化学習] [カメラ] 2軸ロボットアームの強化学習 Part4 (Q学習)

0
Last updated at Posted at 2026-06-24

はじめに

PyBullet (Python上で動く物理シミュレータ) を使用して,ロボットアームを可視化して,動かしたい.

前記事では,エージェントの学習方法として "SARSA (TD学習)" を採用して,PyBullet 内の2軸ロボットアームの強化学習を実装した.

前記事の問題点は,SARSAが "on-policy" の学習手法であるため,行動の選択に使う方策と,Q値の更新に使う方策が同一となる点である.これは,探索(ε-greedy法)の影響を受けたQ値が学習されるため,最適方策への収束が遅くなる可能性がある.

本記事では,エージェントの学習方法として "Q学習 (off-policy TD学習)" を採用する.Q学習では,次状態での最大Q値を使ってQ値を更新するため,行動の選択方策に依らず,"最適方策" への収束を目指すことができる.
グリッパー付きの2軸ロボットアームを使用して,干渉物が存在しない環境下にて,複数のカメラから把持物体の位置を取得して,物体を把持する(下図はPyBullet上のグリッパー付き2軸ロボットアームである).赤枠がグリッパー,緑枠が把持したい物体,青枠がカメラ,青色の球が初期位置である.
2DoF_Random_Agent.png

本記事を実施してできる最終的なものは下記動画の通りである.エージェントの学習方法は "Q学習" である.
下記は,学習中の強化学習による経路生成の動画である.

Q学習_再現フェーズ.gif

下記は,学習後の強化学習による経路生成の動画である.

Q学習_推論フェーズ.gif

本記事で実装すること

  • エージェントの学習方法は"Q学習"

本記事では実装できないこと (将来実装したい内容)

エージェントの学習手法

  • DQN
  • Actor-Critic

動作環境

  • macOS Sequoia (バージョン15.5)
  • Python3 (3.13.3)
  • PyBullet (3.25) (物理シミュレータ)
  • Numpy (2.3.0) (数値計算用ライブラリ)

PyBullet のインストール方法

PyBullet のインストール方法については下記にて,説明したため,割愛する.

PyBulletの使用方法

Pythonの物理シミュレータであるPyBulletの使用方法について説明する.
下記リンクのPyBullet公式で調べながら,PyBulletを使用している.

上記リンクを開くと,下図のようなサイトに飛ぶ.使用方法を調べるときは,下図の赤枠内の「PYBULLET QUICKSTART GUIDE」タグをクリックする.
PyBullet公式.png

「PYBULLET QUICKSTART GUIDE」タグをクリックすると,下図のようなドキュメントを見ることができる.基本的には,ドキュメントに記載されている関数の使用方法を見て,ソースコードを作成している.
PyBulletドキュメント.png
PyBulletの関数の引数や戻り値をもっと知りたいのでしたら,上記ドキュメントを見た方がわかりやすいです.

2軸ロボットアームの定義

2軸ロボットアームの定義については下記にて,説明したため,割愛する.

グリッパーの定義

グリッパーの定義については下記にて,説明したため,割愛する.

グリッパー付き2軸ロボットアームのURDF作成

グリッパー付き2軸ロボットアームのURDF作成については下記にて,説明したため,割愛する.

URDFに関しては,下記にて説明したため,割愛する.

カメラによる把持物体の2次元位置を取得

PyBulletでカメラ情報を取得する方法については下記にて,説明したため,割愛する.

強化学習に関して

強化学習は機械学習の一つの種類である.強化学習とは,自分で試行錯誤をしてデータを集め,詰めたデータから良い行動を学習することである.
強化学習のイメージは下図の通りである.

Env_Agent.drawio.png

1:「環境」から「エージェント」に対して,「状態」を渡す
2:「エージェント」が「状態」より,「行動」を選択する
3:「エージェント」から「環境」に対して,「行動」を実行する
4:「環境」が「行動」より,「状態」を更新する
5:「環境」から「エージェント」に対して,「報酬」を渡す
6:「エージェント」が「報酬」より,「学習」する

ここで,用語の定義をする.

用語 用語の定義
エージェント 行動の主体者
環境 エージェントと相互作用を行う対象
状態 エージェントの行動によって置かれるエージェントの状況
行動 エージェントが起こすアクション
報酬 エージェントの行動に対する環境からのフィードバック

本記事での "環境" は "PuBullet上のロボットと環境" である."エージェント" は "ロボットを動かすための頭脳" である.
以下では,本記事で使用する "環境" と "エージェント" を説明していく.

強化学習の環境に関して

強化学習の環境に関しては下記にて,説明したため本記事では割愛する.

強化学習のエージェントに関して

強化学習のエージェントに関して説明する.強化学習の全体像の中で,下図の赤枠で囲んだ「エージェント」を説明する.

Env_AgentAtract.drawio.png

エージェントは,環境から「状態」を受け取り,「行動」を行い,「報酬」を得て,次の「状態」へ遷移する.下記のように1エピソードが完了するまで,「状態(S)」,「行動(A)」,「報酬(R)」,「状態(S)」のループとなる.
$S_{0}, A_{0}, R_{0}, S_{1}, A_{1}, R_{1}, ...$

行動価値関数に関して

行動価値関数については下記にて,説明したため本記事では割愛する.

Q学習に関して

エージェントの学習方法の一種である "Q学習" に関して説明する.

Q学習とは,"off-policy の TD学習" の一種である.Q値の更新式は以下の通りである.

\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t) \right] \\
\\
文字の意味は以下の通り.\\
Q ... \text{行動価値関数},\; \alpha ... \text{学習率},\; \gamma ... \text{割引率} \\
s_t ... \text{時刻}t\text{の状態},\; a_t ... \text{時刻}t\text{の行動},\; r_t ... \text{時刻}t\text{の報酬} \\
s_{t+1} ... \text{次の状態},\; \max_{a'} Q(s_{t+1}, a') ... \text{次状態での最大Q値}
}

SARSAとQ学習の違いは,更新式における "次状態の価値の見積もり" にある.SARSAでは実際にε-greedy方策で選択した $a_{t+1}$ の Q値 $Q(s_{t+1}, a_{t+1})$ を使うのに対して,Q学習では次状態での全行動の中で最大の Q値 $\max_{a'} Q(s_{t+1}, a')$ を使う点が異なる.

SARSAとQ学習の比較を下表にまとめた.

比較項目 SARSA Q学習
更新タイミング 1ステップごと 1ステップごと
更新に必要な情報 $(s_t, a_t, r_t, s_{t+1}, a_{t+1})$ $(s_t, a_t, r_t, s_{t+1})$
次状態の価値見積もり $Q(s_{t+1}, a_{t+1})$(ε-greedy選択) $\max_{a'} Q(s_{t+1}, a')$(最大値)
方策の種類 on-policy off-policy
最適方策への収束 探索の影響を受ける 探索に依らず最適方策に収束

Q学習は "off-policy" の学習手法である.off-policyとは,"行動の選択に使う方策(行動方策)と,Q値の更新に使う方策(ターゲット方策)が異なる" ことを意味する.具体的には,行動はε-greedy方策で選択するが,Q値の更新には "greedy方策 (最大Q値を選択する方策)" を使う.そのため,探索時のランダムな行動がQ値の更新に影響しないため,最適方策に近いQ値を学習できる.

Q学習の学習フローを以下に示す.

1:初期状態 $s_0$ を取得する
2:ε-greedy方策で行動 $a_t$ を選択する
3:行動 $a_t$ を実行して,報酬 $r_t$ と次の状態 $s_{t+1}$ を得る
4:$Q(s_t, a_t)$ を更新式で更新する (次行動の選択は不要)
5:$s_t \leftarrow s_{t+1}$ として2に戻る

SARSAと異なる点は,"ループ前に最初の行動を選択する必要がない" 点である.Q学習では,更新式に次行動 $a_{t+1}$ が含まれないため,ループ内で行動を選択してからステップを実行し,次状態の最大Q値でQ値を更新するだけでよい.

Q学習の更新式の意味を分解すると下式の通りとなる.

\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ r_t + \gamma \max_{a'} Q(s_{t+1}, a') - Q(s_t, a_t) \right] \\
\\
\underbrace{r_t + \gamma \max_{a'} Q(s_{t+1}, a')}_{\text{TD目標値 (最適行動を仮定した1ステップ先の見積もり)}} - \underbrace{Q(s_t, a_t)}_{\text{現在の推定値}} = \underbrace{\delta_t}_{\text{TD誤差}} \\
\\
Q値の更新 = Q値 + \alpha * TD誤差 \\
TD誤差が正なら Q値を増やす(現在の推定より良い状態だった)\\
TD誤差が負なら Q値を減らす(現在の推定より悪い状態だった)
}

TD目標値として "次状態で取り得る最大のQ値" を使うことで,実際に選択した行動の影響を排除し,常に最適な行動を仮定した上でQ値を更新する.これにより,探索が多いエピソード序盤でも,最適方策に近いQ値を学習し続けることができる.

行動の選択方法 (ε-greedy法)

行動の選択方法 (ε-greedy法) に関しては下記にて,説明したため本記事では割愛する.

ソースコード一覧

本記事で使用する全ソースコードの一覧を下表にまとめる.フォルダ名が記載されているものは,そのフォルダを作成して,フォルダ内にファイルを保存してください.

URDFファイル

ファイル名 概要
camera_back_to_front.urdf 手前方向(-Y方向)を向いているカメラの定義
camera_front_to_back.urdf 奥行き方向(+Y方向)を向いているカメラの定義
camera_left_to_right.urdf 右方向(+X方向)を向いているカメラの定義
camera_right_to_left.urdf 左方向(-X方向)を向いているカメラの定義
camera_up_to_down.urdf 下方向(-Z方向)を向いているカメラの定義
grasp_object.urdf 把持物体の定義
robot_2dof.urdf グリッパーなし2軸ロボットアームの定義
environment_2dof.urdf 2軸ロボットアームの環境を定義
robot_2dof_hand.urdf グリッパー付き2軸ロボットアームの定義

Pythonファイル

ファイル名 概要
constant.py 定数の定義 (Q学習追加)
main.py 全体的なメイン処理
pybullet_grasp.py PyBulletの把持物体
pybullet_gripper.py PyBulletのグリッパー
pybullet_robot.py PyBulletのロボット
pybullet_camera.py PyBulletのカメラ
pybullet_agent_controller.py PyBulletのエージェント制御 (Q学習対応)
BaseAgent.py PyBulletのエージェントの抽象クラス
RandomAgent.py PyBulletのランダムに動くエージェント
MonteCarloAgent.py PyBulletのモンテカルロ法で学習するエージェント
SarsaAgent.py PyBulletのSARSAで学習するエージェント
QLearningAgent.py PyBulletのQ学習で学習するエージェント
pybullet_environment_controller.py PyBulletの強化学習用の環境制御
BaseEnvironment.py PyBulletの強化学習用の環境の抽象クラス
DiscretizeEnvironment.py PyBulletの強化学習用の離散値環境
pybullet_main.py PyBulletのメイン処理 (Q学習ループ)

pybullet_main.py の変更点に関して

pybullet_main.py__learning() メソッドをQ学習用に変更した点について説明する.

SARSAとQ学習の学習ループの違いを下表にまとめた.

比較項目 SARSA (part3) Q学習 (part4)
最初の行動選択 ループ前に選択 whileループ内で選択
add() の呼び出し add(s, a, r, s', a') add(s, a, r, s')
Q値の更新タイミング ステップごとの add() ステップごとの add()
update() の役割 ε更新のみ ε更新のみ

Q学習でループ前の行動選択が不要な理由は,"更新式に次行動 $a_{t+1}$ が含まれない" ためである.SARSAでは次のステップ前に $a_{t+1}$ が必要だったが,Q学習では次状態 $s_{t+1}$ の最大Q値を使うため,次行動を事前に決める必要がない.

Q学習の __learning() の主要部分を抜粋すると以下の通りとなる.

while not done:
    # 行動の選択 (ε-greedy方策)
    action = self.__agent.get_action(state)

    # 1ステップ実行: (s, a) → (s', r, done)
    next_state, reward, done = self.__env.step(action)

    # Q値を即時更新: Q(s,a) ← Q(s,a) + α[r + γ*max_a'(Q(s',a')) - Q(s,a)]
    self.__agent.add(state, action, reward, next_state)

    # 状態の更新 (s ← s')
    state = next_state

# エピソード終了: 探索確率 ε の更新 (Q値更新はadd()内で完了済み)
self.__agent.update()

QLearningAgent.py の実装に関して

QLearningAgent.py では,SARSA (SarsaAgent.py) と比較して,以下の点が異なる.

add() メソッドの引数変更
SARSAでは add(state, action, reward, next_state, next_action) だったが,Q学習では次行動が不要なため,add(state, action, reward, next_state) に変更した.また,Q値の更新式として,次行動の Q値の代わりに "次状態での最大Q値 $\max_{a'} Q(s_{t+1}, a')$" を使う.

\displaylines{
Q(s_t, a_t) \leftarrow Q(s_t, a_t) + \alpha \left[ \underbrace{r_t + \gamma \max_{a'} Q(s_{t+1}, a')}_{\text{TD目標値}} - Q(s_t, a_t) \right]
}

QLearningAgent.pyadd() メソッドの実装を抜粋すると以下の通りとなる.

def add(self, state, action, reward, next_state):
    """
    データの追加 + Q値の即時更新 (1ステップごとに呼ぶ)

    Q学習の更新式:
        Q(s, a) ← Q(s, a) + α * [r + γ * max_a'(Q(s', a')) - Q(s, a)]

    パラメータ
        state(tuple)      : 現在の状態
        action(int)       : 現在の行動
        reward(float)     : 報酬
        next_state(tuple) : 次の状態
    """
    key = (state, action)

    # 次状態での全行動のQ値を取得して,最大値を選択
    next_Qs = [self.__Q[next_state, a] for a in range(self.__n_action)]
    max_next_Q = max(next_Qs)

    # TD誤差の計算: r + γ * max_a'(Q(s', a')) - Q(s, a)
    td_error = reward + self._GAMMA * max_next_Q - self.__Q[key]

    # 行動価値関数の更新
    self.__Q[key] = self.__Q[key] + self._ALPHA * td_error

update() メソッドの役割
SARSAと同様に,update() は ε 更新のみである (Q値更新は add() で完了済み).

パラメータファイル
Q学習は qlearning_param.json にQ値を保存する.学習パラメータ (γ, α, ε など) はSARSAと同一の値とした.

パラメータ
割引率 γ 0.9
学習率 α 0.1
探索確率の最小値 ε_min 0.1
探索確率の最大値 ε_max 0.9
探索確率の減衰率 0.9999

PyBulletのメイン処理 (pybullet_main.py)

p.connect() 関数の引数である p.DIRECTp.GUI に関しては下記にて,説明したため本記事では割愛する.

PyBulletでロボットを動かす

上記にて,ソースコードを説明した.
main.py ファイルを実施することによって,PyBullet上のロボットを動かしていく.

経路生成の動画

Q学習に動くエージェントによる経路生成の動画を載せる.

動画1:学習時の経路生成の動画

Q学習_再現フェーズ.gif

動画2:学習完了後の経路生成の動画

Q学習_推論フェーズ.gif

Q学習はoff-policyの学習手法であるため,SARSAと比較して,より最適な方策に収束することが期待される.探索時のランダムな行動がQ値の更新に影響せず,常に "次状態で最も価値の高い行動" を仮定してQ値を更新するためである.
そのため,次回はQ学習ではなく,より表現力の高いDQN (Deep Q-Network) を採用することで,状態数が爆発的に増加するケースにも対応できるようにする.

おわりに

本記事では,Pythonを使用して,下記内容を実装しました

  • エージェントの学習方法としてQ学習を採用して,PyBullet 内の2軸ロボットアームの強化学習

次記事では,下記内容を実装していきます.

参考文献

本記事を作成する上で参考にした内容を記載する.

参考記事

参考書籍

  • ゼロから作るDeep Learning ❹ ―強化学習編
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?