強化學習(RL)是機器學習的三大範式之一,另外兩個是監督式學習和非監督式學習。在強化學習中,代理程序學習與環境互動,以最大化累積獎勵。它通過試錯的方式學習在不同環境條件下的最佳行為。具人類反饋的強化學習(RLHF)允許代理程序根據每一步的人類輸入來調整行為。
RL解決了自動駕駛汽車、自動交易、視頻遊戲中的電腦玩家、培訓機器人等問題。當使用深度神經網絡應用RL算法時,稱為深度強化學習。
在本教程中,我將向您展示如何開始使用Gymnasium,這是一個用於開發和比較強化學習算法的開源Python庫。我將演示如何設置它,探索各種RL環境,並使用Python構建一個簡單的代理程序來實現RL算法。
什麼是Gymnasium?
Gymnasium是一個開源的Python庫,旨在支持強化學習(RL)算法的開發。為了促進RL的研究和開發,Gymnasium提供:
- 各種環境,從簡單的遊戲到模擬現實生活場景的問題。
- 簡化的API和包裝器,以便與環境進行交互。
- 創建自定義環境的能力,並利用API框架。
開發者可以構建RL算法並使用API調用進行以下任務:
- 將代理選擇的動作傳遞給環境。
- 了解環境的狀態和每個行動後的獎勵。
- 訓練模型。
- 測試模型的性能。
OpenAI 的 Gym 與 Farama 的 Gymnasium
OpenAI 沒有投入大量資源來開發 Gym,因為這對公司來說並不是商業優先事項。Farama 基金會的成立是為了標準化和長期維護強化學習庫。Gymnasium 是 Farama 基金會基於 OpenAI Gym 的分支。Gymnasium 0.26.2 是 Gym 0.26.2 的替代品。透過這個分支,Farama 旨在為所有 API 調用添加功能性(除了基於類的)方法,支持向量環境,並改善包裝器。整體目標是使框架更乾淨、更高效。
設置 Gymnasium
體育館需要特定版本(而非最新版本)各種依賴程序,如NumPy和PyTorch。因此,我們建議創建一個新的 Conda 或 venv 環境,或者一個新的筆記本來安裝、使用體育館並運行強化學習程序。
您可以使用這個DataLab工作簿來跟著教程進行。
安裝體育館
要在服務器或本地計算機上安裝體育館,運行:
$ pip install gymnasium
要使用類似 Google 的 Colab 或 DataCamp 的 DataLab 安裝,請使用:
!pip install gymnasium
上述命令安裝 Gymnasium 及其正確版本的依賴項。
探索 Gymnasium 環境
截至 2024 年 11 月,Gymnasium 包含超過 60 種內建環境。要瀏覽可用的內建環境,請使用 gym.envs.registry.all()
函數,如下例所示:
import gymnasium as gym for i in gym.envs.registry.keys(): print(i)
你也可以访问体育馆主页。左侧栏中有所有环境的链接。每个环境的网页包括关于其的详细信息,如动作、状态等。
环境被组织成经典控制、Box2D等类别。以下我列出了每个组中一些常见环境:
- 经典控制:这些是RL开发中使用的经典环境;它们构成许多教科书示例的基础。它们提供了测试和基准测试新的RL算法的复杂性和简单性的正确混合。Gymnasium中的经典控制环境包括:
- Acrobot
- Cart Pole
- Mountain Car Discrete
- Mountain Car Continuous
- Pendulum
- Box2D: Box2D 是一個用於遊戲的2D物理引擎。基於這個引擎的環境包括簡單的遊戲,如:
- 月球登陸
- 賽車
- ToyText: 這些是小型而簡單的環境,通常用於調試強化學習算法。許多這些環境都基於小網格世界模型和簡單的紙牌遊戲。例如:
- 二十一點
- 出租車
- 冰湖
- MuJoCo: 多關節動力學與接觸(MuJoCo)是一個開源的物理引擎,模擬應用於機器人技術、生物力學、機器學習等的環境。Gymnasium中的MuJoCo環境包括:
- 螞蟻
- 跳躍者
- 人形機器人
- 游泳者
- 等等
除了內置環境外,Gymnasium還可以使用相同的API與許多外部環境一起使用。
在本教程中,我們將使用其中一個經典的 Classic Control 環境。要導入特定環境,請使用 .make()
命令,並將環境的名稱作為參數傳遞。例如,要基於 CartPole(版本 1)創建新環境,請使用以下命令:
import gymnasium as gym env = gym.make("CartPole-v1")
在 Gymnasium 中理解強化學習概念
簡而言之,強化學習 包括 一個與環境互動的代理(如機器人)。一個策略決定代理的行動。根據代理的行動,環境在每個時間步給出獎勵(或懲罰)。代理使用強化學習來找出最大化代理獲得的總獎勵的最佳策略。
強化學習環境的組成部分
以下是RL環境的關鍵組成部分:
- 環境: 外部系統、世界或上下文。智能體在一系列時間步中與環境互動。在每個時間步中,根據智能體的行動,環境:
- 給予獎勵(或懲罰)
- 決定下一狀態
- 狀態: 環境當前配置的數學表示。
- 例如,擺動環境的狀態可以包括每個時間步的擺動位置和角速度。
- 終端狀態:不會導致新的狀態或其他狀態的狀態。
- Agent: 觀察環境並根據觀察採取各種行動的算法。代理的目標是最大化其獎勵。
- 例如,代理決定以多大力道和方向推動擺動。
- 觀察: 代理人對環境的數學表述,例如通過傳感器獲取的數據。
- 行動: 代理人在進入下一步之前所做的決策。該行動會影響環境的下一狀態並為代理人獲得獎勵。
- 獎勵: 環境對代理人的反饋。根據行動和環境狀態,可以是正面或負面的。
- 返回: 未來時間步的預期累積回報。未來時間步的獎勵可以使用折扣因子進行折現。
- 策略: 關於在不同狀態下採取何種行動的代理策略。通常表示為概率矩陣,P,將狀態映射到行動。
- 給定一個有限的狀態集合m個可能的狀態和n個可能的動作,矩陣中的元素Pmn表示在狀態an中採取動作sm的概率。
- 集數: 從(隨機)初始狀態到代理到達終端狀態的一系列時間步驟。
觀察空間和行動空間
觀察是代理人獲取有關環境的信息。例如,一個機器人可以使用感應器收集環境信息。理想情況下,代理應該能夠觀察完整的狀態,該狀態描述了環境的所有方面。實際上,代理使用其觀察作為狀態的代理。因此,觀察決定了代理的行動。
一個空間類似於一個數學集合。項目的空間包括所有可能的實例X。空間也定義了所有類型為X的項目的結構(語法和格式)。每個Gymnasium環境都有兩個空間,動作空間action_space
和觀察空間observation_space
。動作和觀察空間都是從父類gymnasium.spaces.Space
繼承而來。
觀察空間
觀察空間是包含所有可能觀察結果的空間。它還定義了觀察結果的存儲格式。觀察空間通常表示為一個數據類型 Box 的物件。這是一個 ndarray,用於 描述觀察結果的參數。該盒子指定了每個維度的範圍。您可以使用 observation_space
方法查看環境的觀察空間:
print("observation space: ", env.observation_space)
在 CartPole-v1
環境的情況下,輸出看起來如下所示:
observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)
在這個例子中,CartPole-v1
觀察空間有4個維度。觀察數組的4個元素是:
- 小車位置 – 變化範圍在-4.8到+4.8之間
- 推車速度 – 範圍在 – 到 +
- 桿角度 – 在 -0.4189 到 +0.4189 之間變化
- 極角速度 – 範圍在 – 到 +
要查看單個觀測數組的示例,請使用 .reset()
命令。
observation, info = env.reset() print("observation: ", observation)
在 CartPole-v1
环境中,输出如下例所示:
[ 0.03481963 -0.0277232 0.01703267 -0.04870504]
数组的四个元素对应于四个观察到的量(小车位置、小车速度、杆子角度、杆子角速度),如前所述。
动作空间
动作空间包括代理程序可以采取的所有可能动作。动作空间还定义了动作的表示格式。您可以使用 action_space
方法查看环境的动作空间:
print("action space: ", env.action_space)
在CartPole-v1
环境中,输出如下所示:
action space: Discrete(2)
在CartPole-v1
环境中,动作空间是离散的。代理可以采取两个动作:
- 0:将小车向左推
- 1:将小车向右推
使用Gymnasium构建您的第一个RL代理
在前幾節中,我們探討了強化學習和Gymnasium的基本概念。本節將向您展示如何使用Gymnasium來建立一個強化學習代理程序。
創建和重置環境
第一步是創建環境的一個實例。要創建新的環境,請使用.make()
方法。
env = gym.make('CartPole-v1')
代理的交互會改變環境的狀態。.reset()
方法將環境重置為初始狀態。默認情況下,環境被初始化為一個隨機狀態。您可以使用.reset()
方法的SEED
參數來使環境在每次運行程序時初始化為相同的狀態。以下代碼展示了如何實現這一點:
SEED = 1111 env.reset(seed=SEED)
行動抽樣也涉及隨機性。為了控制這種隨機性並獲得完全可重現的訓練路徑,我們可以種子化 NumPy 和 PyTorch 的隨機生成器:
np.random.seed(SEED) torch.manual_seed(SEED)
隨機對比智能行動
在馬可夫過程的每一步中,代理可以隨機選擇一個動作並探索環境,直到達到終端狀態。通過隨機選擇動作:
- 可能需要很長時間才能達到終端狀態。
- 累積獎勵遠低於其潛在水平。
訓練代理根據先前的經驗(與環境互動)優化動作選擇,更有效地最大化長期獎勵。
未经训练的代理人根据随机初始化的策略执行随机动作。这个策略通常表示为神经网络。在训练过程中,代理人学习最大化奖励的最优策略。在强化学习中,训练过程也被称为策略优化。
有各种各样的策略优化方法。贝尔曼方程描述了如何计算RL策略的价值并确定最优策略。在本教程中,我们将使用一种称为策略梯度的简单技术。还有其他方法,比如近端策略优化(PPO)。
实现一个简单的策略梯度代理
為了建立一個使用政策梯度的強化學習代理,我們創建一個神經網絡來實現政策,編寫函數來計算基於步驟獎勵和動作概率的回報和損失,並使用標準的反向傳播技術迭代更新政策。
設置政策網絡
我們使用神經網絡來實現政策。因為CartPole-v1
是一個簡單的環境,我們使用一個具有以下特徵的神經網絡:
- 輸入維度等於環境觀察空間的維度。
- 一個隱藏層,包含64個神經元。
- 輸出維度等於環境動作空間的維度。
因此,策略網絡的功能是將觀察到的狀態映射到動作。給定一個輸入觀察,它預測正確的動作。以下代碼實現了策略網絡:
class PolicyNetwork(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim, dropout): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, x): x = self.layer1(x) x = self.dropout(x) x = F.relu(x) x = self.layer2(x) return x
獎勵收集和前向傳播
如前所述,在馬爾可夫過程的每一步中,環境根據代理的動作和狀態給予獎勵。強化學習的目標是最大化總回報。
- 每個時間步的回報是從開始到該步驟獲得的獎勵的累積和。
- 每一個情節的總回報是通過累計該情節中所有步驟的獎勵來獲得的。因此,總回報是在最後一個時間步(當代理達到終端狀態時)的回報。
在實踐中,在累積獎勵時,通常會採取以下措施:
- 使用折扣因子調整未來的獎勵。
- 對步驟回報的數組進行歸一化,以確保訓練的平穩和穩定。
以下代碼展示了如何實現這一目標:
def calculate_stepwise_returns(rewards, discount_factor): returns = [] R = 0 for r in reversed(rewards): R = r + R * discount_factor returns.insert(0, R) returns = torch.tensor(returns) normalized_returns = (returns - returns.mean()) / returns.std() return normalized_returns
前向傳遞的過程包括根據當前策略運行代理,直到達到終止狀態,並收集逐步獎勵和行動概率。以下步驟解釋了如何實現前向傳遞:
- 將環境重置為初始狀態。
- 初始化緩衝區以存儲行動概率、獎勵和累積回報
- 使用
.step()
函數迭代地在環境中運行代理,直到終止: - 獲取環境狀態的觀察。
- 根據觀察獲取政策預測的行動。
- 使用
Softmax
函數來估計執行預測行動的概率。 - 根據這些估計的概率模擬一個分類概率分佈。
- 從這個分佈中抽樣以獲得代理的行動。
- 從模擬分佈中估計所抽樣行動的對數概率。
- 將每一步的行動的對數概率和獎勵附加到各自的緩衝區中。
- 根據獎勵估計每一步的回報的標準化和折現值。
def forward_pass(env, policy, discount_factor): log_prob_actions = [] rewards = [] done = False episode_return = 0 policy.train() observation, info = env.reset() while not done: observation = torch.FloatTensor(observation).unsqueeze(0) action_pred = policy(observation) action_prob = F.softmax(action_pred, dim = -1) dist = distributions.Categorical(action_prob) action = dist.sample() log_prob_action = dist.log_prob(action) observation, reward, terminated, truncated, info = env.step(action.item()) done = terminated or truncated log_prob_actions.append(log_prob_action) rewards.append(reward) episode_return += reward log_prob_actions = torch.cat(log_prob_actions) stepwise_returns = calculate_stepwise_returns(rewards, discount_factor) return episode_return, stepwise_returns, log_prob_actions
根據獎勵更新策略
損失表示我們應用 梯度下降 的量。在強化學習中,目標是最大化回報。因此,我們使用預期回報值作為損失的代理。預期回報值是逐步預期回報和逐步行動的對數概率的乘積。以下代碼計算損失:
def calculate_loss(stepwise_returns, log_prob_actions): loss = -(stepwise_returns * log_prob_actions).sum() return loss
更新政策時,您需要針對損失函數運行反向傳播。下面的update_policy()
方法調用calculate_loss()
方法。然後對該損失運行反向傳播,以更新政策參數,即政策網絡的模型權重。
def update_policy(stepwise_returns, log_prob_actions, optimizer): stepwise_returns = stepwise_returns.detach() loss = calculate_loss(stepwise_returns, log_prob_actions) optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()
基於回報梯度更新政策被稱為策略梯度方法。
訓練政策
現在我們擁有訓練和評估政策所需的所有組件。我們按照以下步驟實現訓練循環:
在開始之前,我們宣告超參數,實例化一個策略,並創建一個優化器:
- 將超參數聲明為 Python 常數:
MAX_EPOCHS
是我們準備運行以訓練策略的最大迭代次數。DISCOUNT_FACTOR
決定來自未來時間步的獎勵的相對重要性。折扣因子為 1 表示所有獎勵同等重要,而值為 0 則表示只有當前時間步的獎勵是重要的。N_TRIALS
是我們用來評估代理程式表現的平均回報的計算次數。如果在N_TRIALS
個回合的平均回報超過閾值,我們將認為訓練是成功的。REWARD_THRESHOLD
:如果政策可以實現高於閾值的回報,則被視為成功。DROPOUT
決定應該隨機歸零的權重比例。退出功能將模型權重的一部分隨機設置為零。這減少對特定神經元的依賴,防止過度擬合,使網絡更加強壯。LEARNING_RATE
決定在每個步驟中可以修改策略參數的程度。每次迭代中對參數的更新是梯度和學習率的乘積。- 將策略定義為
PolicyNetwork
類的一個實例(之前實現的)。 - 使用Adam算法和學習率創建一個優化器。
為了訓練策略,我們迭代運行訓練步驟,直到平均回報(在N_TRIALS
中)大於獎勵閾值為止:
- 對於每個情節,運行一次正向傳播。收集動作的對數概率、逐步回報和該情節的總回報。將情節回報累積在一個數組中。
- 使用對數概率和逐步返回值計算損失。運行梯度反向傳播算法處理損失。使用優化器更新策略參數。
- 檢查平均返回值是否超過獎勵閾值。
以下代碼實現了這些步驟:
def main(): MAX_EPOCHS = 500 DISCOUNT_FACTOR = 0.99 N_TRIALS = 25 REWARD_THRESHOLD = 475 PRINT_INTERVAL = 10 INPUT_DIM = env.observation_space.shape[0] HIDDEN_DIM = 128 OUTPUT_DIM = env.action_space.n DROPOUT = 0.5 episode_returns = [] policy = PolicyNetwork(INPUT_DIM, HIDDEN_DIM, OUTPUT_DIM, DROPOUT) LEARNING_RATE = 0.01 optimizer = optim.Adam(policy.parameters(), lr = LEARNING_RATE) for episode in range(1, MAX_EPOCHS+1): episode_return, stepwise_returns, log_prob_actions = forward_pass(env, policy, DISCOUNT_FACTOR) _ = update_policy(stepwise_returns, log_prob_actions, optimizer) episode_returns.append(episode_return) mean_episode_return = np.mean(episode_returns[-N_TRIALS:]) if episode % PRINT_INTERVAL == 0: print(f'| Episode: {episode:3} | Mean Rewards: {mean_episode_return:5.1f} |') if mean_episode_return >= REWARD_THRESHOLD: print(f'Reached reward threshold in {episode} episodes') break
最後,調用main()
函數來訓練策略:
main()
U使用這個DataLab工作簿直接運行上述算法,並使用RL解決CartPole環境。
體育館的高級技術
我們已經演示了如何實現一個RL算法,現在我們討論一些在實踐中常用的進階技術。
使用預建的架構
從頭開始實現RL算法是一個長期且困難的過程,特別是對於複雜的環境和最先進的策略。
一個更實用的替代方案是使用軟件,如 Stable Baselines3。它具有經過驗證的強化學習算法實現。它包括預先訓練的代理、訓練腳本、評估工具和繪製圖表以及記錄視頻的模塊。
Ray RLib是另一個流行的強化學習工具。RLib 設計為可擴展解決方案,使在多GPU系統上實現強化學習算法變得容易。它還支持多代理強化學習,這帶來了新的可能性,例如:
- 獨立多代理學習:每個代理將其他代理視為環境的一部分。
- 協作式多智能體訓練:一組智能體共享相同的政策和價值函數,並且並行地從彼此的經驗中學習。
- 對抗訓練:智能體(或智能體組)在競爭性類遊戲環境中相互競爭。
在 RLib 和 Stable Baselines3 中,您可以導入並使用來自 OpenAI Gymnasium 的環境。
自定義環境
Gymnasium打包的环境是测试新RL策略和训练策略的正确选择。然而,对于大多数实际应用,您需要创建和使用一个准确反映您想要解决的问题的环境。您可以使用Gymnasium创建自定义环境。使用Gymnasium自定义环境的优势在于,许多外部工具如RLib和Stable Baselines3已配置为与Gymnasium API结构配合使用。
要在Gymnasium中创建自定义环境,您需要定义:
- 观察空间。
- 终止条件。
- 代理可以选择的动作集。
- 如何初始化环境(当调用
reset()
函数时)。 - 环境如何根据代理动作决定下一个状态(当调用
step()
函数时)。
要了解更多,请查看Gymnasium创建自定义环境指南。
使用Gymnasium的最佳实践
尝试不同的环境
這篇教程中的代碼展示了如何在CartPole環境中實現策略梯度算法。這是一個具有離散動作空間的簡單環境。為了更好地理解強化學習,我們建議您在其他環境中應用相同的策略梯度算法(以及其他算法,如PPO)。 PPO 其他環境。
例如,擺動環境具有連續的動作空間。它由一個輸入組成,表示為一個連續變數 – 在任何給定狀態下施加於擺動的(大小和方向的)扭矩。這個扭矩可以取任何值,範圍在 -2 到 +2 之間。
在不同環境中實驗不同的算法,有助於你更好地理解各種強化學習解決方案及其挑戰。
監控訓練進度
強化學習環境通常由機器人、擺錘、山地車、視頻遊戲等組成。在環境中可視化代理的行動,有助於更直觀地理解策略的表現。
在Gymnasium中,env.render()
方法可視化代理與環境的互動。它以圖形方式顯示環境的當前狀態——遊戲畫面、擺錘或小車的位置信息等。代理行動的視覺反饋及環境的反應有助於監控代理在訓練過程中的表現和進展。
有四種渲染模式:“human”、“rgb_array”、“ansi”和“rgb_array_list”。要可視化代理的表現,請使用“human”渲染模式。渲染模式在環境初始化時指定。例如:
env = gym.make(‘CartPole-v1’, render_mode=’human’)
要執行渲染,請在代理人執行每個動作後(通過調用.step()
方法)加入.render()
方法。下面的虛擬碼示例說明了如何執行此操作:
while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render() …
疑難排解常見錯誤
Gymnasium使得與複雜的RL環境進行交互變得容易。然而,它是一個帶有許多依賴項的持續更新軟件。因此,注意一些常見類型的錯誤是很重要的。
版本不匹配
- 體育館版本不匹配: Farama的體育館軟件包是從OpenAI的Gym 0.26.2版本分叉出來的。舊版Gym和新版Gymnasium之間存在一些重大更改。許多公開可用的實現是基於舊版Gym發行版,可能無法直接與最新發行版配合使用。在這種情況下,必須將安裝回滾到舊版本,或者適應新版本的代碼。
- 環境版本不匹配:許多 Gymnasium 環境有不同的版本。例如,有兩個 CartPole 環境 –
CartPole-v1
和CartPole-v0
。雖然兩個版本的環境行為相同,但某些參數,例如回合長度、獎勵閾值等,可能會有所不同。在一個版本上訓練的策略在同一環境的另一個版本上可能表現不佳。您需要更新訓練參數並為每個環境版本重新訓練策略。 - 依賴版本不一致: 體育館依賴於 NumPy 和 PyTorch 等依賴項。截至2024年12月,這些依賴的最新版本分別為
numpy 2.1.3
和torch 2.5.1
。然而,體育館最適用的版本是torch 1.13.0
和numpy 1.23.3
。如果您將體育館安裝到已預先安裝這些依賴項的環境中,可能會遇到問題。我們建議在一個全新的 Conda 環境中安裝並使用體育館。
收斂問題
- 超參數: 像其他機器學習算法一樣,強化學習策略對於超參數(如學習率、折扣因子等)非常敏感。我們建議通過手動實驗和調整超參數,或者使用像網格搜索和隨機搜索等自動化技術來進行調優。
- 探索與利用: 對於某些策略類型(如PPO),代理採用雙管齊下的策略:探索環境以發現新路徑,並根據迄今所知的路徑採用貪婪方法來最大化獎勵。如果探索過多,策略就無法收斂。相反,如果探索不夠,它就永遠不會嘗試最優路徑。因此,在探索和利用之間找到合適的平衡至關重要。在訓練過程中,通常會優先在早期情節中進行探索,而在後期情節中進行利用。
訓練不穩定
- 過大的學習率: 如果學習率過高,策略參數在每一步都會進行大幅更新。這可能導致錯過最佳值的集合。一個常見的解決方案是逐漸減少學習率,確保在訓練收斂時進行更小且更穩定的更新。
- 過度探索: 過多的隨機性(熵)在行動選擇中會妨礙收斂,並導致後續步驟之間損失函數的巨大變化。為了實現穩定且收斂的訓練過程,需平衡探索與利用。
- 錯誤的演算法選擇:對於具有大型行動和狀態空間的複雜環境,使用像PPO和Trust Region Policy Optimization (TRPO)這樣的更穩健的演算法比簡單的策略梯度可能會導致不穩定的訓練。這些演算法避免在每個步驟中進行大型策略更新,因此更穩定。
- 隨機性:強化學習演算法對於初始狀態和動作選擇的隨機性非常敏感。當訓練過程不穩定時,有時可以通過使用不同的隨機種子或重新初始化策略來穩定訓練過程。
結論
在本教程中,我們探討了強化學習的基本原則,討論了 Gymnasium 作為一個軟體套件,具有乾淨的 API 來與各種強化學習環境進行交互,並展示了如何編寫一個 Python 程式來實現一個簡單的強化學習算法並應用於 Gymnasium 環境中。
在本教程中理解基礎知識後,我建議使用 Gymnasium 環境將強化學習的概念應用於解決實際問題,如計程車路線優化和股票交易模擬。
Source:
https://www.datacamp.com/tutorial/reinforcement-learning-with-gymnasium