使用 Carla 和 Python 的自动驾驶汽车第 4 部分 —— 强化学习Action
歡迎來(lái)到自動(dòng)駕駛汽車的第五部分,并與Carla、Python和TensorFlow加強(qiáng)學(xué)習(xí)。
現(xiàn)在我們已經(jīng)有了環(huán)境和代理,我們只需要添加更多的邏輯將它們連接在一起,這是我們接下來(lái)要做的。
首先,我們將從強(qiáng)化學(xué)習(xí)教程中復(fù)制粘貼修改后的張量板類:
from keras.callbacks import TensorBoard ... # Own Tensorboard class class ModifiedTensorBoard(TensorBoard):# Overriding init to set initial step and writer (we want one log file for all .fit() calls)def __init__(self, **kwargs):super().__init__(**kwargs)self.step = 1self.writer = tf.summary.FileWriter(self.log_dir)# Overriding this method to stop creating default log writerdef set_model(self, model):pass# Overrided, saves logs with our step number# (otherwise every .fit() will start writing from 0th step)def on_epoch_end(self, epoch, logs=None):self.update_stats(**logs)# Overrided# We train for one batch only, no need to save anything at epoch enddef on_batch_end(self, batch, logs=None):pass# Overrided, so won't close writerdef on_train_end(self, _):pass# Custom method for saving own metrics# Creates writer, writes custom metrics and closes writerdef update_stats(self, **stats):self._write_logs(stats, self.step)提醒一下,上面的代碼只是為了簡(jiǎn)化TensorFlow/TensorBoard所做的日志量。通常,每個(gè)配置都有一個(gè)日志文件,每個(gè)步驟都有一個(gè)數(shù)據(jù)點(diǎn),這很快就變得非?;闹?#xff0c;隨著強(qiáng)化學(xué)習(xí)(在哪里適合每個(gè)步驟!)
讓我們添加以下導(dǎo)入:
import tensorflow as tf import keras.backend.tensorflow_backend as backend from threading import Thread在那之后,我們將去我們的腳本底部和:
if __name__ == '__main__':FPS = 60# For statsep_rewards = [-200]# For more repetitive resultsrandom.seed(1)np.random.seed(1)tf.set_random_seed(1)# Memory fraction, used mostly when trai8ning multiple agentsgpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=MEMORY_FRACTION)backend.set_session(tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)))# Create models folderif not os.path.isdir('models'):os.makedirs('models')# Create agent and environmentagent = DQNAgent()env = CarEnv()首先,我們?cè)O(shè)置一些FPS值(每秒幀數(shù))。當(dāng)我們開(kāi)始的時(shí)候,我們會(huì)有很高的,這意味著我們很有可能隨機(jī)選擇一個(gè)行動(dòng),而不是用我們的神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)它。隨機(jī)選擇要比預(yù)測(cè)操作快得多,所以我們可以通過(guò)設(shè)置某種一般FPS來(lái)任意延遲這一過(guò)程。當(dāng)epsilon為0時(shí),你應(yīng)該將其設(shè)置為你實(shí)際的FPS。我們將為可重復(fù)的結(jié)果設(shè)置隨機(jī)種子,然后指定GPU內(nèi)存比例。您可能不需要這樣做,但我的RTX Titan似乎有問(wèn)題,至少在Windows上,當(dāng)它試圖分配盡可能多的內(nèi)存時(shí),運(yùn)行耗盡。
接下來(lái),我們將創(chuàng)建模型目錄(如果它還不存在的話),這就是我們的模型的位置。然后創(chuàng)建代理和環(huán)境類。
# Start training thread and wait for training to be initializedtrainer_thread = Thread(target=agent.train_in_loop, daemon=True)trainer_thread.start()while not agent.training_initialized:time.sleep(0.01)開(kāi)始訓(xùn)練線程,并等待訓(xùn)練被初始化,正如評(píng)論所說(shuō)的!
# Initialize predictions - forst prediction takes longer as of initialization that has to be done# It's better to do a first prediction then before we start iterating over episode stepsagent.get_qs(np.ones((env.im_height, env.im_width, 3)))現(xiàn)在,我們準(zhǔn)備開(kāi)始迭代,不管我們?cè)O(shè)置了多少集:
# Iterate over episodesfor episode in tqdm(range(1, EPISODES + 1), ascii=True, unit='episodes'):#try:env.collision_hist = []# Update tensorboard step every episodeagent.tensorboard.step = episode# Restarting episode - reset episode reward and step numberepisode_reward = 0step = 1# Reset environment and get initial statecurrent_state = env.reset()# Reset flag and start iterating until episode endsdone = Falseepisode_start = time.time()我們的環(huán)境的一些初始值,現(xiàn)在我們可以運(yùn)行了。基本上,一個(gè)環(huán)境會(huì)一直運(yùn)行直到它完成,所以我們可以使用一個(gè)While True循環(huán)并在我們的done標(biāo)志上中斷。
在游戲過(guò)程中,我們要么采取隨機(jī)行動(dòng),要么根據(jù)代理模型確定當(dāng)前行動(dòng):
# Play for given number of seconds onlywhile True:# This part stays mostly the same, the change is to query a model for Q valuesif np.random.random() > epsilon:# Get action from Q tableaction = np.argmax(agent.get_qs(current_state))else:# Get random actionaction = np.random.randint(0, 3)# This takes no time, so we add a delay matching 60 FPS (prediction above takes longer)time.sleep(1/FPS)現(xiàn)在,我們將從環(huán)境的.step()方法中獲取信息,該方法將我們的action作為參數(shù):
new_state, reward, done, _ = env.step(action)# Transform new continous state to new discrete state and count rewardepisode_reward += reward# Every step we update replay memoryagent.update_replay_memory((current_state, action, reward, new_state, done))current_state = new_statestep += 1if done:break一旦我們完成了,我們需要做什么?首先,我們需要擺脫演員:
# End of episode - destroy agentsfor actor in env.actor_list:actor.destroy()現(xiàn)在,對(duì)于一些具有良好獎(jiǎng)勵(lì)的統(tǒng)計(jì)數(shù)據(jù)+保存模型(或任何其他你決定設(shè)置為if語(yǔ)句的規(guī)則):
# Append episode reward to a list and log stats (every given number of episodes)ep_rewards.append(episode_reward)if not episode % AGGREGATE_STATS_EVERY or episode == 1:average_reward = sum(ep_rewards[-AGGREGATE_STATS_EVERY:])/len(ep_rewards[-AGGREGATE_STATS_EVERY:])min_reward = min(ep_rewards[-AGGREGATE_STATS_EVERY:])max_reward = max(ep_rewards[-AGGREGATE_STATS_EVERY:])agent.tensorboard.update_stats(reward_avg=average_reward, reward_min=min_reward, reward_max=max_reward, epsilon=epsilon)# Save model, but only when min reward is greater or equal a set valueif min_reward >= MIN_REWARD:agent.model.save(f'models/{MODEL_NAME}__{max_reward:_>7.2f}max_{average_reward:_>7.2f}avg_{min_reward:_>7.2f}min__{int(time.time())}.model')接下來(lái)讓epsilon衰減:
# Decay epsilonif epsilon > MIN_EPSILON:epsilon *= EPSILON_DECAYepsilon = max(MIN_EPSILON, epsilon)最后,如果我們已經(jīng)迭代了所有的目標(biāo)章節(jié),我們就可以退出了:
# Set termination flag for training thread and wait for it to finishagent.terminate = Truetrainer_thread.join()agent.model.save(f'models/{MODEL_NAME}__{max_reward:_>7.2f}max_{average_reward:_>7.2f}avg_{min_reward:_>7.2f}min__{int(time.time())}.model')讓我們繼續(xù)播放它,它將播放100集。在泰坦RTX上100集需要17分鐘。
你應(yīng)該有一些日志文件,我們來(lái)看看。
tensorboard --logdir=logs/根據(jù)您的操作系統(tǒng),您需要導(dǎo)航到的內(nèi)容可能會(huì)有所不同。在linux上,無(wú)論它告訴您什么(應(yīng)該在控制臺(tái)輸出中給您一個(gè)URL)都應(yīng)該足夠了,可能127.0.0.1:6006也可以工作。在windows上,我發(fā)現(xiàn)唯一適合我的是localhost:6006。無(wú)論你做什么都要去那里!無(wú)論如何,一旦那里,我們可以搜索匹配以下正則表達(dá)式的標(biāo)簽:\w(任何字母),并看到所有的圖形在一起。對(duì)我來(lái)說(shuō),我有:
所以,不足為奇的是,我們并沒(méi)有在100集節(jié)目中突然學(xué)會(huì)如何成為一名出色的司機(jī)(從我們的平均回報(bào)來(lái)看),所以我們可能應(yīng)該取消那些投資會(huì)議,以推介下一家價(jià)值數(shù)十億美元的自動(dòng)駕駛汽車初創(chuàng)公司。
我忘記添加模型了。保存到我第一次測(cè)試時(shí)的代碼中,所以我最終再次運(yùn)行。這一次,我得到了更好看的結(jié)果。主要注意損失是如何從爆炸中恢復(fù)過(guò)來(lái)的。
現(xiàn)在,我們只拍了100集。我想我們需要10萬(wàn)集才能看到像樣的東西,前提是我們的其他問(wèn)題也都解決了。也就是說(shuō),“看到”您實(shí)際的代理運(yùn)行是有幫助的。所以這里有一個(gè)快速的腳本,只是播放和看到你的模型在行動(dòng):
將導(dǎo)入tutorial5_code重命名為RL代理/env/培訓(xùn)器腳本,然后修改MODEL_PATH = 'models/Xception__-118.00max_-179.10avg_-250.00min__1566603992。你使用的模型,因?yàn)槟愕哪P兔麑⑴c我的不同。
我需要再次強(qiáng)調(diào),這只是100集。但是,我們可以看到代理只學(xué)會(huì)了做一件事。Agent可能只學(xué)習(xí)做一件事,因?yàn)槟愕腝值實(shí)際上是靜態(tài)的(模型輸出相同的Q值,不管輸入),或者,就像我們的例子,它們都是變化的,只是右轉(zhuǎn)總是更高。
我在這里看到的另一件事是,有時(shí)左轉(zhuǎn)比直轉(zhuǎn)高,有時(shí)直轉(zhuǎn)比左轉(zhuǎn)高。所以還是有希望的。我在《俠盜獵車手5》系列的自動(dòng)駕駛汽車中學(xué)到的一件事是,你可以添加一個(gè)輸出層權(quán)重。
例如,在play腳本中,你可以這樣修改qs:
qs = model.predict(np.array(current_state).reshape(-1, *current_state.shape)/255)[0]qs *= [0.975, 1, 0.92]action = np.argmax(qs)這是網(wǎng)絡(luò)的最后一層。再說(shuō)一遍,這對(duì)100集的模型沒(méi)有幫助。我們發(fā)現(xiàn)的下一件事是,保持獎(jiǎng)勵(lì)為-1和正1可能會(huì)更好。沒(méi)有更多的-200。我們發(fā)現(xiàn)這可能會(huì)破壞Q值,而這似乎會(huì)破壞損失并導(dǎo)致混亂。我們甚至可以做進(jìn)一步的剪輯。
我們所做的下一個(gè)改變是將我們的神經(jīng)網(wǎng)絡(luò)簡(jiǎn)化為一個(gè)2-3層的CNN,每個(gè)CNN有64-256個(gè)功能。還不確定,但越簡(jiǎn)單越好,需要學(xué)習(xí)的參數(shù)越少。對(duì)于完全監(jiān)督學(xué)習(xí),我認(rèn)為更多的參數(shù)更有效,因?yàn)橐磺卸际恰盎臼聦?shí)”。對(duì)于強(qiáng)化學(xué)習(xí),我認(rèn)為對(duì)于人工智能來(lái)說(shuō),要想讓自己從愚蠢的洞穴中解脫出來(lái)太難了,因?yàn)樗婚_(kāi)始要嘗試訓(xùn)練成千上萬(wàn)的重量。
無(wú)論如何,這就是本教程的全部?jī)?nèi)容。在下一篇教程中,我將為您帶來(lái)一個(gè)工作模型,并告訴您我是如何做到的。
總結(jié)
以上是生活随笔為你收集整理的使用 Carla 和 Python 的自动驾驶汽车第 4 部分 —— 强化学习Action的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用 Carla 和 Python 的自
- 下一篇: 2019年第十届蓝桥杯 - 省赛 - C