Deep QLearning算法详解(强化学习 Reinforcement Learning)
一、算法詳解
文章最后附有博主自己實現的深度qlearning玩space invader游戲
本文介紹的是基于神經網絡的qlearning算法。我們知道傳統的qlearning算法只能處理狀態和動作有限的情況,對于無窮多,則是無法有效處理的。現實生活中,環境的狀態肯定是無窮多的,而神經網絡正好可以處理這樣的情況。這里深度qlearning算法使用一個神經網絡來表示一個q表,無論環境的狀態有沒有出現過,我們都可以將狀態輸入到神經網絡,去評估價值函數。
1.1 幾個概念
1.1.1 什么是critic?
critic:批評家,評論家。
在這里算法要更新就是一個critic,而不是一個actor(agent),使用critic來間接指導actor做決策,critic的作用就是評估一個actor有多好,水平高不高。
1.1.2 狀態價值函數Vπ(s)V ^{\pi }(s)Vπ(s)和狀態動作價值函數Qπ(s,a)Q^{\pi }(s,a)Qπ(s,a),以及他們之間的關系
π\piπ表示一個actor,s是一個狀態,a是指actor看到狀態s時做出的動作
-
Vπ(s)V ^{\pi }(s)Vπ(s)指使用actor π\piπ時,當看到狀態s時,計算累計獎勵的期望值
舉個例子吧,不然有點難以理解,這里計算的依然是累計獎勵的期望值。我個人理解,如果要寫出具體 Vπ(s)V ^{\pi }(s)Vπ(s)公式的話,應該是這樣
Vπ(s)=∑τR(τ,s)p(τ)(1)V^{\pi}(s)=\sum_{\tau }R(\tau ,s)p(\tau)\tag{1}Vπ(s)=τ∑?R(τ,s)p(τ)(1)
公式解釋:R(τ,s)R(\tau ,s)R(τ,s)表示在一個eposide內,只計算s之后的所有累計獎勵的和。比如τ={s1,a1,r1,s2,a2,r2,...,sT,aT,rT,End}\tau =\{s_{1},a_{1},r_{1},s_{2},a_{2},r_{2},...,s_{T},a_{T},r_{T},End\}τ={s1?,a1?,r1?,s2?,a2?,r2?,...,sT?,aT?,rT?,End},我們計算R(τ,s2)R(\tau ,s_{2})R(τ,s2?),由上面的定義知道,R(τ,s2)=r2+...+rTR(\tau ,s_{2})=r_{2}+...+r_{T}R(τ,s2?)=r2?+...+rT?,這里沒有計算r1r_{1}r1?,只計算看到s2s_{2}s2?之后的所有獎勵。p(τ)p(\tau)p(τ)表示eposide τ\tauτ出現的概率。
舉一個sutton強化學習書上的例子。
例子1:
假設我們采樣得到8個eposides,分別如下:
1、sa,r=0,sb,r=0,Ends_{a},r=0,s_{b},r=0,Endsa?,r=0,sb?,r=0,End
2、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
3、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
4、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
5、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
6、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
7、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
8、sb,r=0,Ends_{b},r=0,Endsb?,r=0,End
這里給出了8個采樣得到的eposide,并且忽略所采取的動作,這里是采樣得到8個eposide來逼近Vπ(s)V^{\pi}(s)Vπ(s),選擇采樣來逼近Vπ(s)V^{\pi}(s)Vπ(s),是因為actor所處的環境和actor本身都具有隨機性,由上面的公式(1)可以看到,如果所有的eposides有無窮多個,那么計算機根本無法實現計算Vπ(s)V^{\pi}(s)Vπ(s)
根據上面的8個eposides,可以計算得到:
Vπ(sb)=1+1+1+1+1+18=34V^{\pi}(s_{b})=\frac{1+1+1+1+1+1}{8}=\frac{3}{4}Vπ(sb?)=81+1+1+1+1+1?=43?
只有在第二到第七個eposide時,遇到狀態sbs_{b}sb?才有獎勵,第一個eposide中,當遇到狀態sbs_{b}sb?時,所有累積的獎勵值是0。第8個eposide也是如此。就算第一個eposide變成sa,r=1,sb,r=0,Ends_{a},r=1,s_{b},r=0,Endsa?,r=1,sb?,r=0,End,Vπ(s)V^{\pi}(s)Vπ(s)依然不變還是34\frac{3}{4}43?. -
Qπ(s,a)Q^{\pi }(s,a)Qπ(s,a)指actor看到狀態sss之后確定選擇動作aaa之后的獎勵累積期望
為什么說確定選擇動作aaa呢?看到狀態sss,其實有很多個動作可以選擇,但是在這里就是確定選擇動作aaa,而不是別的動作。還有一個因素就是選擇動作的時候具有隨機性,比如采用ε?greedy\varepsilon -greedyε?greedy方法,會有一定的幾率隨機選擇動作。 -
兩者之間的關系
假設有...,st,at,rt,st+1,......,s_{t},a_{t},r_{t},s_{t+1},......,st?,at?,rt?,st+1?,...,那么就有Qπ(st,at)=E(rt+Vπ(st+1))Q^{\pi }(s_{t},a_{t})=E(r_{t}+V ^{\pi }(s_{t+1}))Qπ(st?,at?)=E(rt?+Vπ(st+1?))
這里還是要求期望的。不過在實際操作的時候需要采樣或者直接把變成Qπ(st,at)=rt+Vπ(st+1)Q^{\pi }(s_{t},a_{t})=r_{t}+V ^{\pi }(s_{t+1})Qπ(st?,at?)=rt?+Vπ(st+1?)。這種情況就是只采樣一個用來逼近期望。這樣網絡收斂的效果可能不是太好,畢竟用一條樣本來逼近還是效果不大好的。
1.1.3 如何計算Vπ(s)V ^{\pi }(s)Vπ(s)?
-
Monte-Carlo(MC)方法
如下圖,我們使用一個神經網絡來計算Vπ(s)V ^{\pi }(s)Vπ(s),并且根據actor玩游戲的實際情況,來優化這個神經網絡,并且利用這個神經網絡(q表,我們前面說到了使用神經網絡來表示這個q表以處理狀態極其復雜多變的情況,所以神經網絡==q表)來指導actor進行決策。
例子:假設有狀態 sa和sbs_{a}和 s_{b}sa?和sb?,計算Vπ(sa)和Vπ(sb)V ^{\pi }(s_{a})和V ^{\pi }(s_{b})Vπ(sa?)和Vπ(sb?)的步驟如下:
對于Vπ(sa)V ^{\pi }(s_{a})Vπ(sa?):
(1) actor(agent)玩游戲或者和環境互動.
(2) 狀態 sas_{a}sa? 出現在某個回合(episode)中.
(3) 僅記錄從狀態 sas_{a}sa? 出現到這個回合結束后的累積的獎勵,我們將其記為GaG_{a}Ga?.
(4) 將狀態sas_{a}sa?輸入到神經網絡然后輸出 Vπ(sa)V ^{\pi }(s_{a})Vπ(sa?),這個神經網絡輸出的是個標量.
(5) 利用 回歸(regression) 的方法來優化神經網絡,使得神經網絡的輸出的Vπ(sa)V ^{\pi }(s_{a})Vπ(sa?)來逼近GaG_{a}Ga?.
(6) 對于任何一個狀態都可以重復以上過程,直到神經網絡收斂。
對于Vπ(sb)V ^{\pi }(s_{b})Vπ(sb?)的計算也是如此。 -
Temporal-Difference-Approach(時間差分方法)
時間差分方法,顧名思義,肯定是需要兩個連續時間步上的狀態才能達到訓練神經網絡的目的。
假設actor玩游戲或者與環境互動的一個episode中的連續兩步是...,st,at,rt,st+1,......,s_{t},a_{t},r_{t},s_{t+1},......,st?,at?,rt?,st+1?,...
首先,Vπ(st)=rt+Vπ(st+1)(2)V^{\pi }(s_{t})=r_{t}+V^{\pi }(s_{t+1})\tag{2}Vπ(st?)=rt?+Vπ(st+1?)(2)
π{\pi}π表示agent或者actor。
時間差分方法每連續的兩個時間步都會訓練一次神經網絡,因此收斂的速度也會相對來說較快。步驟如下
(1) 假設在時間步 ttt 觀測到狀態 sts_{t}st?
(2) actor根據現在的狀態 sts_{t}st? 做出動作 ata_{t}at? ,得到獎勵 rtr_{t}rt?
(3) actor觀測到下一個時間步 t+1t+1t+1 的狀態 st+1s_{t+1}st+1?
(4) 將狀態 sts_{t}st?, st+1s_{t+1}st+1? 輸入進神經網絡得到 Vπ(st)V^{\pi }(s_{t})Vπ(st?) 和 Vπ(st+1)V^{\pi }(s_{t+1})Vπ(st+1?)
(5) 利用公式2,我們將Vπ(st)V^{\pi }(s_{t})Vπ(st?) 和 Vπ(st+1)V^{\pi }(s_{t+1})Vπ(st+1?)的差值逼近時間步的獎勵 rtr_{t}rt?. 還是利用回歸(Regression)的方法來訓練神經網絡。
圖片來自李宏毅老師的強化學習課程,侵刪!!! -
兩種方法之間的關系
蒙特卡洛方法有更大的方差,方差大說明效果不好,相比來說時間差分方法的訓練速度更加高效,收斂的更快,時間差分方法只需要使用兩個時間步的信息就可以訓練網絡,而蒙特卡洛方法卻需要等待一個完整的episode完成之后才可以進行訓練。不知道大家發現沒有,突然覺得這個方法也是有點類似監督學習方法,這個深度qlearning算法里面的“監督信息是環境反饋過來的獎勵”,我們需要使用獎勵來指引actor的學習。
對于同一個采樣出來的樣本,使用兩種方法計算出來的同一個狀態 sas_{a}sa? 的價值函數是不一樣的
比如下面的例子:
假設我們采樣得到8個eposides,分別如下:
1、sa,r=0,sb,r=0,Ends_{a},r=0,s_{b},r=0,Endsa?,r=0,sb?,r=0,End
2、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
3、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
4、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
5、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
6、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
7、sb,r=1,Ends_{b},r=1,Endsb?,r=1,End
8、sb,r=0,Ends_{b},r=0,Endsb?,r=0,End
我們先使用蒙特卡洛方法計算 Vπ(sa)V^{\pi}(s_{a})Vπ(sa?):
觀察采樣出來的數據,我們可以看到狀態 sas_{a}sa? 只是出現在 第一條樣本里面,而且直到游戲結束,得到的兩個獎勵值都是0,所以 Ga=0G_{a}=0Ga?=0,因為我們需要讓 Vπ(sa)V^{\pi}(s_{a})Vπ(sa?) 逼近 GaG_{a}Ga?,所以理想情況下有Vπ(sa)=0V^{\pi}(s_{a})=0Vπ(sa?)=0.
接著使用時間差分方法來計算Vπ(sa)V^{\pi}(s_{a})Vπ(sa?):
從第一條采樣樣本可以看到狀態 sas_{a}sa? 和 sbs_{b}sb? 是兩個相鄰的狀態,因此由公式2可以知道計算 Vπ(sa)V^{\pi}(s_{a})Vπ(sa?),需要使用 Vπ(sb)V^{\pi}(s_{b})Vπ(sb?)的值。
根據采樣的8條樣本,我們使用這八條樣本的 $V^{\pi}(s_{b})_{i},i=1,2,…,8的期望值來近似逼近 Vπ(sb)V^{\pi}(s_{b})Vπ(sb?)
因此有Vπ(sb)=1+1+1+1+1+18=34V^{\pi}(s_{b})=\frac{1+1+1+1+1+1}{8}=\frac{3}{4}Vπ(sb?)=81+1+1+1+1+1?=43?
由在第一條樣本中在狀態 sas_{a}sa? 時actor得到的獎勵是0,所以Vπ(sa)=0+Vπ(sb)=34V^{\pi }(s_{a})=0+V^{\pi }(s_{b})=\frac{3}{4}Vπ(sa?)=0+Vπ(sb?)=43?.
可以看到,不同的計算方法得到的價值函數的值是不一樣的。
二、算法運行流程
步驟一: actor(agent) π{\pi}π和環境(Environment)互動
步驟二: 使用蒙特卡洛方法或者時間差分方法來計算狀態價值函數Vπ(s)V^{\pi}(s)Vπ(s)或者狀態動作價值函數Qπ(s,a)Q^{\pi}(s,a)Qπ(s,a)
步驟三: 使用回歸(Regression)方法訓練神經網絡
步驟四: 價值函數指導actor做出更好的策略,循環以上步驟,直到收斂。
基于TD方法的QLearning具體如下圖:
算法流程里面的butter要改為buffer。
三、幾個小技巧
3.1 技巧1 target網絡和predict網絡
其實在傳統的qlearning里面以及涉及到了“q_target和q_predict”的概念了,這里的深度qlearning在訓練的時候同樣也是由target網絡和predict網絡,只不過是兩個網絡需要共享參數,其中target是固定的,只有在predict網絡以target的輸出為目標更新若干次之后采后將predict網絡的參數重新賦給target網絡。
有需要可以看看傳統的qlearning算法。傳送門:傳統qlearning算法講解
我們以李宏毅老師的課程講解如何訓練的
這里使用的是時間差分方法來訓練的
右邊的 Target 網絡的參數在一定時間內是固定的,Target網絡輸出的值是左邊網絡需要回歸的目標,然后更新這個來更新左邊的predict網絡,更新若干次之后,然后將predict網絡的參數重新賦給Target網絡,一直訓練,直到收斂。
3.2、技巧2之 ε?greedy\varepsilon -greedyε?greedy選擇動作
使用這個技巧有利于actor學會探索,也可以確保當訓練的次數足夠多時,所有的動作都可以被的更新到。隨機探索的可能性會隨著訓練的進行逐漸變小的
我們之前在強化學習(RL)QLearning算法詳解介紹過了這個技巧,不再重復。
3.3 技巧3 Boltzmann選擇動作
利用狀態動作價值函數的大小來選擇動作,值越大,這個對于的動作被選擇的概率就越大,對于的動作被選擇的概率公式如下:
P(a∣s)=exp(Q(s,a))∑aexp(Q(s,a))(3)P(a|s)=\frac{exp(Q(s,a))}{\sum_{a}exp(Q(s,a))}\tag{3}P(a∣s)=∑a?exp(Q(s,a))exp(Q(s,a))?(3)
3.4 技巧4 RePlay Buffer
設計一個Buffer將actor玩過的experience存儲起來,可以重復使用這個數據更新網絡。
假如使用時間差分方法,我們可以在Buffer存儲器里面存儲只需要兩個時間步就可以,比如其中一條數據可以是:st,at,rt,st+1s_{t},a_{t},r_{t},s_{t+1}st?,at?,rt?,st+1?,當儲存很多時,也可以進行batch學習。
四、小例子
基于卷積神經網絡的小例子
4.1 readme
- 安裝gym
- 安裝atari-py
在第二步很容易出現ale_c.dll不存在的問題。
以下是解決方法
分三步:
第一步:先卸載atari-py。pip uninstall atari-py
第二步:再重新安裝這個。pip install --no-index -f https://github.com/Kojoley/atari-py/releases atari_py
第三步:pip install gym
# -*- coding: utf-8 -*-import gym
import torch.nn as nn
import torch as t
from torch.nn import functional as F
import randomdicount_factor = 0.9
eplison = 0.1
lr = 0.001
epochs = 50
nums_p2t = 100 #每隔100詞將Q_Net_predict的參數賦給Q_Net_target,然后繼續固定target網絡
env = gym.make("SpaceInvaders-v0") # 構造一個太空入侵者的環境# 下面這個神經網絡是用來預測
class Q_Net_predict(nn.Module): def __init__(self, nums_action):super(Q_Net_predict,self).__init__()#下面開始定義卷積和全連接層,計劃使用兩個全連接層和兩個卷積層self.conv1 = nn.Conv2d(3, 16, 5, 2)self.conv2 = nn.Conv2d(16, 16, 5, 2)self.linear1 = nn.Linear(1728,256)self.linear2 = nn.Linear(256,nums_action)def forward(self, x):#先進行類型的轉換state = t.from_numpy(x[:,:,::-1].copy())state = state.permute((2,0,1)).unsqueeze(dim=0).float()#開始使用卷積,最大池化和線性層out = self.conv1(state)out = F.relu(out)out = F.max_pool2d(out,(2,2))out = self.conv2(out)out = F.relu(out)out = F.max_pool2d(out,(2,2))s = out.size()out = out.view(1,s[1]*s[2]*s[3])out = F.relu(self.linear1(out))out = self.linear2(out)return out# 下面這個神經網絡是用來作為Q_Net_predict擬合的目標函數
class Q_Net_target(nn.Module): def __init__(self, nums_action):super(Q_Net_target,self).__init__()#下面開始定義卷積和全連接層,計劃使用兩個全連接層和兩個卷積層self.conv1 = nn.Conv2d(3, 16, 5, 2)self.conv2 = nn.Conv2d(16, 16, 5, 2)self.linear1 = nn.Linear(1728,256)self.linear2 = nn.Linear(256,nums_action)def forward(self, x):#先進行類型的轉換state = t.from_numpy(x[:,:,::-1].copy())state = state.permute((2,0,1)).unsqueeze(dim=0).float()#開始使用卷積,最大池化和線性層out = self.conv1(state)out = F.relu(out)out = F.max_pool2d(out,(2,2))out = self.conv2(out)out = F.relu(out)out = F.max_pool2d(out,(2,2))s = out.size()out = out.view(1,s[1]*s[2]*s[3])out = F.relu(self.linear1(out))out = self.linear2(out)return outdef choose_action(logits):## 使用eplison-greedy選擇agent需要執行的動作v = random.uniform(0, 1)q_value, index = t.topk(logits, 1, dim = 1)#下面開始eplison-greedy 算法if v > eplison:#這里是求最大的狀態價值函數對應的動作q_value_t = logits[0,index[0][0]]action = index[0][0].item()else:#下面是隨機產生動作action = random.randint(0, 5)q_value_t = logits[0, action]return action, q_value_tdef q_learning():all_count = 0#下面開始#先定義兩個狀態價值函數網絡q_target = Q_Net_target(6)q_predict = Q_Net_predict(6)#定義一個優化器opt_Adam = t.optim.Adam(q_predict.parameters(),lr = lr)#將target網絡的參數凍結for p in q_target.parameters():p.requires_grad = Falsefor _ in range(epochs):done = False#初始化一個狀態observation = env.reset() #每個episode的初始狀態while not done:env.render()#下面開始網絡的參數復制if all_count % nums_p2t == 0:target_paras = q_target.state_dict()predict_paras = q_predict.state_dict()target_paras.update(predict_paras)q_target.load_state_dict(target_paras)#下面使用q_predict網絡的輸出選擇動作predict_logits = q_predict(observation)action, q_value_t = choose_action(logits= predict_logits)#下面根據動作得到獎勵以及下一個時間步的狀態observationobservation, reward, done, info = env.step(action)#現在有了observation,需要使用使用target網絡計算observation的狀態價值函數target_qvalue = q_target(observation)q_value_t_ = max(target_qvalue[0]).item()#我們需要使reward+q_value_t_ 和 q_value_t接近loss = (reward + q_value_t_ - q_value_t)**2loss.backward()opt_Adam.step()all_count +=1env.close()if __name__ == '__main__':q_learning()
五、參考文獻
1、李宏毅老師的強化學習算法
2、莫煩python的強化學習系列
3、ale_c.dll確實解決方法
4、openai官網
總結
以上是生活随笔為你收集整理的Deep QLearning算法详解(强化学习 Reinforcement Learning)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 西伯利亚(Siberia)冷空气
- 下一篇: 拳击体重级别划分