利用PyTorch實(shí)現(xiàn)爬山算法
0. 前言
在隨機(jī)搜索策略中,每個(gè)回合都是獨(dú)立的。因此,隨機(jī)搜索中的所有回合都可以并行運(yùn)行,最終選擇能夠得到最佳性能的權(quán)重。我們還通過繪制總獎(jiǎng)勵(lì)隨回合增加的變化情況進(jìn)行驗(yàn)證,可以看到獎(jiǎng)勵(lì)并沒有上升的趨勢(shì)。在本節(jié)中,我們將實(shí)現(xiàn)爬山算法 (hill-climbing algorithm),以將在一個(gè)回合中學(xué)習(xí)到的知識(shí)轉(zhuǎn)移到下一個(gè)回合中。
1. 使用 PyTorch 實(shí)現(xiàn)爬山算法
1.1 爬山算法簡介
在爬山算法中,我們同樣從隨機(jī)選擇的權(quán)重開始。但是,對(duì)于每個(gè)回合,我們都會(huì)為權(quán)重添加一些噪聲數(shù)據(jù)。如果總獎(jiǎng)勵(lì)有所改善,我們將使用新的權(quán)重來更新原權(quán)重;否則,將保持原權(quán)重。通過這種方法,隨著回合的增加,權(quán)重也會(huì)逐步修改,而不是在每個(gè)回合中隨機(jī)改變。
1.2 使用爬山算法進(jìn)行 CartPole 游戲
接下來,我們使用 PyTorch 實(shí)現(xiàn)爬山算法。首先,導(dǎo)入所需的包,創(chuàng)建一個(gè) CartPole 環(huán)境實(shí)例,并計(jì)算狀態(tài)空間和動(dòng)作空間的尺寸。重用 run_episode 函數(shù),其會(huì)根據(jù)給定權(quán)重,模擬一個(gè)回合后返回總獎(jiǎng)勵(lì):
import gym
import torch
from matplotlib import pyplot as plt
env = gym.make('CartPole-v0')
n_state = env.observation_space.shape[0]
print(n_state)
n_action = env.action_space.n
print(n_action)
def run_episode(env, weight):
state = env.reset()
total_reward = 0
is_done = False
while not is_done:
state = torch.from_numpy(state).float()
action = torch.argmax(torch.matmul(state, weight))
state, reward, is_done, _ = env.step(action.item())
total_reward += reward
return total_reward模擬 1000 個(gè)回合,并初始化變量用于跟蹤最佳的總獎(jiǎng)勵(lì)以及相應(yīng)的權(quán)重。同時(shí),初始化一個(gè)空列表用于記錄每個(gè)回合的總獎(jiǎng)勵(lì):
n_episode = 1000 best_total_reward = 0 best_weight = torch.randn(n_state, n_action) total_rewards = []
正如以上所述,我們?cè)诿總€(gè)回合中為權(quán)重添加一些噪音,為了使噪聲不會(huì)覆蓋原權(quán)重,我們還將對(duì)噪聲進(jìn)行縮放,使用 0.01 作為噪聲縮放因子:
noise_scale = 0.01
然后,就可以運(yùn)行 run_episode 函數(shù)進(jìn)行模擬。
隨機(jī)選擇初始權(quán)重之后,在每個(gè)回合中執(zhí)行以下操作:
- 為權(quán)重增加隨機(jī)噪音
- 智能體根據(jù)線性映射采取動(dòng)作
- 回合終止并返回總獎(jiǎng)勵(lì)
- 如果當(dāng)前獎(jiǎng)勵(lì)大于到目前為止獲得的最佳獎(jiǎng)勵(lì),更新最佳獎(jiǎng)勵(lì)和權(quán)重;否則,最佳獎(jiǎng)勵(lì)和權(quán)重將保持不變
- 記錄每回合的總獎(jiǎng)勵(lì)
for e in range(n_episode):
weight = best_weight + noise_scale * torch.rand(n_state, n_action)
total_reward = run_episode(env, weight)
if total_reward >= best_total_reward:
best_total_reward = total_reward
best_weight = weight
total_rewards.append(total_reward)
print('Episode {}: {}'.format(e + 1, total_reward))計(jì)算使用爬山算法所獲得的平均總獎(jiǎng)勵(lì):
print('Average total reward over {} episode: {}'.format(n_episode, sum(total_rewards) / n_episode))
# Average total reward over 1000 episode: 62.4212. 改進(jìn)爬山算法
為了評(píng)估使用爬山算法的訓(xùn)練效果,多次重復(fù)訓(xùn)練過程,使用循環(huán)語句多次執(zhí)行爬山算法,可以觀察到平均總獎(jiǎng)勵(lì)的波動(dòng)變化較大:
for i in range(10):
best_total_reward = 0
best_weight = torch.randn(n_state, n_action)
total_rewards = []
for e in range(n_episode):
weight = best_weight + noise_scale * torch.rand(n_state, n_action)
total_reward = run_episode(env, weight)
if total_reward >= best_total_reward:
best_total_reward = total_reward
best_weight = weight
total_rewards.append(total_reward)
# print('Episode {}: {}'.format(e + 1, total_reward))
print('Average total reward over {} episode: {}'.format(n_episode, sum(total_rewards) / n_episode))以下是我們運(yùn)行10次后得到的結(jié)果:
Average total reward over 1000 episode: 200.0
Average total reward over 1000 episode: 9.846
Average total reward over 1000 episode: 82.1
Average total reward over 1000 episode: 9.198
Average total reward over 1000 episode: 9.491
Average total reward over 1000 episode: 9.073
Average total reward over 1000 episode: 149.421
Average total reward over 1000 episode: 49.584
Average total reward over 1000 episode: 8.827
Average total reward over 1000 episode: 9.369
產(chǎn)生如此差異的原因是什么呢?如果初始權(quán)重較差,則添加的少量噪聲只會(huì)小范圍改變權(quán)重,且對(duì)改善性能幾乎沒有影響,導(dǎo)致算法收斂性能不佳。另一方面,如果初始權(quán)重較為合適,則添加大量噪聲可能會(huì)大幅度改變權(quán)重,使得權(quán)重偏離最佳權(quán)重并破壞算法性能。為了使爬山算法的訓(xùn)練更穩(wěn)定,我們可以使用自適應(yīng)噪聲縮放因子,類似于梯度下降中的自適應(yīng)學(xué)習(xí)率,隨著模型性能的提升改變?cè)肼暱s放因子的大小。
為了使噪聲具有自適應(yīng)性,執(zhí)行以下操作:
- 指定初始噪聲縮放因子
- 如果回合中的模型性能有所改善,則減小噪聲縮放因子,本節(jié)中,每次將噪聲縮放因子減小為原來的一半,同時(shí)設(shè)置縮放因子最小值為
0.0001 - 而如果回合中中的模型性能下降,則增大噪聲縮放因子,本節(jié)中,每次將噪聲縮放因子增大為原來的
2倍,同時(shí)設(shè)置縮放因子最大值為2
noise_scale = 0.01
best_total_reward = 0
best_weight = torch.randn(n_state, n_action)
total_rewards = []
for e in range(n_episode):
weight = best_weight + noise_scale * torch.rand(n_state, n_action)
total_reward = run_episode(env, weight)
if total_reward >= best_total_reward:
best_total_reward = total_reward
best_weight = weight
noise_scale = max(noise_scale/2, 1e-4)
else:
noise_scale = min(noise_scale*2, 2)
total_rewards.append(total_reward)
print('Episode {}: {}'.format(e + 1, total_reward))可以看到,獎(jiǎng)勵(lì)隨著回合的增加而增加。訓(xùn)練過程中,當(dāng)一個(gè)回合中可以運(yùn)行 200 個(gè)步驟時(shí),模型的性能可以得到保持,平均總獎(jiǎng)勵(lì)也得到了極大的提升:
print('Average total reward over {} episode: {}'.format(n_episode, sum(total_rewards) / n_episode))
# Average total reward over 1000 episode: 196.28接下來,為了更加直觀的觀察,我們繪制每個(gè)回合的總獎(jiǎng)勵(lì)的變化情況,如下所示,可以看到總獎(jiǎng)勵(lì)有明顯的上升趨勢(shì),然后穩(wěn)定在最大值處:
plt.plot(total_rewards, label='search')
plt.xlabel('episode')
plt.ylabel('total_reward')
plt.legend()
plt.show()
多次運(yùn)行訓(xùn)練過程過程,可以發(fā)現(xiàn)與采用恒定噪聲縮放因子進(jìn)行學(xué)習(xí)相比,自適應(yīng)噪聲縮放因子可以得到穩(wěn)定的訓(xùn)練結(jié)果。
接下來,我們測(cè)試所得到的模型策略在 1000 個(gè)新回合中的性能表現(xiàn):
n_episode_eval = 1000
total_rewards_eval = []
for episode in range(n_episode_eval):
total_reward = run_episode(env, best_weight)
print('Episode {}: {}'.format(episode+1, total_reward))
total_rewards_eval.append(total_reward)
print('Average total reward over {} episode: {}'.format(n_episode_eval, sum(total_rewards_eval)/n_episode_eval))
# Average total reward over 1000 episode: 199.98可以看到在測(cè)試階段的平均總獎(jiǎng)勵(lì)接近 200,即 CartPole 環(huán)境中可以獲得的最高獎(jiǎng)勵(lì)。通過多次運(yùn)行評(píng)估,可以獲得非常一致的結(jié)果。
到此這篇關(guān)于利用PyTorch實(shí)現(xiàn)爬山算法的文章就介紹到這了,更多相關(guān)PyTorch爬山算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Ubuntu 16.04 LTS中源碼安裝Python 3.6.0的方法教程
最近Python 3發(fā)布了新版本Python 3.6.0,好像又加入了不少黑魔法!由于暫時(shí)不能使用 apt-get 的方式安裝 Python 3.6,所以還是直接編譯源碼安裝吧。下面這篇文章就介紹了在Ubuntu 16.04 LTS中源碼安裝Python 3.6.0的方法教程,需要的朋友可以參考下。2016-12-12
OpenCV凸包檢測(cè)和凸缺陷學(xué)習(xí)示例
這篇文章主要為大家介紹了OpenCV凸包檢測(cè)和凸缺陷學(xué)習(xí)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Pyspark 線性回歸梯度下降交叉驗(yàn)證知識(shí)點(diǎn)詳解
在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于Pyspark 線性回歸梯度下降交叉驗(yàn)證的相關(guān)知識(shí)點(diǎn)及實(shí)例,需要的朋友們可以參考下。2021-12-12
NCCL深度學(xué)習(xí)之初始化及ncclUniqueId的產(chǎn)生源碼解析
這篇文章主要為大家介紹了NCCL源碼解析之初始化及ncclUniqueId的產(chǎn)生詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
全面了解Python的getattr(),setattr(),delattr(),hasattr()
下面小編就為大家?guī)硪黄媪私釶ython的getattr(),setattr(),delattr(),hasattr()。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06
windows下python安裝paramiko模塊和pycrypto模塊(簡單三步)
這篇文章主要給大家介紹了通過簡單的三個(gè)步驟在windows下python中安裝paramiko模塊和pycrypto模塊的相關(guān)資料,文中安裝的步驟,簡單而且又易于大家理解,需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。2017-07-07
Django如何使用asyncio協(xié)程和ThreadPoolExecutor多線程
這篇文章主要介紹了Django如何使用asyncio協(xié)程和ThreadPoolExecutor多線程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

