注意
跳轉到結尾 以下載完整的示例程式碼。
TorchRL 模組入門¶
注意
要在 notebook 中執行本教程,請在開頭新增一個安裝單元格,其中包含:
!pip install tensordict !pip install torchrl
強化學習旨在建立能夠有效應對特定任務的策略。策略可以採取多種形式,從將觀測空間對映到動作空間的微分對映,到更臨時的 F方法,例如對為每個可能動作計算的值列表取 argmax。策略可以是確定性的或隨機的,並且可以包含複雜的元素,例如迴圈神經網路 (RNN) 或 Transformer。
容納所有這些場景可能相當複雜。在本簡潔的教程中,我們將深入探討 TorchRL 在策略構建方面 の核心功能。我們將主要關注兩種常見場景下的隨機策略和 Q 值策略:使用多層感知機 (MLP) 或卷積神經網路 (CNN) 作為骨幹網路。
TensorDictModules¶
與環境與 `TensorDict` 例項互動的方式類似,用於表示策略和價值函式的模組也執行相同的操作。核心思想很簡單:將標準的 `torch.nn.Module`(或任何其他函式)封裝在一個類中,該類知道哪些條目需要被讀取並傳遞給模組,然後使用指定的條目記錄結果。為了說明這一點,我們將使用最簡單的策略:從觀測空間到動作空間的確定性對映。為了最大程度的通用性,我們將使用 Pendulum 環境的 `LazyLinear` 模組,該環境在上一教程中已例項化。
import torch
from tensordict.nn import TensorDictModule
from torchrl.envs import GymEnv
env = GymEnv("Pendulum-v1")
module = torch.nn.LazyLinear(out_features=env.action_spec.shape[-1])
policy = TensorDictModule(
module,
in_keys=["observation"],
out_keys=["action"],
)
要執行我們的策略,僅此而已!懶惰模組的使用使我們無需獲取觀測空間的形狀,因為模組將自動確定它。此策略現在已準備好在環境中執行。
rollout = env.rollout(max_steps=10, policy=policy)
print(rollout)
專用包裝器¶
為了簡化 `Actor`、# `ProbabilisticActor`、# `ActorValueOperator` 或 # `ActorCriticOperator` 的整合。例如,`Actor` 為 `in_keys` 和 `out_keys` 提供了預設值,使得與許多常見環境的整合變得簡單。
from torchrl.modules import Actor
policy = Actor(module)
rollout = env.rollout(max_steps=10, policy=policy)
print(rollout)
可用專用 TensorDictModules 的列表可在 API 參考 中找到。
網路¶
TorchRL 還提供了可以在不依賴 tensordict 功能的情況下使用的常規模組。您將遇到的最常見的兩個網路是 `MLP` 和 `ConvNet` (CNN) 模組。我們可以用這些模組之一替換我們的策略模組。
from torchrl.modules import MLP
module = MLP(
out_features=env.action_spec.shape[-1],
num_cells=[32, 64],
activation_class=torch.nn.Tanh,
)
policy = Actor(module)
rollout = env.rollout(max_steps=10, policy=policy)
TorchRL 還支援基於 RNN 的策略。由於這是一個更技術性的主題,因此在 單獨的教程 中進行了介紹。
隨機策略¶
像 PPO 這樣的策略最佳化演算法要求策略是隨機的:與上面的示例不同,模組現在編碼了一個從觀測空間到編碼動作空間上分佈的引數空間的對映。TorchRL 透過將各種操作(例如從引數構建分佈、從該分佈取樣以及檢索對數機率)組合到一個類中來促進此類模組的設計。在這裡,我們將構建一個依賴於具有三個元件的常規正態分佈的 actor:
一個 `MLP` 主幹,讀取大小為 `[3]` 的觀測值,並輸出大小為 `[2]` 的單個張量;
一個 `NormalParamExtractor` 模組,它將此輸出分成兩個塊:均值和標準差,大小均為 `[1]`;
一個 `ProbabilisticActor`,它將這些引數作為 `in_keys` 讀取,建立具有這些引數的分佈,並使用樣本和對數機率填充我們的 tensordict。
from tensordict.nn.distributions import NormalParamExtractor
from torch.distributions import Normal
from torchrl.modules import ProbabilisticActor
backbone = MLP(in_features=3, out_features=2)
extractor = NormalParamExtractor()
module = torch.nn.Sequential(backbone, extractor)
td_module = TensorDictModule(module, in_keys=["observation"], out_keys=["loc", "scale"])
policy = ProbabilisticActor(
td_module,
in_keys=["loc", "scale"],
out_keys=["action"],
distribution_class=Normal,
return_log_prob=True,
)
rollout = env.rollout(max_steps=10, policy=policy)
print(rollout)
關於此滾動的有幾點需要注意:
由於我們在 actor 構建期間請求了它,因此給定當時分佈的動作的對數機率也被寫入。這對於 PPO 等演算法是必需的。
分佈的引數也作為 `loc` 和 `scale` 條目返回到輸出 tensordict 中。
如果您的應用程式需要,您可以控制動作的取樣,以使用分佈的期望值或其他屬性,而不是使用隨機樣本。這可以透過 `set_exploration_type()` 函式進行控制。
from torchrl.envs.utils import ExplorationType, set_exploration_type
with set_exploration_type(ExplorationType.DETERMINISTIC):
# takes the mean as action
rollout = env.rollout(max_steps=10, policy=policy)
with set_exploration_type(ExplorationType.RANDOM):
# Samples actions according to the dist
rollout = env.rollout(max_steps=10, policy=policy)
檢查文件字串中的 `default_interaction_type` 關鍵字引數以瞭解更多資訊。
探索¶
像這樣隨機策略在一定程度上自然地權衡了探索和利用,但確定性策略則不能。幸運的是,TorchRL 也可以透過其探索模組來緩解這個問題。我們將以 `EGreedyModule` 探索模組為例(另請參閱 `AdditiveGaussianModule` 和 `OrnsteinUhlenbeckProcessModule`)。為了看到這個模組在起作用,讓我們回到確定性策略。
from tensordict.nn import TensorDictSequential
from torchrl.modules import EGreedyModule
policy = Actor(MLP(3, 1, num_cells=[32, 64]))
我們的 ε-greedy 探索模組通常會使用一定的衰減幀數和 ε 引數的初始值進行自定義。ε = 1 的值意味著每個採取的動作都是隨機的,而 ε=0 意味著根本沒有探索。為了衰減(即減小)探索因子,需要呼叫 `step()`(有關示例,請參閱最後一個 教程)。
exploration_module = EGreedyModule(
spec=env.action_spec, annealing_num_steps=1000, eps_init=0.5
)
為了構建我們的探索性策略,我們只需要在 `TensorDictSequential` 模組(在 tensordict 領域中相當於 `Sequential`)內將確定性策略模組與探索模組串聯起來。
exploration_policy = TensorDictSequential(policy, exploration_module)
with set_exploration_type(ExplorationType.DETERMINISTIC):
# Turns off exploration
rollout = env.rollout(max_steps=10, policy=exploration_policy)
with set_exploration_type(ExplorationType.RANDOM):
# Turns on exploration
rollout = env.rollout(max_steps=10, policy=exploration_policy)
由於它必須能夠從動作空間中取樣隨機動作,因此 `EGreedyModule` 必須配備環境的 `action_space` 才能知道使用什麼策略來隨機取樣動作。
Q 值 actor¶
在某些情況下,策略不是一個獨立的模組,而是構建在另一個模組之上。Q 值 actor 就是這種情況。簡而言之,這些 actor 需要動作值的估計(大多數時候是離散的),並且會貪婪地選擇具有最高值的動作。在某些情況下(有限離散動作空間和有限離散狀態空間),可以只儲存一個狀態-動作對的 2D 表格,並選擇值最高的動作。DQN 帶來的創新是透過使用神經網路來編碼 `Q(s, a)` 值對映,將此擴充套件到連續狀態空間。為了更清楚地理解,讓我們考慮另一個具有離散動作空間的環境。
env = GymEnv("CartPole-v1")
print(env.action_spec)
我們構建了一個價值網路,當它從環境中讀取狀態時,為每個動作產生一個值。
num_actions = 2
value_net = TensorDictModule(
MLP(out_features=num_actions, num_cells=[32, 32]),
in_keys=["observation"],
out_keys=["action_value"],
)
我們可以透過在我們的價值網路之後新增一個 `QValueModule` 來輕鬆構建我們的 Q 值 actor。
from torchrl.modules import QValueModule
policy = TensorDictSequential(
value_net, # writes action values in our tensordict
QValueModule(spec=env.action_spec), # Reads the "action_value" entry by default
)
讓我們來看看!我們讓策略執行幾個步驟,並檢視輸出。我們應該在滾動中找到 `"action_value"` 以及 `"chosen_action_value"` 條目。
rollout = env.rollout(max_steps=3, policy=policy)
print(rollout)
由於它依賴於 `argmax` 運算子,因此此策略是確定性的。在資料收集期間,我們需要探索環境。為此,我們再次使用 `EGreedyModule`。
policy_explore = TensorDictSequential(policy, EGreedyModule(env.action_spec))
with set_exploration_type(ExplorationType.RANDOM):
rollout_explore = env.rollout(max_steps=3, policy=policy_explore)
這就是我們關於使用 TorchRL 構建策略的簡短教程!
您還可以使用該庫進行許多其他操作。一個好的起點是檢視 模組 API 參考。
後續步驟
檢視當動作是複合的時如何使用 `CompositeDistribution`(例如,env 需要離散和連續動作);
看看如何在策略中使用 RNN(教程);
將此與 Decision Transformers 示例中的 Transformer 使用進行比較(參見 GitHub 上的 `example` 目錄)。