DonkeyCar simulatorで強化学習のサンプルを実行してみる(DDQN編)
DonkeyCar3シミュレーターで強化学習してみるのマネをしてDonkeyCarシミュレータライブラリの中にあるサンプルのddqn.pyを実行してみる。
参考:
DQNについてはここが分かりやすかったかな。
【深層強化学習,入門】Deep Q Network(DQN)の解説とPythonで実装 〜図を使って説明〜
【深層強化学習】Double Deep Q Network(DDQN)
# 作業ディレクトリ作成
mkdir -p /work2/donkey_sim
cd /work2/donkey_sim
# 仮想環境構築
pyenv virtualenv 3.8.11 donkey_sim
pyenv local donkey_sim
pip install --upgrade pip setuptools wheel
# 必要なライブラリのインストール
pip install opencv-python
pip install tensorflow
# 現時点での最新リリース v21.7.24 をcheckoutしておく
git clone https://github.com/tawnkramer/gym-donkeycar -b v21.07.24
# gym-donkeycarライブラリのインストール
pip install -e gym-donkeycar
[!NOTE] gym-donkeycar は -e (–editable) オプション付きでインストールしているので、編集も可能。 git cloneした先を参照しているので、インストール後もgym-donkeycarを削除しちゃダメ。
githubから直接インストールする場合は以下。
この場合、パッケージは通常のディレクトリにインストールされる。pip install git+https://github.com/tawnkramer/gym-donkeycar@v21.07.24
でも、以下でサンプルプログラム使うので、git cloneもしないとダメ。
以下のページから実行するプラットフォームに合わせてDonkeySimXXXX.zip
(XXXXはプラットフォーム名)をダウンロードし、
適当なディレクトリに展開しておきます。
(Linux/Macの場合は実行属性付けるのを忘れずに)
https://github.com/tawnkramer/gym-donkeycar/releases
マシンスペックがそれほど高くない場合は別マシンで実行してリモート接続するのがおススメ。
SSH接続で実行する場合はリモート必須。
以下のパッチファイルを使用してサンプルプログラムにパッチをあてます。
内容は、
gym_donkeycar
がimportされてなかったrl_sample.patch
diff --git a/examples/reinforcement_learning/ddqn.py b/examples/reinforcement_learning/ddqn.py
index 87c74f0..5c32f49 100755
--- a/examples/reinforcement_learning/ddqn.py
+++ b/examples/reinforcement_learning/ddqn.py
@@ -21,6 +21,8 @@ from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
+import gym_donkeycar
+
EPISODES = 10000
img_rows, img_cols = 80, 80
# Convert image into Black and white
@@ -121,6 +123,9 @@ class DQNAgent:
if self.epsilon > self.epsilon_min:
self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore
+ def set_epsilon(self, epsilon):
+ self.epsilon = epsilon
+
def train_replay(self):
if len(self.memory) < self.train_start:
return
@@ -196,15 +201,17 @@ def run_ddqn(args):
run a DDQN training session, or test it's result, with the donkey simulator
"""
- # only needed if TF==1.13.1
- config = tf.ConfigProto()
- config.gpu_options.allow_growth = True
- sess = tf.Session(config=config)
- K.set_session(sess)
+ tf_ver = tf.__version__.split('.')
+ if (tf_ver[0] == 1 and tf_ver[1] >= 13) :
+ # only needed if TF==1.13.1
+ config = tf.ConfigProto()
+ config.gpu_options.allow_growth = True
+ sess = tf.Session(config=config)
+ K.set_session(sess)
conf = {
"exe_path": args.sim,
- "host": "127.0.0.1",
+ "host": args.host,
"port": args.port,
"body_style": "donkey",
"body_rgb": (128, 128, 128),
@@ -237,6 +244,9 @@ def run_ddqn(args):
try:
agent = DQNAgent(state_size, action_space, train=not args.test)
+ if args.epsilon > 0 :
+ agent.set_epsilon(args.epsilon)
+
throttle = args.throttle # Set throttle as constant value
episodes = []
@@ -350,6 +360,7 @@ if __name__ == "__main__":
default="manual",
help="path to unity simulator. maybe be left at manual if you would like to start the sim on your own.",
)
+ parser.add_argument("--host", type=str, default="127.0.0.1", help="simulator address")
parser.add_argument("--model", type=str, default="rl_driver.h5", help="path to model")
parser.add_argument("--test", action="store_true", help="agent uses learned model to navigate env")
parser.add_argument("--port", type=int, default=9091, help="port to use for websockets")
@@ -357,6 +368,7 @@ if __name__ == "__main__":
parser.add_argument(
"--env_name", type=str, default="donkey-warehouse-v0", help="name of donkey sim environment", choices=env_list
)
+ parser.add_argument("--epsilon", type=float, default=0.0, help="initial epsilon value")
args = parser.parse_args()
以下のコマンドを実行します。
cd gym-donkeycar/
patch -p1 < rl_sample.patch
とりあえず学習しないと話にならないので学習します。
強化学習は教師データが要らないので、準備がラクチン… でも学習には時間がかかる…
DonkeyCar シミュレータをリモートマシンで実行する場合、
リモートマシンでDonkeyCar シミュレータを実行しておき、以下のコマンドを実行します。
--sim
オプションにremote
を、実行マシンのIPアドレスを--host
オプションに指定します。
cd examples/reinforcement_learning
python ddqn.py --sim=remote --host=192.168.78.200
[!NOTE] ローカルマシンでシミュレータを実行する場合は
--sim
オプションにDonkeyCar シミュレータ起動コマンドをフルパスで指定します。
このとき、--host
オプションは不要です。
シミュレータをあらかじめ起動しておく必要はなく、自動的に起動されます。
エピソード毎に学習結果が rl_driver.h5
に保存されるので、任意のタイミングでCTRL-Cで中断できます。
次回学習を再開する場合は、ログとして表示されているepsilon: 0.XXXXXXX
の部分の最後の値を覚えておいてください。
このプログラムではε値は0.02を下回ると固定されるので、ある程度学習が進んだ状態では0.02
だと思っても問題ないでしょう。
学習を再開する場合は以下のように上記コマンドに--epsilon
オプションを追加して実行します。
(0.XXXXXXX
の部分は上で覚えておいた値。ピッタリ同じでなくて大体で可)
python ddqn.py --sim=remote --host=192.168.78.200 --epsilon=0.XXXXXXX
学習のときのコマンドに--test
を指定するだけです。
--epsilon
オプションは指定しません。
python ddqn.py --sim=remote --host=192.168.78.200 --test
うまく学習が進んでいれば、コースアウトすることなく周回してくれるハズ。
学習時と同様、コースアウトすると自動的にスタート位置に戻って再スタートします。
適当にCTRL-Cで止めてください。
以下はソースを読んだ時のメモです。
書いてみたけど、自分で読んでも なにが何だか分からない…😢
この辺はお約束なので。
"""
file: ddqn.py
author: Felix Yu
date: 2018-09-12
original: https://github.com/flyyufelix/donkey_rl/blob/master/donkey_rl/src/ddqn.py
"""
import argparse
import os
import random
import signal
import sys
import uuid
from collections import deque
import cv2
import gym
import numpy as np
import tensorflow as tf
from tensorflow.keras import backend as K
from tensorflow.keras.layers import Activation, Conv2D, Dense, Flatten
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
gym_donkey
をimportしないとDonkeyCarシミュレータと接続できないので。
なぜかオリジナルでは入ってなかった。
if __name__ == "__main__":
付けといた方が良いかもしれんが、とりあえずそのままimportしておく。
import gym_donkeycar
意味は以下の通り。
変数 | 意味 |
---|---|
EPISODES | 学習回数 |
img_rows | 入力に使用する画像サイズ(Y) |
img_cols | 入力に使用する画像サイズ(X) |
img_channels | 入力に過去何フレーム分のデータを使用するか |
EPISODES = 10000
img_rows, img_cols = 80, 80
# Convert image into Black and white
img_channels = 4 # We stack 4 frames
強化学習のエージェントを定義したクラスです。
class DQNAgent:
クラス変数
変数 | 意味 |
---|---|
t | 実行カウンタ(ステータス表示用のみ使用) |
max_Q | Q値の最大値(ステータス表示用のみ使用) |
train | 学習モード/テストモード(--test オプションで指定) |
state_size | モデルの入力層のサイズ。現状未使用 |
action_space | シミュレータの現在のステアリング/スロットル設定値取得用 |
action_size | 未使用。たぶん、ステアリング角を何分割するかの定義(15)にすべきだと思う |
discount_factor | 割引率(γ値) (固定値) |
learning_rate | 学習率 (固定値) |
epsilon | 現在の探索率(ε値) |
initial_epsilon | 探索率の最大値 最小率と共に探索率の変更率を計算する(固定値) |
epsilon_min | 探索率の最小値 学習時の探索率をこれより小さくしない(固定値) |
explore | 探索率を最小値にするまでの回数(固定値) |
batch_size | バッチサイズ (固定値) |
train_start | 学習開始タイミング(最初は学習を行わない)(固定値) |
memory | Experience Buffer |
model | メインモデル |
target_model | ターゲットモデル(double DQNなので) |
def __init__(self, state_size, action_space, train=True):
self.t = 0
self.max_Q = 0
self.train = train
# Get size of state and action
self.state_size = state_size
self.action_space = action_space
self.action_size = action_space
# These are hyper parameters for the DQN
self.discount_factor = 0.99
self.learning_rate = 1e-4
if self.train:
self.epsilon = 1.0
self.initial_epsilon = 1.0
else:
self.epsilon = 1e-6
self.initial_epsilon = 1e-6
self.epsilon_min = 0.02
self.batch_size = 64
self.train_start = 100
self.explore = 10000
# Create replay memory using deque
self.memory = deque(maxlen=10000)
# Create main model and target model
self.model = self.build_model()
self.target_model = self.build_model()
# Copy the model to target model
# --> initialize the target model so that the parameters of model & target model to be same
self.update_target_model()
そんなに複雑なモデルではないみたい。
def build_model(self):
model = Sequential()
model.add(
Conv2D(24, (5, 5), strides=(2, 2), padding="same", input_shape=(img_rows, img_cols, img_channels))
) # 80*80*4
model.add(Activation("relu"))
model.add(Conv2D(32, (5, 5), strides=(2, 2), padding="same"))
model.add(Activation("relu"))
model.add(Conv2D(64, (5, 5), strides=(2, 2), padding="same"))
model.add(Activation("relu"))
model.add(Conv2D(64, (3, 3), strides=(2, 2), padding="same"))
model.add(Activation("relu"))
model.add(Conv2D(64, (3, 3), strides=(1, 1), padding="same"))
model.add(Activation("relu"))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation("relu"))
# 15 categorical bins for Steering angles
model.add(Dense(15, activation="linear"))
adam = Adam(lr=self.learning_rate)
model.compile(loss="mse", optimizer=adam)
return model
シミュレータの出力はRGB画像、モデルの入力はグレースケール画像なので、その変換を行うための関数。
cv2.dst = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
で良い気もするが…
def rgb2gray(self, rgb):
"""
take a numpy rgb image return a new single channel image converted to greyscale
"""
return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])
シミュレータの出力画像をモデルの入力データに変換する処理。
RGBからグレースケールに変換し、リサイズを行う。
def process_image(self, obs):
obs = self.rgb2gray(obs)
obs = cv2.resize(obs, (img_rows, img_cols))
return obs
メインモデルのパラメータをターゲットモデルにコピーする
def update_target_model(self):
self.target_model.set_weights(self.model.get_weights())
乱数を発生し、ε値以下だったら環境が生成したランダム値(self.action_space.sample()[0]
)を返す。
それ以外はメインモデルで予測した結果を返す。
その際、モデルの出力結果そのままではなく、どのステアリング位置に当たるかの量子化を行って返す。
(得られるのはステアリング情報だけで、スロットル情報は固定値)
# Get action from model using epsilon-greedy policy
def get_action(self, s_t):
if np.random.rand() <= self.epsilon:
return self.action_space.sample()[0]
else:
# print("Return Max Q Prediction")
q_value = self.model.predict(s_t)
# Convert q array to steering value
return linear_unbin(q_value[0])
現在の状態(state)、行動(action)、報酬(reward)、行動後の状態(next_state)、
終了フラグ(done)をExperience Bufferに保存する。
(Experience Buffer は Experience Replayに使用するためのデータを保存しておくところ)
memory
は collections.dque()
で作成しているので、指定サイズを超えたときは古いデータから順に削除される。
def replay_memory(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))
現在のε値が最小値より大きかったら一定比率で小さくしていく。
最小値以下になっていたらそのまま。
def update_epsilon(self):
if self.epsilon > self.epsilon_min:
self.epsilon -= (self.initial_epsilon - self.epsilon_min) / self.explore
--epsilon
オプション追加したので、指定値でε値を変更する処理を追加。
def set_epsilon(self, epsilon):
self.epsilon = epsilon
Experience Bufferから任意の経験を取り出し、Q Networkをミニバッチ学習(Experience Replay)
記憶したデータ数がself.train_start
に達するまでは何もしない。
バッチ学習に使用するデータをExperience Bufferから取り出し、
それぞれの配列にバラす(state_t
,action_t
, reward_t
, state_t1
, terminal
)。
state_t
とstate_t1
はnp.concatenate()
でndarrayにまとめておく。
11行目のself.model.predict(state_t)
はself.max_Q
の取得にしか使用されておらず、
self.max_Q
はステータス表示にしか使用されてなく、無駄な計算なので、削除するのが良いと思われる(無駄な計算なので)。
その場合、targets
の初期化はtargets = np.zeros((batch_size, 15))
で行う。
(self.max_Q
を参照しているところも削除。あるいはget_action()
で戻り値として返すのも手か。)
state_t1
を入力としてメインモデルをターゲットモデルを使用して得られた出力から出力期待値を取得し、
学習を行うself.model.train_on_batch(state_t, targets)
。
この辺は
【深層強化学習】Double Deep Q Network(DDQN)
のソースとかを見ると分かったような分からないような気になれるかも…
def train_replay(self):
if len(self.memory) < self.train_start:
return
batch_size = min(self.batch_size, len(self.memory))
minibatch = random.sample(self.memory, batch_size)
state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)
state_t = np.concatenate(state_t)
state_t1 = np.concatenate(state_t1)
targets = self.model.predict(state_t)
self.max_Q = np.max(targets[0])
target_val = self.model.predict(state_t1)
target_val_ = self.target_model.predict(state_t1)
for i in range(batch_size):
if terminal[i]:
targets[i][action_t[i]] = reward_t[i]
else:
a = np.argmax(target_val[i])
targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])
self.model.train_on_batch(state_t, targets)
モデルの読み込み先はメインモデル。
このあと、ターゲットモデルへコピーするので、ここではターゲットモデルは触らない。
def load_model(self, name):
self.model.load_weights(name)
メインモデルをファイルに保存する。
# Save the model which is under training
def save_model(self, name):
self.model.save_weights(name)
ステアリング角(-1~1)をモデル出力形式(要素数15の配列のどれか1つに1が入る)に変換する。
def linear_bin(a):
"""
Convert a value to a categorical array.
Parameters
----------
a : int or float
A value between -1 and 1
Returns
-------
list of int
A list of length 15 with one item set to 1, which represents the linear value, and all other items set to 0.
"""
a = a + 1
b = round(a / (2 / 14))
arr = np.zeros(15)
arr[int(b)] = 1
return arr
モデル出力のうち、最大値を持つindexに相当するステアリング角を取得する。
def linear_unbin(arr):
"""
Convert a categorical array to value.
See Also
--------
linear_bin
"""
if not len(arr) == 15:
raise ValueError("Illegal array length, must be 15")
b = np.argmax(arr)
a = b * (2 / 14) - 1
return a
def run_ddqn(args):
"""
run a DDQN training session, or test it's result, with the donkey simulator
"""
Tensorflow 2 を使用したかったので、処理不要。
コメントアウトすれば良いのだけれど、なんとなくバージョンで分けてみた。
1.14以降では要るのかな?要ると思って書いてみた。
tf_ver = tf.__version__.split('.')
if (tf_ver[0] == 1 and tf_ver[1] >= 13) :
# only needed if TF==1.13.1
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
K.set_session(sess)
body_style
には donkey
、 bare
、car01
、cybertruck
、f1
が使用できるらしい。
body_rgb
で 色を指定できるらしい。
car_name
でシミュレータに表示される名前を指定。複数の車を走らせるときに見分けられるみたい。
font_size
で名前のフォントサイズを指定。
conf = {
"exe_path": args.sim,
"host": args.host,
"port": args.port,
"body_style": "donkey",
"body_rgb": (128, 128, 128),
"car_name": "me",
"font_size": 100,
"racer_name": "DDQN",
"country": "USA",
"bio": "Learning to drive w DDQN RL",
"guid": str(uuid.uuid4()),
"max_cte": 10,
}
# Construct gym environment. Starts the simulator if path is given.
env = gym.make(args.env_name, conf=conf)
プログラム終了時にシミュレータの終了処理を行うようにフックルーチンを登録する。
# not working on windows...
def signal_handler(signal, frame):
print("catching ctrl+c")
env.unwrapped.close()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGABRT, signal_handler)
# Get size of state and action from environment
state_size = (img_rows, img_cols, img_channels)
action_space = env.action_space # Steering and Throttle
try:
agent = DQNAgent(state_size, action_space, train=not args.test)
オプションでε値が指定されていたら設定する。
if args.epsilon > 0 :
agent.set_epsilon(args.epsilon)
スロットルの設定は固定値(コマンドラインオプションで設定)
throttle = args.throttle # Set throttle as constant value
episodes = []
モデルファイルがあれば読み込む。
if os.path.exists(args.model):
print("load the saved model")
agent.load_model(args.model)
for e in range(EPISODES):
print("Episode: ", e)
obs
← スタート時のカメラ画像
x_t
← obs
をモデルの入力形式に合わせて変換(グレースケール化&リサイズ)
s_t
← x_t
を4枚分コピー(入力画像は過去4枚分を使用するので)(ちゃんとimg_channels
参照して欲しいけど)
done = False
obs = env.reset()
episode_len = 0
x_t = agent.process_image(obs)
s_t = np.stack((x_t, x_t, x_t, x_t), axis=2)
# In Keras, need to reshape
s_t = s_t.reshape(1, s_t.shape[0], s_t.shape[1], s_t.shape[2]) # 1*80*80*4
終了フラグがセットされるまでループ
while not done:
steering
← 予測結果
env.step()
でシミュレータステップ実行
x_t1
←ステップ実行後のカメラ画像
s_t1
← 現在の入力データの一番古いものを削除し、今回の画像を追加
# Get action for the current state and go one step in environment
steering = agent.get_action(s_t)
action = [steering, throttle]
next_obs, reward, done, info = env.step(action)
x_t1 = agent.process_image(next_obs)
x_t1 = x_t1.reshape(1, x_t1.shape[0], x_t1.shape[1], 1) # 1x80x80x1
s_t1 = np.append(x_t1, s_t[:, :, :, :3], axis=3) # 1x80x80x4
ε値の更新も
# Save the sample <s, a, r, s'> to the replay memory
agent.replay_memory(s_t, np.argmax(linear_bin(steering)), reward, s_t1, done)
agent.update_epsilon()
if agent.train:
agent.train_replay()
s_t = s_t1
agent.t = agent.t + 1
episode_len = episode_len + 1
if agent.t % 30 == 0:
print(
"EPISODE",
e,
"TIMESTEP",
agent.t,
"/ ACTION",
action,
"/ REWARD",
reward,
"/ EPISODE LENGTH",
episode_len,
"/ Q_MAX ",
agent.max_Q,
)
agent.update_target_model()
でターゲットモデルの更新
episodes.append(e)
はデバッグ用?
if done:
# Every episode update the target model to be same with model
agent.update_target_model()
episodes.append(e)
# Save model for each episode
if agent.train:
agent.save_model(args.model)
print(
"episode:",
e,
" memory length:",
len(agent.memory),
" epsilon:",
agent.epsilon,
" episode length:",
episode_len,
)
キーボード割り込み例外と終了処理
except KeyboardInterrupt:
print("stopping run...")
finally:
env.unwrapped.close()
コマンドライン解析処理とメインルーチンへのジャンプ
if __name__ == "__main__":
# Initialize the donkey environment
# where env_name one of:
env_list = [
"donkey-warehouse-v0",
"donkey-generated-roads-v0",
"donkey-avc-sparkfun-v0",
"donkey-generated-track-v0",
"donkey-roboracingleague-track-v0",
"donkey-waveshare-v0",
"donkey-minimonaco-track-v0",
"donkey-warren-track-v0",
"donkey-thunderhill-track-v0",
"donkey-circuit-launch-track-v0",
]
parser = argparse.ArgumentParser(description="ddqn")
parser.add_argument(
"--sim",
type=str,
default="manual",
help="path to unity simulator. maybe be left at manual if you would like to start the sim on your own.",
)
parser.add_argument("--host", type=str, default="127.0.0.1", help="simulator address")
parser.add_argument("--model", type=str, default="rl_driver.h5", help="path to model")
parser.add_argument("--test", action="store_true", help="agent uses learned model to navigate env")
parser.add_argument("--port", type=int, default=9091, help="port to use for websockets")
parser.add_argument("--throttle", type=float, default=0.3, help="constant throttle for driving")
parser.add_argument(
"--env_name", type=str, default="donkey-warehouse-v0", help="name of donkey sim environment", choices=env_list
)
parser.add_argument("--epsilon", type=float, default=0.0, help="initial epsilon value")
args = parser.parse_args()
run_ddqn(args)
シミュレータに表示される車を変更してるのはご愛敬😅
--- ddqn.py.old 2021-12-02 06:25:02.149997073 +0900
+++ ddqn.py 2021-12-03 07:14:49.346378878 +0900
@@ -98,9 +98,10 @@
return np.dot(rgb[..., :3], [0.299, 0.587, 0.114])
def process_image(self, obs):
- obs = self.rgb2gray(obs)
- obs = cv2.resize(obs, (img_rows, img_cols))
- return obs
+ # obs1 = self.rgb2gray(obs)
+ obs1 = cv2.dst = cv2.cvtColor(obs, cv2.COLOR_RGB2GRAY)
+ obs2 = cv2.resize(obs1, (img_rows, img_cols))
+ return obs2
def update_target_model(self):
self.target_model.set_weights(self.model.get_weights())
@@ -108,13 +109,17 @@
# Get action from model using epsilon-greedy policy
def get_action(self, s_t):
if np.random.rand() <= self.epsilon:
- return self.action_space.sample()[0]
+ return self.action_space.sample()[0], 0
else:
# print("Return Max Q Prediction")
q_value = self.model.predict(s_t)
+ max_q = np.amax(q_value[0])
+ if self.max_Q < max_q :
+ self.max_Q = max_q
+
# Convert q array to steering value
- return linear_unbin(q_value[0])
+ return linear_unbin(q_value[0]), max_q
def replay_memory(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))
@@ -136,16 +141,16 @@
state_t, action_t, reward_t, state_t1, terminal = zip(*minibatch)
state_t = np.concatenate(state_t)
state_t1 = np.concatenate(state_t1)
- targets = self.model.predict(state_t)
- self.max_Q = np.max(targets[0])
- target_val = self.model.predict(state_t1)
- target_val_ = self.target_model.predict(state_t1)
+
+ targets = np.zeros((batch_size, 15))
+ q_val = self.model.predict(state_t1)
+ target_q_val = self.target_model.predict(state_t1)
for i in range(batch_size):
if terminal[i]:
targets[i][action_t[i]] = reward_t[i]
else:
- a = np.argmax(target_val[i])
- targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_val_[i][a])
+ a = np.argmax(q_val[i])
+ targets[i][action_t[i]] = reward_t[i] + self.discount_factor * (target_q_val[i][a])
self.model.train_on_batch(state_t, targets)
@@ -213,8 +218,8 @@
"exe_path": args.sim,
"host": args.host,
"port": args.port,
- "body_style": "donkey",
- "body_rgb": (128, 128, 128),
+ "body_style": "f1",
+ "body_rgb": (255, 128, 128),
"car_name": "me",
"font_size": 100,
"racer_name": "DDQN",
@@ -273,7 +278,7 @@
while not done:
# Get action for the current state and go one step in environment
- steering = agent.get_action(s_t)
+ steering, max_Q = agent.get_action(s_t)
action = [steering, throttle]
next_obs, reward, done, info = env.step(action)
@@ -305,7 +310,7 @@
"/ EPISODE LENGTH",
episode_len,
"/ Q_MAX ",
- agent.max_Q,
+ max_Q,
)
if done: