基本用法¶
什麼是強化學習?¶
在深入瞭解 Gymnasium 之前,讓我們先了解我們想要實現什麼。強化學習就像透過試錯進行教學——智慧體透過嘗試動作、接收反饋(獎勵)並逐步改進其行為來學習。想象一下用零食訓練寵物,透過練習學習騎腳踏車,或者透過反覆玩遊戲來掌握影片遊戲。
關鍵在於我們不告訴智慧體具體該做什麼。相反,我們建立一個環境,讓它可以在其中安全地進行實驗,並從其行為的後果中學習。
為什麼選擇 Gymnasium?¶
無論您是想訓練智慧體玩遊戲、控制機器人還是最佳化交易策略,Gymnasium 都為您提供了構建和測試想法的工具。其核心是,Gymnasium 為所有單智慧體強化學習環境提供了一個 API(應用程式程式設計介面),並實現了常見的環境:CartPole、Pendulum、Mountain Car、Mujoco、Atari 等。本頁將概述如何使用 Gymnasium 的基礎知識,包括其四個關鍵函式:make()、Env.reset()、Env.step() 和 Env.render()。
Gymnasium 的核心是 Env,一個表示強化學習理論中馬爾可夫決策過程(MDP)的高階 Python 類(注意:這不是一個完美的重構,缺少 MDP 的幾個元件)。該類為使用者提供了開始新情節、採取行動和視覺化智慧體當前狀態的能力。除了 Env,還提供了 Wrapper 來幫助增強/修改環境,特別是智慧體觀察、獎勵和所採取的行動。
初始化環境¶
在 Gymnasium 中初始化環境非常簡單,可以透過 make() 函式完成
import gymnasium as gym
# Create a simple environment perfect for beginners
env = gym.make('CartPole-v1')
# The CartPole environment: balance a pole on a moving cart
# - Simple but not trivial
# - Fast training
# - Clear success/failure criteria
此函式將返回一個 Env 供使用者互動。要檢視可以建立的所有環境,請使用 pprint_registry()。此外,make() 還提供了許多附加引數,用於為環境指定關鍵字、新增更多或更少包裝器等。有關更多資訊,請參閱 make()。
理解智慧體-環境迴圈¶
在強化學習中,下方所示的經典“智慧體-環境迴圈”代表了 RL 中學習的發生方式。它比初看起來要簡單
智慧體觀察當前情況(例如看著遊戲螢幕)
智慧體根據所看到的內容選擇一個動作(例如按下按鈕)
環境響應新的情況和獎勵(遊戲狀態改變,分數更新)
重複直到情節結束
這看起來可能很簡單,但智慧體就是這樣學會從下棋到控制機器人再到最佳化業務流程的一切的。
您的第一個強化學習程式¶
讓我們從一個使用 CartPole 的簡單示例開始——非常適合理解基礎知識
# Run `pip install "gymnasium[classic-control]"` for this example.
import gymnasium as gym
# Create our training environment - a cart with a pole that needs balancing
env = gym.make("CartPole-v1", render_mode="human")
# Reset environment to start a new episode
observation, info = env.reset()
# observation: what the agent can "see" - cart position, velocity, pole angle, etc.
# info: extra debugging information (usually not needed for basic learning)
print(f"Starting observation: {observation}")
# Example output: [ 0.01234567 -0.00987654 0.02345678 0.01456789]
# [cart_position, cart_velocity, pole_angle, pole_angular_velocity]
episode_over = False
total_reward = 0
while not episode_over:
# Choose an action: 0 = push cart left, 1 = push cart right
action = env.action_space.sample() # Random action for now - real agents will be smarter!
# Take the action and see what happens
observation, reward, terminated, truncated, info = env.step(action)
# reward: +1 for each step the pole stays upright
# terminated: True if pole falls too far (agent failed)
# truncated: True if we hit the time limit (500 steps)
total_reward += reward
episode_over = terminated or truncated
print(f"Episode finished! Total reward: {total_reward}")
env.close()
您應該看到什麼:一個視窗開啟,顯示一個帶杆的推車。推車隨機左右移動,杆最終會倒下。這是預期的——智慧體正在隨機行動!
逐步解釋程式碼¶
首先,使用 make() 建立一個環境,並帶有一個可選的 "render_mode" 引數,該引數指定環境應如何視覺化。有關不同渲染模式的詳細資訊,請參閱 Env.render()。渲染模式決定您看到的是視覺化視窗(“human”)、獲取影像陣列(“rgb_array”),還是無視覺執行(None - 訓練最快)。
初始化環境後,我們 Env.reset() 環境以獲取第一個觀察以及附加資訊。這就像開始一個新遊戲或新情節。要使用特定隨機種子或選項初始化環境(有關可能的值,請參閱環境文件),請使用 reset() 的 seed 或 options 引數。
由於我們希望智慧體-環境迴圈繼續進行直到環境結束(這發生在未知數量的時間步中),我們將 episode_over 定義為一個變數來控制我們的 while 迴圈。
接下來,智慧體在環境中執行一個動作。Env.step() 執行選定的動作(在我們的示例中,使用 env.action_space.sample() 隨機選擇動作)來更新環境。這個動作可以想象成移動機器人、按下游戲控制器上的按鈕或做出交易決策。結果,智慧體從更新後的環境接收到新的觀察,以及採取動作的獎勵。這個獎勵對於好的動作(例如成功平衡杆)可能是正面的,對於壞的動作(例如讓杆倒下)可能是負面的。這種動作-觀察的交換被稱為一個時間步。
然而,經過一些時間步後,環境可能會結束——這被稱為終止狀態。例如,機器人可能已經墜毀,或成功完成了任務,或者我們可能希望在固定數量的時間步後停止。在 Gymnasium 中,如果環境因任務完成或失敗而終止,則 step() 會返回 terminated=True。如果我們希望環境在固定數量的時間步後結束(例如時間限制),環境會發出 truncated=True 訊號。如果 terminated 或 truncated 中的任何一個為 True,我們就結束這一情節。在大多數情況下,您會希望使用 env.reset() 重新啟動環境以開始新的情節。
動作空間和觀察空間¶
每個環境都透過 action_space 和 observation_space 屬性指定有效動作和觀察的格式。這有助於瞭解環境的預期輸入和輸出,因為所有有效動作和觀察都應包含在各自的空間內。在上面的示例中,我們透過 env.action_space.sample() 取樣隨機動作,而不是使用將觀察對映到動作的智慧代理策略(這就是您將要學習構建的內容)。
理解這些空間對於構建智慧體至關重要: - 動作空間:您的智慧體能做什麼?(離散選擇、連續值等) - 觀察空間:您的智慧體能看到什麼?(影像、數字、結構化資料等)
重要的是,Env.action_space 和 Env.observation_space 都是 Space 的例項,這是一個提供關鍵函式 Space.contains() 和 Space.sample() 的高階 Python 類。Gymnasium 支援多種空間
Box:描述具有任何 n 維形狀的上限和下限的有界空間(如連續控制或影像畫素)。Discrete:描述一個離散空間,其中{0, 1, ..., n-1}是可能的值(如按鈕按下或選單選擇)。MultiBinary:描述任何 n 維形狀的二進位制空間(如多個開關)。MultiDiscrete:由一系列Discrete動作空間組成,每個元素中有不同數量的動作。Text:描述一個具有最小和最大長度的字串空間。Dict:描述一個更簡單空間字典(如您稍後將看到的 GridWorld 示例)。Tuple:描述一個簡單空間的元組。Graph:描述一個具有相互連線的節點和邊的數學圖(網路)。Sequence:描述可變長度的簡單空間元素。
讓我們看一些例子
import gymnasium as gym
# Discrete action space (button presses)
env = gym.make("CartPole-v1")
print(f"Action space: {env.action_space}") # Discrete(2) - left or right
print(f"Sample action: {env.action_space.sample()}") # 0 or 1
# Box observation space (continuous values)
print(f"Observation space: {env.observation_space}") # Box with 4 values
# Box([-4.8, -inf, -0.418, -inf], [4.8, inf, 0.418, inf])
print(f"Sample observation: {env.observation_space.sample()}") # Random valid observation
修改環境¶
包裝器是一種修改現有環境而無需直接更改底層程式碼的便捷方式。將包裝器視為過濾器或修改器,它們改變您與環境互動的方式。使用包裝器可以避免重複程式碼,並使您的環境更具模組化。包裝器還可以連結以組合其效果。
大多數透過 gymnasium.make() 建立的環境將預設被 TimeLimit(在最大步數後停止情節)、OrderEnforcing(確保正確的重置/步進順序)和 PassiveEnvChecker(驗證您的環境使用)包裝。
要包裝環境,您首先初始化一個基礎環境,然後將其連同可選引數傳遞給包裝器的建構函式
>>> import gymnasium as gym
>>> from gymnasium.wrappers import FlattenObservation
>>> # Start with a complex observation space
>>> env = gym.make("CarRacing-v3")
>>> env.observation_space.shape
(96, 96, 3) # 96x96 RGB image
>>> # Wrap it to flatten the observation into a 1D array
>>> wrapped_env = FlattenObservation(env)
>>> wrapped_env.observation_space.shape
(27648,) # All pixels in a single array
>>> # This makes it easier to use with some algorithms that expect 1D input
初學者認為有用的常見包裝器
TimeLimit:如果超過最大時間步數,則發出截斷訊號(防止無限情節)。ClipAction:將傳遞給step的任何動作裁剪,以確保其在有效動作空間內。RescaleAction:將動作重新縮放到不同的範圍(對於輸出動作在 [-1, 1] 而環境需要 [0, 10] 的演算法很有用)。TimeAwareObservation:將當前時間步的資訊新增到觀察中(有時有助於學習)。
有關 Gymnasium 中已實現包裝器的完整列表,請參閱包裝器。
如果您有一個被包裝的環境,並且想要訪問所有包裝層下面的原始環境(以便手動呼叫函式或更改某些底層方面),您可以使用 unwrapped 屬性。如果環境已經是基礎環境,unwrapped 只會返回其自身。
>>> wrapped_env
<FlattenObservation<TimeLimit<OrderEnforcing<PassiveEnvChecker<CarRacing<CarRacing-v3>>>>>>
>>> wrapped_env.unwrapped
<gymnasium.envs.box2d.car_racing.CarRacing object at 0x7f04efcb8850>
初學者常見問題¶
智慧體行為
智慧體隨機表現:使用
env.action_space.sample()時這是預期的!真正的學習發生在您用智慧策略替換它時情節立即結束:檢查您是否在情節之間正確處理了重置
常見程式碼錯誤
# ❌ Wrong - forgetting to reset
env = gym.make("CartPole-v1")
obs, reward, terminated, truncated, info = env.step(action) # Error!
# ✅ Correct - always reset first
env = gym.make("CartPole-v1")
obs, info = env.reset() # Start properly
obs, reward, terminated, truncated, info = env.step(action) # Now this works
下一步¶
現在您已經瞭解了基礎知識,您可以
訓練一個真正的智慧體 - 用智慧取代隨機動作
建立自定義環境 - 構建您自己的強化學習問題
錄製智慧體行為 - 儲存訓練影片和資料
加速訓練 - 使用向量化環境和其他最佳化