文章目錄
在本節中,我們將討論政策優化算法的數學基礎, 我們將介紹政策梯度理論中的三個關鍵結果:
- 關於策略參數的最簡單的等式描述策略表現的梯度,
- 一條規則,允許我們從該表達式中刪除無用的術語,
- 以及允許我們在該表達式中添加有用術語的規則。
最後,我們將這些結果結合在一起,並描述策略梯度的基於優勢的表達式,這是我們在Vanilla Policy Gradient實現中使用的版本。
Deriving the Simplest Policy Gradient
在這裏,我們考慮一種隨機的,參數化的策略,. 我們的目標是最大化期望收益 。 出於此推導的目的,我們將使用來給出有限步長的無折扣收益,此外無限步長的折現收益設置的推導幾乎是相同的。
我們想通過梯度上升來優化策略,例如:
策略的梯度稱爲策略梯度,以這種方式優化策略的算法稱爲策略梯度算法。 (示例包括Vanilla Policy Gradient和TRPO。PPO通常被稱爲策略梯度算法,儘管這有點不準確。)
要實際使用此算法,我們需要一個可以通過數值計算的策略梯度表達式。 這涉及兩個步驟:1)得出策略表現的分析梯度,結果證明是期望值的形式,然後2)構建該期望值的樣本估計值,可以使用代理與環境相互作用有限數量的數據來計算 。
在本小節中,我們將找到該表達式的最簡單形式。 在後面的小節中,我們將展示如何以最簡單的形式進行改進,以獲取我們在標準策略梯度實現中實際使用的版本。
我們將從列出一些對得出分析梯度有用的事實開始。
1.軌跡的概率 (Probability of a Trajectory)
給定動作來自的軌跡的概率爲:
2.對數導數技巧
對數導數技巧是基於微積分的簡單規則:相對於x的導數爲1 ⁄ x。 重新排列並與鏈式規則結合後,我們得到:
3.軌跡的對數概率
軌跡的對數概率就是:
4.環境函數的梯度
環境不依賴於,因此和的梯度爲零。
5.軌跡的梯度對數概率
因此,軌跡的對數概率的梯度爲
綜上所述,我們得出以下結論:
這是一個期望,這意味着我們可以使用樣本均值對其進行估計。 如果我們收集一組軌跡:`,其中通過使代理在環境中作用獲得每個軌跡 ,策略梯度可以使用以下作爲估計:
其中 是 中軌跡的個數(here, ).
最後一個表達式是我們想要的可計算表達式的最簡單版本。 假設我們以可計算出 的方式表示我們的策略,並且如果是在能夠收集軌跡數據集的環境中,我們可以計算策略梯度並採取更新步驟。
Implementing the Simplest Policy Gradient
我們在spinup / examples / pg_math / 1_simple_pg.py中給出了這個簡單版本的策略梯度算法的簡短Tensorflow實現。 (也可以在github https://github.com/openai/spinningup/blob/master/spinup/examples/pg_math/1_simple_pg.py __上查看)。它只有122行,因此我們高度重視 建議您深入閱讀。 儘管我們不會在此處介紹全部代碼,但我們將重點介紹一些重要的部分。
1.建立策略網絡
# make core of policy network
obs_ph = tf.placeholder(shape=(None, obs_dim), dtype=tf.float32)
logits = mlp(obs_ph, sizes=hidden_sizes+[n_acts])
# make action selection op (outputs int actions, sampled from policy)
actions =tf.squeeze(tf.multinomial(logits=logits,num_samples=1), axis=1)
此塊構建了前饋神經網絡分類策略。 (有關更新,請參閱第1部分中的隨機策略部分。)logits張量可用於構造對數概率和操作的概率,而action張量基於logit隱含的概率對操作進行採樣。
2.構建損失函數
# make loss function whose gradient, for the right data, is policy gradient
weights_ph = tf.placeholder(shape=(None,), dtype=tf.float32)
act_ph = tf.placeholder(shape=(None,), dtype=tf.int32)
action_masks = tf.one_hot(act_ph, n_acts)
log_probs = tf.reduce_sum(action_masks * tf.nn.log_softmax(logits), axis=1)
loss = -tf.reduce_mean(weights_ph * log_probs)
在此塊中,我們爲策略梯度算法構建“損失”函數。 當插入合適的數據時,策略梯度等於這個損失的梯度。 合適的數據表示根據當前策略執行操作時收集的一組(狀態,動作,權重)元組,其中狀態-動作對的權重是從其所屬回合返回的。 (儘管我們將在後面的小節中顯示,但是您可以插入其他值來也可以正常工作的重量。)
即使我們將其描述爲損失函數,但從監督學習的角度來看,它並不是典型的損失函數。與標準損失函數有兩個主要區別。
1.數據分佈取決於參數。損失函數通常在固定的數據分佈上定義,該分佈與我們要優化的參數無關。這裏不是,必須在最新策略上對數據進行採樣。
2.它無法衡量效果。損失函數通常會評估我們關注的性能指標。在這裏,我們關心期望收益,但即使在期望中,我們的“損失”函數也根本不近似。此“損失”功能僅對我們有用,因爲當在當前參數下進行評估時,使用當前參數生成的數據時,其性能會呈現負梯度。
但是,在梯度下降的第一步之後,就不再與性能相關。這意味着,對於給定的一批數據,最小化此“損失”功能無法保證提高預期收益。可以將這一損失放到,而策略表現能可能會下降;實際上,通常會這樣。有時,資深RL研究人員可能會將此結果描述爲對大量數據“過度擬合”的策略。這是描述性的,但不應從字面上理解,因爲它沒有涉及泛化錯誤。
我們提出這一點是因爲,ML練習者通常會在訓練過程中將損失函數解釋爲有用的信號-“如果損失減少了,一切都會好起來的。”在政策梯度中,這種直覺是錯誤的,您應該只在乎平均回報率。損失函數沒有任何意義。
此處用於製作log_probs張量的方法(創建操作掩碼,並使用它來選擇特定的對數概率)僅適用於分類策略。 通常它不起作用。
3.運行訓練的一個Epoch
# for training policy
def train_one_epoch():
# make some empty lists for logging.
batch_obs = [] # for observations
batch_acts = [] # for actions
batch_weights = [] # for R(tau) weighting in policy gradient
batch_rets = [] # for measuring episode returns
batch_lens = [] # for measuring episode lengths
# reset episode-specific variables
obs = env.reset() # first obs comes from starting distribution
done = False # signal from environment that episode is over
ep_rews = [] # list for rewards accrued throughout ep
# render first episode of each epoch
finished_rendering_this_epoch = False
# collect experience by acting in the environment with current policy
while True:
# rendering
if not(finished_rendering_this_epoch):
env.render()
# save obs
batch_obs.append(obs.copy())
# act in the environment
act = sess.run(actions, {obs_ph: obs.reshape(1,-1)})[0]
obs, rew, done, _ = env.step(act)
# save action, reward
batch_acts.append(act)
ep_rews.append(rew)
if done:
# if episode is over, record info about episode
ep_ret, ep_len = sum(ep_rews), len(ep_rews)
batch_rets.append(ep_ret)
batch_lens.append(ep_len)
# the weight for each logprob(a|s) is R(tau)
batch_weights += [ep_ret] * ep_len
# reset episode-specific variables
obs, done, ep_rews = env.reset(), False, []
# won't render again this epoch
finished_rendering_this_epoch = True
# end experience loop if we have enough of it
if len(batch_obs) > batch_size:
break
# take a single policy gradient update step
batch_loss, _ = sess.run([loss, train_op],
feed_dict={
obs_ph: np.array(batch_obs),
act_ph: np.array(batch_acts),
weights_ph: np.array(batch_weights)
})
return batch_loss, batch_rets, batch_lens
train_one_epoch()函數運行策略梯度的一個“epoch”,我們定義爲
- 1.經驗收集步驟(L62-97),其中代理使用最新策略在環境中互動一定數量的回合,其後是
- 2.一個策略梯度的更新 (L99-105).
Expected Grad-Log-Prob Lemma
在本小節中,我們將得出一箇中間結果,該結果在整個政策梯度理論中得到了廣泛使用。 我們將其稱爲“梯度對數概率期望(EGLP)”引理 [1]。
EGLP引理。 假設是隨機變量x上的參數化概率分佈。 然後:
回想一下,所有概率分佈都是“歸一化”的:
取兩側的梯度:
使用對數派生技巧可以獲取:
[1] 本文的作者沒有意識到在文獻中的任何地方都給該引理指定了標準名稱。 但是考慮到它出現的頻率,似乎很值得給它起一個名字以便於參考。
Don’t Let the Past Distract You
到現在的策略梯度的表達變成了:
在這個梯度上邁出一步,將每個動作的對數概率與(曾經獲得的所有獎勵之和)成比例。 但這沒有多大意義。
代理實際上僅應根據其“後果”加強行動。 採取行動之前獲得的獎勵與行動的好壞沒有關係:僅在“之後”獲得獎勵。
事實證明,這種直覺體現在數學上,我們可以證明策略梯度也可以表示爲
以這種形式,僅基於採取行動後獲得的獎勵來加強行動。
我們稱這種形式爲“未來獎勵策略梯度”,因爲軌跡上某點之後的獎勵總和,
這就是從 t 時刻起的“未來獎勵”,而這種策略梯度表述取決於狀態動作對的“未來獎勵”。
但是,這會更好嗎? 策略梯度的關鍵問題是需要多少個樣本軌跡才能獲得它們的低方差樣本估計。 我們從公式開始就包括了與過去的報酬成比例的加強行動的條件,所有這些均值均值爲零,但方差不爲零:結果,它們只會給策略梯度的樣本估計值增加噪音。 通過刪除它們,我們減少了所需的樣本軌跡數量。
An (optional) proof of this claim can be found here, and it ultimately depends on the EGLP lemma.
Implementing Reward-to-Go Policy Gradient
We give a short Tensorflow implementation of the reward-to-go policy gradient in spinup/examples/pg_math/2_rtg_pg.py
. (It can also be viewed on github <https://github.com/openai/spinningup/blob/master/spinup/examples/pg_math/2_rtg_pg.py>
_.)
The only thing that has changed from 1_simple_pg.py
is that we now use different weights in the loss function. The code modification is very slight: we add a new function, and change two other lines. The new function is:
def reward_to_go(rews):
n = len(rews)
rtgs = np.zeros_like(rews)
for i in reversed(range(n)):
rtgs[i] = rews[i] + (rtgs[i+1] if i+1 < n else 0)
return rtgs
然後我們從以下方法調整舊的L86-87,從:
# the weight for each logprob(a|s) is R(tau)
batch_weights += [ep_ret] * ep_len
到:
# the weight for each logprob(a_t|s_t) is reward-to-go from t
batch_weights += list(reward_to_go(ep_rews))
Baselines in Policy Gradients
EGLP引理的直接後果是,對於僅依賴狀態的任何函數:
這使我們能夠從我們的策略梯度表達式中添加或減去任何數量的這樣的術語,而在期望中無需更改它:
Any function b used in this way is called a baseline.
基準的最常見選擇是策略價值函數. 這是從狀態開始,然後遵循策略的代理所得到的平均回報。
根據經驗,選擇具有減少策略梯度樣本估計中方差的理想效果。這樣可以更快,更穩定地學習策略。 從概念的角度來看,它也很吸引人:它編碼了一種直覺,即如果一個代理達到了預期,它將“感覺”到中立。
實際上,不能夠準確計算,所以它需要被近似。這通常用一個神經網絡來近似,,它可以與策略同時被更新(這樣值網絡總是近似最近策略的值函數)。
學習的最簡單的方法, 被用在在較多數策略優化算法中(包括VPG,TRPO,PPO,A2C),是去最小化均方誤差項:
其中是在第k個epoch的策略。這是從前一個值函數的參數,通過梯度下降的一個或多個步驟完成的.
Other Forms of the Policy Gradient
到目前爲止,我們看到的是策略梯度具有一般形式:
其中可以任意的這些形式:
or:
or:
儘管有不同的差異,所有這些選擇都會導致相同的策略梯度期望值。 事實證明,有兩個權重 很重要:
-
1.On-Policy Action-Value Function.
-
2. The Advantage Function.
回憶動作的優勢函數, 定義爲 , (對於當前的策略)描述平均地相對於其他動作而言好還是壞。 這個選擇:也是有效的, 證據是它相當於使用然後再使用一個值函數的基準。
具有優勢函數的策略梯度的制定極爲普遍,並且有許多不同的方法來估算不同算法所使用的優勢函數。
要對此主題進行更詳細的處理,您應該閱讀有關廣義優勢估計(GAE)的文章,該文章深入探討了背景部分中的不同選擇。
然後,該論文繼續描述GAE,GAE是一種在策略優化算法中具有廣泛用途的近似優勢函數的方法。 例如,Spinning Up的VPG,TRPO和PPO的實現都利用了它。 因此,我們強烈建議您進行研究。