注意
要下載完整的示例程式碼,請轉到末尾。
TorchRL 模組入門¶
作者: Vincent Moens
注意
要在 notebook 中執行此教程,請在開頭新增一個包含以下內容的安裝單元格:
!pip install tensordict !pip install torchrl
強化學習旨在建立能夠有效解決特定任務的策略。策略可以採取各種形式,從可微分的對映(將觀測空間對映到動作空間),到更臨時的方法(例如對每個可能動作計算的值列表執行 argmax)。策略可以是確定性的或隨機的,並且可能包含複雜元素,例如迴圈神經網路 (RNN) 或 Transformer。
適應所有這些場景可能相當複雜。在這個簡潔的教程中,我們將深入研究 TorchRL 在策略構建方面的核心功能。我們將主要關注兩種常見場景下的隨機策略和 Q 值策略:使用多層感知機 (MLP) 或卷積神經網路 (CNN) 作為骨幹網路。
TensorDict模組(TensorDictModules)¶
與環境如何與 TensorDict 例項互動類似,用於表示策略和值函式的模組也執行相同的操作。核心思想很簡單:將一個標準的 Module(或任何其他函式)封裝在一個類中,該類知道哪些條目需要被讀取並傳遞給模組,然後將結果記錄到指定的條目中。為了說明這一點,我們將使用最簡單的策略:從觀測空間到動作空間的確定性對映。為了最大限度地提高通用性,我們將使用一個 LazyLinear 模組和我們在上一個教程中例項化的 Pendulum 環境。
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)
專用包裝器(Specialized wrappers)¶
為了簡化 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 參考中找到。
網路(Networks)¶
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 的策略。由於這是一個更技術性的主題,因此在單獨的教程中進行了處理。
機率策略(Probabilistic policies)¶
像 PPO 這樣的策略最佳化演算法要求策略是隨機的:與上述示例不同,模組現在編碼從觀測空間到引數空間的對映,該引數空間編碼了對可能動作的分佈。TorchRL 透過將各種操作(例如從引數構建分佈、從該分佈取樣以及檢索對數機率)分組到一個單一類中來促進此類模組的設計。在這裡,我們將構建一個依賴於正則正態分佈的 actor,使用三個元件:
一個
MLP骨幹網路,讀取大小為[3]的觀測值,並輸出一個大小為[2]的單一張量;一個
NormalParamExtractor模組,它將此輸出分成兩塊,一個均值(mean)和一個標準差(standard deviation),大小均為[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)
關於這次 roll out 有幾點需要注意:
正如我們在構建 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 關鍵字引數以瞭解更多資訊。
探索(Exploration)¶
像這樣的隨機策略在一定程度上自然地權衡了探索和利用,但確定性策略則不會。幸運的是,TorchRL 也可以透過其探索模組來彌補這一點。我們將以 EGreedyModule 探索模組為例(也請檢視 AdditiveGaussianModule 和 OrnsteinUhlenbeckProcessModule)。為了看到這個模組的作用,讓我們回到一個確定性策略。
from tensordict.nn import TensorDictSequential
from torchrl.modules import EGreedyModule
policy = Actor(MLP(3, 1, num_cells=[32, 64]))
我們的 \(\epsilon\)-greedy 探索模組通常會透過一些退火幀數和 \(\epsilon\) 引數的初始值進行定製。 \(\epsilon = 1\) 的值意味著採取的每個動作都是隨機的,而 \(\epsilon = 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-Value actors)¶
在某些設定中,策略不是一個獨立的模組,而是構建在另一個模組之上。Q 值 actor 就是這種情況。簡而言之,這些 actor 需要對動作值(大多數情況下是離散的)進行估計,並貪婪地選擇具有最高值的動作。在某些設定中(有限的離散動作空間和有限的離散狀態空間),人們可以直接儲存一個狀態-動作對的二維表格,並選擇具有最高值的動作。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
)
我們來試一試!我們執行策略幾個步驟,並檢視輸出。我們應該在獲得的 roll out 中找到 "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;瞭解如何在策略中使用 RNN(參閱教程);
將其與決策 Transformer 示例中的 Transformer 使用進行比較(請參閱 GitHub 上的
example目錄)。