https://mp.weixin.qq.com/s/upkQXe5dzb1bn7Ymg4X6kQ
Acme 是一個基於 Python 的強化學習研究框架,由谷歌的 DeepMind 於 2020 年開源。它旨在簡化新型 RL 代理的開發並加速 RL 研究。根據 DeepMind 自己的聲明,這個強化學習和人工智能研究的先鋒團隊每天都在使用 Acme。
最近我參與了一個大學項目,為此決定學習 Acme 並使用它來實現不同的 RL 算法。我發現它的確很棒,我真的很喜歡用它。
Acme 的入門也相對容易。這是因為它有多條入門路徑,分別有不同的復雜度。換句話說,這款框架不僅適用於高級研究人員,而且還能讓初學者實現頗為簡單的算法——這和對初學者與專家都很友好的 TensorFlow 和 PyTorch 差不多。
它的不足之處在於,由於這款框架還很新,因此沒有真正完整的文檔可用,也沒有做得很好的教程。
這篇博文可能是朝着正確方向邁出的一步。它並不打算成為或取代完整的文檔,而是對 Acme 的一篇簡明實用的介紹。最重要的是,它應該能讓你了解框架底層的設計選擇,以及這些選擇對 RL 算法的實現有着怎樣的意義。
我將討論我的兩個簡單算法的實現:SARSA 和 Q Learning,其目標是玩二十一點游戲。一旦你了解了 actor 和 agent 都是什么東西,以及它們在 Acme 中是如何設計的,我相信你將很快了解如何實現你能想到的任何強化學習算法。
Acme 的基本構建塊
我們來深入研究一個實際案例。如前所述,我們希望我們的代理(agent)玩二十一點游戲。
環境
Acme 代理並非設計為與 Gym 環境交互。相反,DeepMind 有自己的 RL 環境 API。區別主要在於時間步長的表示方式。
不過幸運的是你仍然可以使用 Gym 環境,因為 Acme 的開發人員為此提供了包裝函數。
env = acme.wrappers.GymWrapper(gym.make('Blackjack-v0'))
二十一點游戲中有 32x11x2 的狀態,不過並非所有狀態都可以在游戲中實際出現。另外還有兩個動作,“拿牌(hit)”和“停牌(stick)”。想要了解這些維度的細節,以及為什么不是所有狀態都可以出現,你可以在 這里 查看 GitHub 上的環境。我知道一開始學起來會有些難度。
參與者、學習者和代理
了解參與者(actor)、學習者(learner)和代理(agent)之間的區別至關重要。參與者與環境互動。也就是說,它們觀察狀態並根據某些動作選擇策略采取動作。下圖說明了這一點。
圖 1:只有參與者的簡單環境循環。
學習者使用參與者收集的數據來學習或改進策略,通常用的是在線迭代的方式。例如,學習內容可能包括對神經網絡參數的更新。新參數被傳遞給參與者,然后參與者根據更新的策略行事。
代理就是行動和學習組件的簡單結合,但通常不需要實現額外的強化學習邏輯。下圖包括所有三個組件。
圖 2:包括參與者和學習者的環境循環。
架構分解為參與者、學習者和代理的主要原因之一是為了促進分布式強化學習。但是,如果我們不關心這一點並且算法足夠簡單,那么僅實現參與者,並簡單地將學習步驟集成到參與者的 update 方法也足夠了。為簡單起見,這也是我在這里采用的方法。
例如,下面的隨機代理繼承自 acme.Actor 類。必須由開發者(你)實現的方法是 select_action、observe_first、observe 和 update。如前所述,后者是在沒有額外學習者組件的情況下進行學習的地方。請注意,這個代理將以相同的方式工作,只是無需子類化 acme.Actor。基類確定你必須覆蓋的方法。這也確保了代理按預期與其他 Acme 組件(例如我將在下面介紹的環境循環)集成。
class RandomAgent(acme.Actor):
"""A random agent for the Black Jack environment."""
def __init__(self):
# init action values, will not be updated by random agent
self.Q = np.zeros((32,11,2,2))
# specify the behavior policy
self.behavior_policy = lambda q_values: np.random.choice(2)
# store timestep, action, next_timestep
self.timestep = None
self.action = None
self.next_timestep = None
def select_action(self, observation):
"Choose an action according to the behavior policy."
return self.behavior_policy(self.Q[observation])
def observe_first(self, timestep):
"Observe the first timestep."
self.timestep = timestep
def observe(self, action, next_timestep):
"Observe the next timestep."
self.action = action
self.next_timestep = next_timestep
def update(self, wait = False):
"Update the policy."
# no updates occur here, it's just a random policy
這個代理使用一個簡單的隨機選擇拿牌或停牌的策略,但一般來說,這個框架在實現策略的方式方面有巨大的靈活性。稍后,你將看到一個 epsilon-greedy 策略。在其他情況下,策略可能包括一個神經網絡,你可以使用 TensorFlow、PyTorch 或 JAX 來實現它。從這個意義上說,Acme 與框架無關,因此你可以與你喜歡的任何機器學習庫搭配使用它。
在 update 方法中,參與者通常只從學習者中提取最新的參數。但如果你不使用單獨的學習者,則 RL 邏輯將包含在 update 方法中(稍后你會看到這一點)。
EnvironmentLoop
如果你已經對強化學習有所了解並且已經實現了 RL 算法,那么你肯定會非常熟悉以下循環。每個 episode 由四個步驟組成,這些步驟重復執行,直到達到最終狀態。
-
觀察一個狀態
-
根據行為策略采取一個行動
-
觀察一個獎勵
-
更新政策
代碼:
# first initialize env and agent
# env = ...
agent = RandomAgent()
# repeat for a number of episodes
for episode in range(10):
# make first observation
timestep = env.reset()
agent.observe_first(timestep)
# run an episode
while not timestep.last():
# generate an action from the agent's policy
action = agent.select_action(timestep.observation)
# step the environment
timestep = env.step(action)
# have the agent observe the next timestep
agent.observe(action, next_timestep=timestep)
# let the agent perform updates
agent.update()
有時你可能需要實現這樣的循環,特別是如果你希望對其自定義的時候。但大多數情況下,這個循環都是完全相同的。
方便的是,Acme 中有一個快捷方式:EnvironmentLoop,它執行的步驟與上述步驟幾乎完全相同。你只需傳遞你的環境和代理實例,然后你就可以使用一行代碼運行單個 episode 或任意多個 episode。還有許多日志記錄器可用於跟蹤重要指標,例如每個 episode 中使用的步數和收集的獎勵。
# init Acme's environment loop
loop = EnvironmentLoop(env, agent, logger=InMemoryLogger())
# run a single episode
loop.run_episode()
# or run multiple episodes
loop.run(10
實現 SARSA 和 Q 學習代理
當然,隨機代理不是很有用。我的承諾是展示如何實現一些實際的強化學習算法,所以我們開始吧。
順便說一句,如果你根本不熟悉 RL,請參閱 Sutton 和 Barto 的《強化學習:簡介》(2018 年)一書。大家通常最早學習的兩種算法——無論是在書中還是在大學上的強化學習課程上——是 SARSA 和 Q 學習。
SARSA 代理
現在你已經知道 Acme 代理(或參與者)是如何設計的了。讓我們看看如何在 Acme 中實現 SARSA 算法。
SARSA 是一種基於策略的算法,其更新取決於狀態、動作、獎勵、下一個狀態和下一個動作(因此得名)。由於本文不是一篇理論 RL 教程,因此我不會在這里詳細介紹算法本身。
首先,在代理的 init 方法中,我們初始化 Q、狀態 - 動作值矩陣和行為策略——這里是一個 epsilon 貪婪策略。另請注意,這個代理必須始終存儲其上一個時間步長、動作和下一個時間步長,因為 update 步驟中需要它們。所以我們也初始化它們。
class SarsaAgent(acme.Actor):
def __init__(self, env_specs=None, epsilon=0.1, step_size=0.1):
# in Black Jack, we have the following dimensions
self.Q = np.zeros((32,11,2,2))
# epsilon for policy and step_size for TD learning
self.epsilon = epsilon
self.step_size = step_size
# set behavior policy
self.behavior_policy = lambda q_values: epsilon_greedy(q_values, self.epsilon)
# store timestep, action, next_timestep
self.timestep = None
self.action = None
self.next_timestep = None
def transform_state(self, state):
# this is specifally required for the blackjack environment
state = *map(int, state),
return state
def select_action(self, observation):
state = self.transform_state(observation)
return self.behavior_policy(self.Q[state])
def observe_first(self, timestep):
self.timestep = timestep
def observe(self, action, next_timestep):
self.action = action
self.next_timestep = next_timestep
def update(self):
# get variables for convenience
state = self.timestep.observation
_, reward, discount, next_state = self.next_timestep
action = self.action
# turn states into indices
state = self.transform_state(state)
next_state = self.transform_state(next_state)
# sample a next action
next_action = self.behavior(self.Q[next_state])
# compute and apply the TD error
td_error = reward + discount * self.Q[next_state][next_action] - self.Q[state][self.action]
self.Q[state][action] += self.step_size * td_error
# finally, set timestep to next_timestep
self.timestep = self.next_timestep
在 observe 中你通常不需要做太多事情。在本例中,我們只存儲觀察到的時間步長和采取的行動。然而這並不總是必要的。比如有時候,你可能希望將時間步長(和整個軌跡)存儲在一個數據集或重播緩沖區中。Acme 還為此提供了數據集和加法器組件。事實上,DeepMind 也開發了一個庫。它被稱為 Reverb(參見此處的 GitHub)。
上面的 transform_state 方法只是一個輔助函數,用於將狀態放入正確的格式以便正確索引 Q 矩陣。
最后,要在環境上訓練 SARSA 500,000 episodes,只需運行
agent = SarsaAgent()
loop = EnvironmentLoop(env, agent, logger=InMemoryLogger())
loop.run(500000)
Q 學習代理
下面的 Q 學習代理與 SARSA 代理非常相似。它們僅在更新 Q 矩陣的方式上有所不同。這是因為 Q 學習是一種離策略算法。
class QLearningAgent(acme.Actor):
def __init__(self, env_specs=None, step_size=0.1):
# Black Jack dimensions
self.Q = np.zeros((32,11,2,2))
# set step size
self.step_size = step_size
# set behavior policy
# self.policy = None
self.behavior_policy = lambda q_values: epsilon_greedy(q_values, epsilon=0.1)
# store timestep, action, next_timestep
self.timestep = None
self.action = None
self.next_timestep = None
def state_to_index(self, state):
state = *map(int, state),
return state
def transform_state(self, state):
# this is specifally required for the blackjack environment
state = *map(int, state),
return state
def select_action(self, observation):
state = self.transform_state(observation)
return self.behavior_policy(self.Q[state])
def observe_first(self, timestep):
self.timestep = timestep
def observe(self, action, next_timestep):
self.action = action
self.next_timestep = next_timestep
def update(self):
# get variables for convenience
state = self.timestep.observation
_, reward, discount, next_state = self.next_timestep
action = self.action
# turn states into indices
state = self.transform_state(state)
next_state = self.transform_state(next_state)
# Q-value update
td_error = reward + discount * np.max(self.Q[next_state]) - self.Q[state][action]
self.Q[state][action] += self.step_size * td_error
# finally, set timestep to next_timestep
self.timestep = self.next_timestep
要在環境上訓練 Q 學習代理 500,000 episodes,運行
agent = QLearningAgent()
loop = EnvironmentLoop(env, agent, logger=InMemoryLogger())
loop.run(500000)
小 結
我認為 Acme 是一個非常棒的強化學習框架,因為你不必從頭開始開發算法。因此,與其自己弄清楚如何編寫可讀且可重復的 RL 代碼,你大可依靠 DeepMind 那些聰明的研究人員和開發人員,他們已經為你完成了這些工作。
Acme 能讓你實現任何強化學習算法,並且你可以將其與任何機器學習框架結合使用,包括 TensorFlow、PyTorch 和 JAX。
如果你想了解有關 Acme 的更多信息,可以閱讀 DeepMind 的研究 論文 並查看他們的 GitHub存儲庫。
你還會在那里找到一些常見算法的實現,例如深度 Q 網絡(DQN)、深度確定性策略梯度(DDPG)、蒙特卡洛樹搜索(MCTS)、行為克隆(BC)、IMPALA 等。
無論你是高級研究員還是對強化學習感興趣的初學者,我都鼓勵你嘗試一下。
感謝你的閱讀。如果你有任何問題,請告訴我。
鏈接
我的 Jupyter 筆記本(包括本文用到的代碼)在 這里。
如果有興趣,也可以查看我的強化學習課程 項目。除了 SARSA 和 Q-learning,我還實現了 dyna-Q、優先掃描和蒙特卡洛樹搜索代理。
參考
Hoffman 等人(2020):Acme:一個分布式強化學習的研究框架。ArXiv。
Sutton 和 Barto(2018 年):強化學習:簡介。
原文鏈接:
https://towardsdatascience.com/deepminds-reinforcement-learning-framework-acme-87934fa223bf