前情提要:
取自:http://news.ifeng.com/a/20170515/51093579_0.shtml
值函數估計
離散狀態下可以用表格來表示值函數或策略;但進入連續狀態空間就要用一個函數的近似來表示,這個方法叫做值函數近似。
比如,我們可以用一個線性函數來表示,V值是表示狀態s下面的一個值,狀態s先有一個特征的向量φ(s),這個V值表達出來就是一個線性的參數乘以特征的內積。Q值里面有一個動作,假設這個動作是離散的,一種方式是把這個動作和狀態放在一起變成一個特征,另一種方法是給每一個動作單獨做一個模型。
但我們現在先不管那些問題,先看做了近似以后怎么來學?我們想知道的是,這里的Q值,是希望Q值近似以后,夠盡量逼近真實的Q值。如果已經知道真實的Q值,怎么逼近呢?最簡單的方法就是做一個最小二乘回歸。其中一種解法是求導。求導以后,導數表示為,真實的Q和估計的Q的差值,然后再乘對Q值模型的導。可以看到,導數表達的含義與之前的模特卡羅誤差、TD誤差是一致的,只不過更新的是參數w。把這種更新方式套進Q-learning里,其他地方都沒有變,只得到了用值函數逼近的Q-Learning方法。
用批量學習改進
還有一些改進的方式。比如說我們在訓練近似模型的時候,在一個樣本上訓練可能會不穩定,所以可以用Batch Models的方式,積累一批數據來訓練這個模型。
但是用值函數估計會有一個問題——這種方法可以收斂到最優策略,但前提必須是用表格的表達方式;如果用的是函數近似,則會出現策略退化,即對Q值估計越大,策略越差。
舉一個簡單的例子,現在有兩個狀態,一個是狀態1,一個是狀態2,狀態1的特征為2,狀態2的特征為1。我們設定獎賞,使得狀態2的最優V值比狀態1的要大。這時如果用一個線性函數來表示這個V,也就是用W乘以特征,這個特征只有一維,最優的這個V值2是比1大的,1的特征值要高一點,2的特征值要小一點,所以最優的W就應該是個負數,這樣會使得V(2)比V(1)大,因而能導出最優策略。
但是基於值函數的做法是要使得V值盡量靠近最優的V值,最優的V值又是正值,這樣會導致這個W一定是正的,無法得到最優的策略。這樣值函數估計得越准,策略越差的現象被稱為策略退化。
====================================================================
以上這個小例子已給出在一種模型情況下最優策略和值函數,具體參看如下:
https://www.cnblogs.com/devilmaycry812839668/p/10314049.html
超參數設置: gama折扣因子都為0.99 , 兩浮點數相同的判斷規格都為0.0001 。
可知, 在折扣因子 gama 設置為0.99的情況下, 狀態“1”的狀態值為66.65674655343062,
狀態“2”的狀態值為66.65674655343062 。
可以發現 真實的狀態值在計算后居然得出了 兩個狀態值相同的結果,這個和本文上面所引用到的內容貌似不符,個人觀點可能是因為這兩個狀態采取動作后所跳轉新狀態后得到的獎勵值過小,獎勵值差距也過小,所以經過多輪的迭代學習發現得出了兩個狀態相同的值函數的結果。
不過又研究一下發現好像也不是這個原因:
這里1狀態V值為x, 2狀態V值為y, 狀態1 采取最優動作后再次估計狀態值為 1.0/3*x + 2.0/3*(1+y)
狀態2 采取最優動作后再次估計狀態值也為 1.0/3*x + 2.0/3*(1+y)
最后狀態1和2再次更新得到的狀態值仍然相同為 67.32341322009728, 所以上部分所說的狀態2的值大於狀態1的值是錯誤的,這兩個狀態值本就應該相同。
============================================================
在動態規划問題中我們一般認為模型是已知的,也就是說我們知道agent執行某個動作后跳轉到哪個狀態的概率為多少,會獲得多少reward。
而在強化學習中我們一般認為模型是未知的,也就是說我們需要自己去構建一個算法去識別出在某一狀態時我們應該選擇什么樣的動作,即尋找策略。因此我們一般采用模擬采樣的方法,如:蒙特卡洛法,但是由於該方法采樣需要每一次都是完整的決策過程,然后對其過程中動作值進行更新,因此我們一般采用時序差分法,如:Q-Learning 和 Sarsa 。
本文內容:
1. 基於單個樣本的 值函數估計強化學習方法例子 (最小二乘估計)( Q-learning 和 Sarsa )
其中, Q-Learning 代碼如下:
#encoding:UTF-8 #!/usr/bin/env python3 import random #動作 actions=[0, 1] #狀態 states=[1, 2] #構建環境 s, a r s a def next_state_reward(state, action): alfa=random.random() if state==1: if action==0: if alfa<=1.0/3: new_state=1 reward=0 else: new_state=2 reward=1 else: if alfa>1.0/3: new_state=1 reward=0 else: new_state=2 reward=1 else: if action==0: if alfa<=1.0/3: new_state=1 reward=0 else: new_state=2 reward=1 else: if alfa>1.0/3: new_state=1 reward=0 else: new_state=2 reward=1 return new_state, reward import torch.nn as nn import torch.optim # 構建模型 # 最小二乘法 # 輸入狀態1維 輸出action_q值2維(兩個動作) model = nn.Sequential( nn.Linear(1, 2), ) #反傳優化器 optimizer = torch.optim.Adam(model.parameters()) epsilon=0.4 def act(model, state, act_type="greedy", epsilon=epsilon): if (act_type!="greedy") or (random.random() > epsilon): # 選最大的 q_value = model.forward(state) action = q_value.max(1)[1].item() else: # 隨便選 action = random.randrange(len(actions)) return action gama=0.99 learning_rate=0.1 def q_learning(): state=random.choice(states) # 單個狀態變為序列型數據 state=(state, ) state = torch.FloatTensor(state).unsqueeze(0) action=act(model, state, act_type="greedy") # q 值 qs = model(state) # 單個數據 位置為0 q_value = qs[0][action] # 下一狀態 和 獎勵 next_state, reward=next_state_reward(state, action) # 單個狀態變為序列型數據 next_state=(next_state, ) next_state = torch.FloatTensor(next_state).unsqueeze(0) # 選擇的下一動作 next_action=act(model, next_state, act_type="max") # q 值 next_q_value, _ = model(next_state).max(1) q_estimate = reward + gama*next_q_value td_error=q_estimate - q_value # 計算 MSE 損失 loss = td_error.pow(2).mean() # 根據損失改進網絡 optimizer.zero_grad() loss.backward() optimizer.step() if __name__=="__main__": for episode in range(10**5): q_learning() state=((0,), (1,)) state = torch.FloatTensor(state) #.unsqueeze(0) # q 值 qs = model(state) print(qs)
tensor([[1.1225, 1.0938],
[0.5891, 0.5746]], grad_fn=<AddmmBackward>)
得到的結果:
tensor
第一行是狀態1的Q值 :
action 1為 1.1225, action 2為1.0938,
第二行是狀態2的Q值 :
action 1為 0.5891, action 2為0.5746 。
============================================================
部分素材取自:
http://news.ifeng.com/a/20170515/51093579_0.shtml