注意
轉到底部 下載完整的示例程式碼。
TorchRL 教程:多智慧體強化學習 (PPO)¶
作者: Matteo Bettini
另請參閱
BenchMARL 庫提供了使用 TorchRL 的最先進的 MARL 演算法實現。
本教程演示瞭如何使用 PyTorch 和 torchrl 來解決多智慧體強化學習 (MARL) 問題。
為了方便使用,本教程將遵循現有教程的一般結構:TorchRL 強化學習 (PPO) 教程。建議在開始本教程之前熟悉該教程,但並非強制要求。
在本教程中,我們將使用 VMAS 中的“導航”環境,這是一個多機器人模擬器,同樣基於 PyTorch,它在裝置上執行並行批處理模擬。
在“導航”環境中,我們需要訓練多個機器人(在隨機位置生成)導航到它們的目標(也在隨機位置),同時使用 LIDAR 感測器來避免相互碰撞。
多智慧體“導航”場景¶
主要學習內容
如何在 TorchRL 中建立多智慧體環境,它的規範如何工作,以及它如何與庫整合;
如何在 TorchRL 中使用 GPU 向量化環境;
如何在 TorchRL 中建立不同的多智慧體網路架構(例如,使用引數共享、集中式評論員)
我們如何使用
tensordict.TensorDict來承載多智慧體資料;如何將所有庫元件(收集器、模組、回放緩衝區和損失)整合到多智慧體 MAPPO/IPPO 訓練迴圈中。
如果您在 Google Colab 中執行此程式碼,請確保安裝以下依賴項
!pip3 install torchrl
!pip3 install vmas
!pip3 install tqdm
近端策略最佳化(PPO)是一種策略梯度演算法,它收集並直接消耗一批資料,以在存在某些近端約束的情況下最大化預期回報來訓練策略。您可以將其視為 REINFORCE(基礎策略最佳化演算法)的複雜版本。有關更多資訊,請參閱 近端策略最佳化演算法論文。
這類演算法通常是“*在策略上*”訓練的。這意味著在每次學習迭代中,我們都有一個**取樣**和一個**訓練**階段。在迭代 \(t\) 的**取樣**階段,使用當前策略 \(\mathbf{\pi}_t\) 從智慧體與環境的互動中收集的軌跡。在**訓練**階段,所有收集到的軌跡會立即饋送到訓練過程以執行反向傳播。這會導致策略更新,然後再次用於取樣。該過程的迴圈執行構成了“*在策略上學習*”。
在策略上學習¶
在 PPO 演算法的訓練階段,會使用一個*評論員*來估計策略所採取行動的好壞。評論員學習近似特定狀態的價值(折扣回報的平均值)。然後,PPO 損失將策略獲得的實際回報與評論員估計的回報進行比較,以確定所採取行動的優勢,並指導策略最佳化。
在多智慧體環境中,情況有所不同。我們現在有多個策略 \(\mathbf{\pi}\),每個智慧體一個。策略通常是區域性的和分散的。這意味著單個智慧體的策略將僅基於其觀察值輸出該智慧體的行動。在 MARL 文獻中,這被稱為**分散式執行**。另一方面,評論員存在不同的表述,主要有:
在 MAPPO 中,評論員是集中的,並且將系統的全域性狀態作為輸入。這可以是全域性觀察,或者是智慧體觀察的簡單拼接。MAPPO 可用於執行**集中式訓練**的場景,因為它需要訪問全域性資訊。
在 IPPO 中,評論員只接收相應智慧體的觀察作為輸入,這與策略完全相同。這允許**分散式訓練**,因為評論員和策略都只需要本地資訊來計算它們的輸出。
集中式評論員有助於克服多個智慧體同時學習時的非平穩性,但另一方面,它們可能會受到其巨大輸入空間的影響。在本教程中,我們將能夠訓練這兩種表述,我們還將討論引數共享(跨智慧體共享網路引數的做法)如何影響每一種。
本教程結構如下
首先,我們將定義一組將要使用的超引數。
接下來,我們將建立一個向量化多智慧體環境,使用 TorchRL 對 VMAS 模擬器的包裝器。
接下來,我們將設計策略和評論員網路,討論各種選擇對引數共享和評論員中心化的影響。
接下來,我們將建立取樣收集器和回放緩衝區。
最後,我們將執行訓練迴圈並分析結果。
如果您在 Colab 或帶有 GUI 的機器上執行此程式,您還可以選擇在訓練您的策略之前和之後渲染和視覺化它。
讓我們匯入我們的依賴項
# Torch
import torch
# Tensordict modules
from tensordict.nn import set_composite_lp_aggregate, TensorDictModule
from tensordict.nn.distributions import NormalParamExtractor
from torch import multiprocessing
# Data collection
from torchrl.collectors import SyncDataCollector
from torchrl.data.replay_buffers import ReplayBuffer
from torchrl.data.replay_buffers.samplers import SamplerWithoutReplacement
from torchrl.data.replay_buffers.storages import LazyTensorStorage
# Env
from torchrl.envs import RewardSum, TransformedEnv
from torchrl.envs.libs.vmas import VmasEnv
from torchrl.envs.utils import check_env_specs
# Multi-agent network
from torchrl.modules import MultiAgentMLP, ProbabilisticActor, TanhNormal
# Loss
from torchrl.objectives import ClipPPOLoss, ValueEstimators
# Utils
torch.manual_seed(0)
from matplotlib import pyplot as plt
from tqdm import tqdm
定義超引數¶
我們設定本教程的超引數。根據可用資源,可以選擇在 GPU 或其他裝置上執行策略和模擬器。您可以調整其中一些值來調整計算需求。
# Devices
is_fork = multiprocessing.get_start_method() == "fork"
device = (
torch.device(0)
if torch.cuda.is_available() and not is_fork
else torch.device("cpu")
)
vmas_device = device # The device where the simulator is run (VMAS can run on GPU)
# Sampling
frames_per_batch = 6_000 # Number of team frames collected per training iteration
n_iters = 5 # Number of sampling and training iterations
total_frames = frames_per_batch * n_iters
# Training
num_epochs = 30 # Number of optimization steps per training iteration
minibatch_size = 400 # Size of the mini-batches in each optimization step
lr = 3e-4 # Learning rate
max_grad_norm = 1.0 # Maximum norm for the gradients
# PPO
clip_epsilon = 0.2 # clip value for PPO loss
gamma = 0.99 # discount factor
lmbda = 0.9 # lambda for generalised advantage estimation
entropy_eps = 1e-4 # coefficient of the entropy term in the PPO loss
# disable log-prob aggregation
set_composite_lp_aggregate(False).set()
環境¶
多智慧體環境模擬多個智慧體與世界互動。TorchRL API 允許整合各種型別多智慧體環境。一些例子包括具有共享或個體獎勵、完成標誌和觀察的環境。有關 TorchRL 中多智慧體環境 API 如何工作的更多資訊,您可以檢視專門的文件部分。
VMAS 模擬器尤其如此,它使用個體獎勵、資訊、觀察和動作來模擬智慧體,但有一個集體完成標誌。此外,它使用*向量化*來在批次中執行模擬。這意味著其所有狀態和物理都是 PyTorch 張量,第一維表示批次中的並行環境數量。這允許利用 GPU 的單指令多資料 (SIMD) 範例,並透過利用 GPU warp 中的並行化來顯著加快平行計算速度。這也意味著,在 TorchRL 中使用它時,模擬和訓練都可以**在裝置上**執行,而無需將資料傳遞到 CPU。
我們今天將要解決的多智慧體任務是“導航”(見上面的動畫圖)。在“導航”任務中,隨機生成的智慧體(帶有點的圓圈)需要導航到隨機生成的(較小的)目標圓圈。智慧體需要使用 LIDAR(周圍的點)來避免相互碰撞。智慧體在一個具有拖拽和彈性碰撞的 2D 連續世界中行動。它們的行動是 2D 連續力,決定了它們的加速度。獎勵由三部分組成:碰撞懲罰、基於到目標距離的獎勵,以及當所有智慧體都到達目標時給出的最終共享獎勵。基於距離的部分計算為智慧體與其目標在兩個連續時間步之間的相對距離之差。每個智慧體觀察其位置、速度、LIDAR 讀數以及到其目標的相對位置。
我們將例項化環境。在本教程中,我們將把**劇集限制為** max_steps,之後將設定完成標誌。這是 VMAS 模擬器已經提供的功能,但 TorchRL 的 StepCount 轉換也可以使用。我們還將使用 num_vmas_envs 個向量化環境,以利用批處理模擬。
max_steps = 100 # Episode steps before done
num_vmas_envs = (
frames_per_batch // max_steps
) # Number of vectorized envs. frames_per_batch should be divisible by this number
scenario_name = "navigation"
n_agents = 3
env = VmasEnv(
scenario=scenario_name,
num_envs=num_vmas_envs,
continuous_actions=True, # VMAS supports both continuous and discrete actions
max_steps=max_steps,
device=vmas_device,
# Scenario kwargs
n_agents=n_agents, # These are custom kwargs that change for each VMAS scenario, see the VMAS repo to know more.
)
環境不僅由其模擬器和轉換定義,還由一系列描述其執行過程中可預期內容的元資料定義。為了效率起見,TorchRL 在環境規範方面非常嚴格,但您可以輕鬆檢查您的環境規範是否合適。在我們的示例中,VmasEnv 負責為您的環境設定正確的規範,因此您不必擔心這個問題。
有四個規範需要關注
action_spec定義了動作空間;reward_spec定義了獎勵域;done_spec定義了完成域;observation_spec定義了環境步驟所有其他輸出的域;
print("action_spec:", env.full_action_spec)
print("reward_spec:", env.full_reward_spec)
print("done_spec:", env.full_done_spec)
print("observation_spec:", env.observation_spec)
使用上面顯示的命令,我們可以訪問每個值的域。這樣做,我們可以看到除了完成之外的所有規範都帶有前導形狀 (num_vmas_envs, n_agents)。這代表了每個環境中每個智慧體都會存在這些值。另一方面,完成規範帶有前導形狀 num_vmas_envs,代表完成是在智慧體之間共享的。
TorchRL 有一種方法可以跟蹤哪些 MARL 規範是共享的,哪些不是。實際上,具有附加智慧體維度(即,它們對每個智慧體都不同)的規範將包含在一個內部“agents”鍵中。
正如你所見,獎勵和動作規範呈現了“agent”鍵,這意味著屬於這些規範的 tensordicts 中的條目將巢狀在一個“agents” tensordict 中,將所有每個智慧體的值分組。
要快速訪問 tensordicts 中每個值的鍵,我們可以簡單地向環境詢問相應的鍵,我們就會立即瞭解哪些是每個智慧體的值,哪些是共享的。此資訊將有助於我們告訴所有其他 TorchRL 元件在哪裡找到每個值
print("action_keys:", env.action_keys)
print("reward_keys:", env.reward_keys)
print("done_keys:", env.done_keys)
變換 (Transforms)¶
我們可以附加任何我們需要的 TorchRL 轉換到我們的環境中。這些轉換將以某種期望的方式修改其輸入/輸出。我們強調,在多智慧體上下文中,顯式提供要修改的鍵是至關重要的。
例如,在這種情況下,我們將例項化一個 RewardSum 轉換,它將對整個劇集的獎勵求和。我們將告訴此轉換在哪裡找到獎勵鍵以及在哪裡寫入求和的劇集獎勵。轉換後的環境將繼承包裝環境的裝置和元資料,並根據其包含的轉換序列來轉換它們。
env = TransformedEnv(
env,
RewardSum(in_keys=[env.reward_key], out_keys=[("agents", "episode_reward")]),
)
該 check_env_specs() 函式執行一個小的回滾,並將其輸出與環境規範進行比較。如果沒有引發錯誤,我們可以確信規範已正確定義。
check_env_specs(env)
回滾 (Rollout)¶
為了好玩,讓我們看看一個簡單的隨機回滾是什麼樣的。您可以呼叫 env.rollout(n_steps) 並獲得環境輸入和輸出外觀的概覽。動作將自動從動作規範域中隨機抽取。
n_rollout_steps = 5
rollout = env.rollout(n_rollout_steps)
print("rollout of three steps:", rollout)
print("Shape of the rollout TensorDict:", rollout.batch_size)
我們可以看到我們的回滾具有 batch_size 為 (num_vmas_envs, n_rollout_steps)。這意味著其中所有張量都將具有這些前導維度。
更深入地看,我們可以看到輸出 tensordict 可以這樣劃分
在根目錄(可透過執行
rollout.exclude("next")訪問)我們將找到在第一次呼叫 reset 後可用的所有鍵。我們可以透過索引n_rollout_steps維度來檢視它們在回滾步驟中的演變。在這些鍵中,我們將找到在rollout["agents"]tensordict 中每個智慧體都不同的鍵,它將具有(num_vmas_envs, n_rollout_steps, n_agents)的批處理大小,表示它儲存了附加的智慧體維度。在此智慧體 tensordict 之外的那些將是共享的(在本例中只有完成)。在 next(可透過執行
rollout.get("next")訪問)。我們將找到與根目錄相同的結構,但對於僅在步驟後可用的鍵。
在 TorchRL 中,慣例是 done 和 observations 會同時出現在根目錄和 next 中(因為它們在重置時間和步驟之後都可用)。Action 只在根目錄中可用(因為步驟沒有動作),Reward 只在 next 中可用(因為重置時間沒有獎勵)。此結構遵循**強化學習:導論(Sutton 和 Barto)**中的結構,其中根目錄表示時間 \(t\) 的資料,next 表示世界步驟時間 \(t+1\) 的資料。
渲染隨機回滾¶
如果您正在 Google Colab 或具有 OpenGL 和 GUI 的機器上執行,您實際上可以渲染一個隨機回滾。這將讓您大致瞭解隨機策略在此任務中將實現的目標,以便與您自己訓練的策略進行比較!
要渲染回滾,請遵循本教程末尾“渲染”部分中的說明,只需從 env.rollout() 中刪除 policy=policy 行即可。
策略 (Policy)¶
PPO 利用隨機策略來處理探索。這意味著我們的神經網路將不得不輸出分佈的引數,而不是對應於所採取行動的單個值。
由於資料是連續的,我們使用 Tanh-Normal 分佈來遵守動作空間邊界。TorchRL 提供了這種分佈,我們唯一需要關心的是構建一個輸出正確數量引數的神經網路。
在這種情況下,每個智慧體的動作將由一個 2 維獨立正態分佈表示。為此,我們的神經網路將需要為每個動作輸出一個均值和一個標準差。因此,每個智慧體將有 2 * n_actions_per_agents 個輸出。
我們需要做出的另一個重要決定是是否希望我們的智慧體**共享策略引數**。一方面,共享引數意味著它們將共享相同的策略,這將使它們能夠從彼此的經驗中受益。這還將導致更快的訓練。另一方面,它將使它們在行為上“*同質化*”,因為它們實際上將共享相同的模型。在此示例中,我們將啟用共享,因為我們不介意同質化並且可以從計算速度中受益,但在您自己的問題中,始終考慮此決定非常重要!
我們分三個步驟設計策略。
第一步:定義一個神經網路 n_obs_per_agent -> 2 * n_actions_per_agents
為此,我們使用 MultiAgentMLP,這是一個專門為多個智慧體設計的 TorchRL 模組,具有許多可定製的選項。
share_parameters_policy = True
policy_net = torch.nn.Sequential(
MultiAgentMLP(
n_agent_inputs=env.observation_spec["agents", "observation"].shape[
-1
], # n_obs_per_agent
n_agent_outputs=2
* env.full_action_spec[env.action_key].shape[-1], # 2 * n_actions_per_agents
n_agents=env.n_agents,
centralised=False, # the policies are decentralised (ie each agent will act from its observation)
share_params=share_parameters_policy,
device=device,
depth=2,
num_cells=256,
activation_class=torch.nn.Tanh,
),
NormalParamExtractor(), # this will just separate the last dimension into two outputs: a loc and a non-negative scale
)
第二步:將神經網路包裝在 TensorDictModule 中
這只是一個模組,它將從 tensordict 中讀取 in_keys,將它們饋送到神經網路,並將輸出原地寫入 out_keys。
請注意,我們使用 ("agents", ...) 鍵,因為這些鍵表示帶有附加 n_agents 維度的資料。
policy_module = TensorDictModule(
policy_net,
in_keys=[("agents", "observation")],
out_keys=[("agents", "loc"), ("agents", "scale")],
)
第三步:將 TensorDictModule 包裝在 ProbabilisticActor 中
現在我們需要從正態分佈的均值和標準差構建一個分佈。為此,我們指示 ProbabilisticActor 類從均值和標準差引數構建一個 TanhNormal。我們還提供了此分佈的最小值和最大值,我們從環境規範中獲取這些值。
in_keys 的名稱(因此也是上面 TensorDictModule 的 out_keys 的名稱)必須以 TanhNormal 分佈建構函式的關鍵字引數(loc 和 scale)結尾。
policy = ProbabilisticActor(
module=policy_module,
spec=env.action_spec_unbatched,
in_keys=[("agents", "loc"), ("agents", "scale")],
out_keys=[env.action_key],
distribution_class=TanhNormal,
distribution_kwargs={
"low": env.full_action_spec_unbatched[env.action_key].space.low,
"high": env.full_action_spec_unbatched[env.action_key].space.high,
},
return_log_prob=True,
) # we'll need the log-prob for the PPO loss
評論員網路¶
評論員網路是 PPO 演算法的一個關鍵組成部分,儘管它在取樣時並不使用。此模組將讀取觀察值並返回相應的價值估計。
與之前一樣,人們應該仔細考慮**共享評論員引數**的決定。一般來說,引數共享將帶來更快的訓練收斂速度,但有幾個重要考慮因素:
不建議在智慧體具有不同獎勵函式時共享,因為評論員需要學習為同一狀態分配不同的值(例如,在混合合作-競爭場景中)。
在分散式訓練設定中,在沒有額外基礎設施來同步引數的情況下無法進行共享。
在所有其他情況下,當所有智慧體的獎勵函式(與獎勵不同)相同時(如當前場景),共享可以提供改進的效能。這可能會以智慧體策略同質化的代價為代價。一般來說,瞭解哪種選擇更優的最佳方法是快速嘗試這兩種選項。
這裡也是我們必須在**MAPPO 和 IPPO**之間進行選擇的地方
使用 MAPPO,我們將獲得一個具有完全可觀測性的集中式評論員(即,它將以所有智慧體觀察值的拼接作為輸入)。由於我們處於模擬器中且訓練是集中的,因此我們可以這樣做。
使用 IPPO,我們將擁有一個區域性的分散式評論員,就像策略一樣。
無論哪種情況,評論員輸出的形狀都將是 (..., n_agents, 1)。如果評論員是集中的並且是共享的,那麼 n_agents 維度的所有值都將是相同的。
share_parameters_critic = True
mappo = True # IPPO if False
critic_net = MultiAgentMLP(
n_agent_inputs=env.observation_spec["agents", "observation"].shape[-1],
n_agent_outputs=1, # 1 value per agent
n_agents=env.n_agents,
centralised=mappo,
share_params=share_parameters_critic,
device=device,
depth=2,
num_cells=256,
activation_class=torch.nn.Tanh,
)
critic = TensorDictModule(
module=critic_net,
in_keys=[("agents", "observation")],
out_keys=[("agents", "state_value")],
)
讓我們試試我們的策略和評論員模組。如前所述,使用 TensorDictModule 可以直接讀取環境的輸出來執行這些模組,因為它們知道要讀取哪些資訊以及在哪裡寫入它們
從這一點開始,多智慧體特定的元件已經例項化,我們將簡單地使用與單智慧體學習相同的元件。這不是很棒嗎?
print("Running policy:", policy(env.reset()))
print("Running value:", critic(env.reset()))
資料收集器 (Data collector)¶
TorchRL 提供了一組資料收集器類。簡而言之,這些類執行三個操作:重置環境、使用策略和最新觀察值計算動作、在環境中執行一步,並重復最後兩個步驟,直到環境發出停止訊號(或達到完成狀態)。
我們將使用最簡單的資料收集器,它具有與環境回滾相同的輸出,唯一的區別是它將自動重置完成狀態,直到收集到所需的幀數。
collector = SyncDataCollector(
env,
policy,
device=vmas_device,
storing_device=device,
frames_per_batch=frames_per_batch,
total_frames=total_frames,
)
回放緩衝區 (Replay buffer)¶
回放緩衝區是離策略 RL 演算法的常見構建模組。在策略環境中,每當收集一批資料時,回放緩衝區就會被重新填充,並且其資料會在一定數量的 epoch 中被重複消耗。
為 PPO 使用回放緩衝區並非強制要求,我們可以簡單地線上使用收集到的資料,但使用這些類可以讓我們輕鬆地以可重現的方式構建內部訓練迴圈。
replay_buffer = ReplayBuffer(
storage=LazyTensorStorage(
frames_per_batch, device=device
), # We store the frames_per_batch collected at each iteration
sampler=SamplerWithoutReplacement(),
batch_size=minibatch_size, # We will sample minibatches of this size
)
損失函式 (Loss function)¶
PPO 損失可以直接從 TorchRL 匯入,以便於使用 ClipPPOLoss 類。這是利用 PPO 最簡單的方法:它隱藏了 PPO 的數學運算以及與之相關的控制流。
PPO 需要一些“優勢估計”來計算。簡而言之,優勢是一個反映回報值期望的(在處理偏差/方差權衡時)。要計算優勢,只需(1)構建優勢模組,它利用我們的價值運算子,以及(2)在每個 epoch 之前將每個資料批次透過它。GAE 模組將使用新的 "advantage" 和 "value_target" 條目更新輸入 TensorDict。“value_target”是一個無梯度張量,表示價值網路應表示的帶有輸入觀察值的經驗值。這兩者都將由 ClipPPOLoss 用來返回策略和價值損失。
loss_module = ClipPPOLoss(
actor_network=policy,
critic_network=critic,
clip_epsilon=clip_epsilon,
entropy_coef=entropy_eps,
normalize_advantage=False, # Important to avoid normalizing across the agent dimension
)
loss_module.set_keys( # We have to tell the loss where to find the keys
reward=env.reward_key,
action=env.action_key,
value=("agents", "state_value"),
# These last 2 keys will be expanded to match the reward shape
done=("agents", "done"),
terminated=("agents", "terminated"),
)
loss_module.make_value_estimator(
ValueEstimators.GAE, gamma=gamma, lmbda=lmbda
) # We build GAE
GAE = loss_module.value_estimator
optim = torch.optim.Adam(loss_module.parameters(), lr)
訓練迴圈¶
現在我們有了編寫訓練迴圈所需的所有元件。步驟包括
- 收集資料
- 計算優勢
- 遍歷 epoch
- 遍歷 minibatch 來計算損失值
反向傳播
最佳化
重複
重複
重複
重複
pbar = tqdm(total=n_iters, desc="episode_reward_mean = 0")
episode_reward_mean_list = []
for tensordict_data in collector:
tensordict_data.set(
("next", "agents", "done"),
tensordict_data.get(("next", "done"))
.unsqueeze(-1)
.expand(tensordict_data.get_item_shape(("next", env.reward_key))),
)
tensordict_data.set(
("next", "agents", "terminated"),
tensordict_data.get(("next", "terminated"))
.unsqueeze(-1)
.expand(tensordict_data.get_item_shape(("next", env.reward_key))),
)
# We need to expand the done and terminated to match the reward shape (this is expected by the value estimator)
with torch.no_grad():
GAE(
tensordict_data,
params=loss_module.critic_network_params,
target_params=loss_module.target_critic_network_params,
) # Compute GAE and add it to the data
data_view = tensordict_data.reshape(-1) # Flatten the batch size to shuffle data
replay_buffer.extend(data_view)
for _ in range(num_epochs):
for _ in range(frames_per_batch // minibatch_size):
subdata = replay_buffer.sample()
loss_vals = loss_module(subdata)
loss_value = (
loss_vals["loss_objective"]
+ loss_vals["loss_critic"]
+ loss_vals["loss_entropy"]
)
loss_value.backward()
torch.nn.utils.clip_grad_norm_(
loss_module.parameters(), max_grad_norm
) # Optional
optim.step()
optim.zero_grad()
collector.update_policy_weights_()
# Logging
done = tensordict_data.get(("next", "agents", "done"))
episode_reward_mean = (
tensordict_data.get(("next", "agents", "episode_reward"))[done].mean().item()
)
episode_reward_mean_list.append(episode_reward_mean)
pbar.set_description(f"episode_reward_mean = {episode_reward_mean}", refresh=False)
pbar.update()
結果 (Results)¶
讓我們繪製每集獲得的平均獎勵
為了讓訓練持續更長時間,請增加 n_iters 超引數。
plt.plot(episode_reward_mean_list)
plt.xlabel("Training iterations")
plt.ylabel("Reward")
plt.title("Episode reward mean")
plt.show()
渲染¶
如果您在帶有 GUI 的機器上執行此程式,您可以透過執行以下命令來渲染訓練好的策略:
with torch.no_grad():
env.rollout(
max_steps=max_steps,
policy=policy,
callback=lambda env, _: env.render(),
auto_cast_to_device=True,
break_when_any_done=False,
)
如果您正在 Google Colab 上執行此程式,您可以透過執行以下命令來渲染訓練好的策略:
!apt-get update
!apt-get install -y x11-utils
!apt-get install -y xvfb
!pip install pyvirtualdisplay
import pyvirtualdisplay
display = pyvirtualdisplay.Display(visible=False, size=(1400, 900))
display.start()
from PIL import Image
def rendering_callback(env, td):
env.frames.append(Image.fromarray(env.render(mode="rgb_array")))
env.frames = []
with torch.no_grad():
env.rollout(
max_steps=max_steps,
policy=policy,
callback=rendering_callback,
auto_cast_to_device=True,
break_when_any_done=False,
)
env.frames[0].save(
f"{scenario_name}.gif",
save_all=True,
append_images=env.frames[1:],
duration=3,
loop=0,
)
from IPython.display import Image
Image(open(f"{scenario_name}.gif", "rb").read())
結論和後續步驟¶
在本教程中,我們看到了
如何在 TorchRL 中建立多智慧體環境,它的規範如何工作,以及它如何與庫整合;
如何在 TorchRL 中使用 GPU 向量化環境;
如何在 TorchRL 中建立不同的多智慧體網路架構(例如,使用引數共享、集中式評論員)
我們如何使用
tensordict.TensorDict來承載多智慧體資料;如何將所有庫元件(收集器、模組、回放緩衝區和損失)整合到多智慧體 MAPPO/IPPO 訓練迴圈中。
現在您已經精通多智慧體 DDPG,您可以檢視 GitHub 倉庫中的所有 TorchRL 多智慧體實現。這些是許多流行 MARL 演算法的程式碼指令碼,例如本教程中看到的演算法、QMIX、MADDPG、IQL 等等!
您還可以檢視我們關於如何在 PettingZoo/VMAS 中訓練具有多個智慧體組的競爭性 MADDPG/IDDPG 的多智慧體教程:TorchRL 教程:競爭性多智慧體強化學習 (DDPG)。
如果您有興趣在 TorchRL 中建立或包裝自己的多智慧體環境,您可以檢視專門的文件部分。
最後,您可以修改本教程的引數來嘗試許多其他配置和場景,成為 MARL 大師。以下是一些 VMAS 中可用場景的影片。