• 文件 >
  • 開始使用環境、TED 和轉換
捷徑

開始使用環境、TED 和轉換

作者Vincent Moens

注意

若要在筆記本中執行本教學,請在開頭新增一個包含以下內容的安裝儲存格

!pip install tensordict
!pip install torchrl

歡迎來到入門教學!

以下是我們將涵蓋的主題清單。

如果您時間緊迫,您可以直接跳到最後一個教學,您自己的第一個訓練迴圈,如果您不清楚或想了解有關特定主題的更多資訊,您可以從那裡回溯到其他每個「入門」教學!

RL 中的環境

標準的 RL(強化學習)訓練迴圈涉及一個模型,也稱為策略,該模型經過訓練以完成特定環境中的任務。通常,此環境是一個模擬器,它接受動作作為輸入,並產生一個觀察以及一些元數據作為輸出。

在本文件中,我們將探索 TorchRL 的環境 API:我們將學習如何建立環境、與其互動,並了解它使用的資料格式。

建立環境

本質上,TorchRL 並不直接提供環境,而是為封裝模擬器的其他函式庫提供包裝器。envs 模組可以被視為通用環境 API 的提供者,以及模擬後端的中心樞紐,例如 gymGymEnv)、BraxBraxEnv)或 DeepMind Control SuiteDMControlEnv)。

建立您的環境通常與底層後端 API 允許的一樣簡單。以下是使用 gym 的範例

from torchrl.envs import GymEnv

env = GymEnv("Pendulum-v1")

執行環境

在 TorchRL 中,環境有兩個關鍵的方法:reset(),用於初始化一個 episode;以及 step(),用於執行 actor 選擇的動作。在 TorchRL 中,環境方法讀取和寫入 TensorDict 實例。本質上,TensorDict 是一個通用的、基於鍵的 tensor 資料載體。使用 TensorDict 而不是普通 tensor 的好處是,它使我們能夠互換地處理簡單和複雜的資料結構。由於我們的函式簽名非常通用,因此消除了適應不同資料格式的挑戰。簡單來說,在經過這個簡短的教學後,您將能夠操作簡單和高度複雜的環境,因為它們面向使用者的 API 是相同且簡單的!

讓我們將環境投入使用,看看 tensordict 實例長什麼樣子

reset = env.reset()
print(reset)
TensorDict(
    fields={
        done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([]),
    device=None,
    is_shared=False)

現在讓我們在動作空間中採取一個隨機動作。首先,對動作進行取樣

reset_with_action = env.rand_action(reset)
print(reset_with_action)
TensorDict(
    fields={
        action: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.float32, is_shared=False),
        done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([]),
    device=None,
    is_shared=False)

這個 tensordict 具有與從 EnvBase() 獲得的 tensordict 相同的結構,但多了一個 "action" 條目。您可以像使用普通字典一樣輕鬆存取動作

print(reset_with_action["action"])
tensor([1.5947])

現在我們需要將這個動作傳遞給環境。我們會將整個 tensordict 傳遞給 step 方法,因為在更進階的情況下,例如多代理 RL 或無狀態環境,可能需要讀取多個 tensor

stepped_data = env.step(reset_with_action)
print(stepped_data)
TensorDict(
    fields={
        action: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.float32, is_shared=False),
        done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        next: TensorDict(
            fields={
                done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
                observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
                reward: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.float32, is_shared=False),
                terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
                truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
            batch_size=torch.Size([]),
            device=None,
            is_shared=False),
        observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([]),
    device=None,
    is_shared=False)

同樣,這個新的 tensordict 與前一個相同,只是它有一個 "next" 條目(它本身是一個 tensordict!),其中包含由我們的動作產生的觀察、獎勵和完成狀態。

我們將此格式稱為 TED,代表 TorchRL Episode Data format (TorchRL Episode 資料格式)。它是該函式庫中表示資料的普遍方式,無論是像這裡一樣動態地,還是靜態地使用離線資料集。

您需要在環境中執行 rollout 的最後一點資訊是如何將 "next" 條目移到根目錄以執行下一步。 TorchRL 提供了一個專用的 step_mdp() 函數,它正是做這件事:它過濾掉您不需要的資訊,並提供一個資料結構,該結構對應於您在 Markov Decision Process(或 MDP)中執行一個步驟後的觀察。

from torchrl.envs import step_mdp

data = step_mdp(stepped_data)
print(data)
TensorDict(
    fields={
        done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([]),
    device=None,
    is_shared=False)

環境 rollout

寫下這三個步驟(計算動作、執行步驟、在 MDP 中移動)可能有點乏味和重複。幸運的是,TorchRL 提供了一個不錯的 rollout() 函數,允許您隨意在閉環中執行它們

rollout = env.rollout(max_steps=10)
print(rollout)
TensorDict(
    fields={
        action: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.float32, is_shared=False),
        done: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
        next: TensorDict(
            fields={
                done: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
                observation: Tensor(shape=torch.Size([10, 3]), device=cpu, dtype=torch.float32, is_shared=False),
                reward: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.float32, is_shared=False),
                terminated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
                truncated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False)},
            batch_size=torch.Size([10]),
            device=None,
            is_shared=False),
        observation: Tensor(shape=torch.Size([10, 3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([10]),
    device=None,
    is_shared=False)

這個資料看起來很像上面的 stepped_data,只是它的 batch size 現在等於我們透過 max_steps 參數提供的步驟數。 tensordict 的神奇之處還不止於此:如果您對這個環境的單個轉換感興趣,您可以像索引 tensor 一樣索引 tensordict

transition = rollout[3]
print(transition)
TensorDict(
    fields={
        action: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.float32, is_shared=False),
        done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        next: TensorDict(
            fields={
                done: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
                observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
                reward: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.float32, is_shared=False),
                terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
                truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
            batch_size=torch.Size([]),
            device=None,
            is_shared=False),
        observation: Tensor(shape=torch.Size([3]), device=cpu, dtype=torch.float32, is_shared=False),
        terminated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([]),
    device=None,
    is_shared=False)

TensorDict 將自動檢查您提供的索引是否為鍵(在這種情況下,我們沿鍵維度索引)或像這裡一樣的空間索引。

像這樣執行(沒有策略),rollout 方法可能看起來相當無用:它只是運行隨機動作。如果有一個策略可用,它可以被傳遞給該方法並用於收集資料。

然而,首先運行一個 naive 的、沒有策略的 rollout 來檢查從環境中可以預期什麼,這可能會很有用。

要體會 TorchRL API 的多功能性,請考慮這樣一個事實:rollout 方法是普遍適用的。無論您是使用像這樣的單個環境、跨多個進程的多個副本、多代理環境,甚至是它的無狀態版本,它都可以在所有用例中工作!

轉換環境

大多數情況下,您會想要修改環境的輸出,以更好地滿足您的需求。例如,您可能想要監控自上次重置以來執行的步驟數、調整圖像大小或將連續的觀察結果堆疊在一起。

在本節中,我們將研究一個簡單的轉換,StepCounter 轉換。轉換的完整列表可以在這裡找到。

轉換通過 TransformedEnv 與環境整合

from torchrl.envs import StepCounter, TransformedEnv

transformed_env = TransformedEnv(env, StepCounter(max_steps=10))
rollout = transformed_env.rollout(max_steps=100)
print(rollout)
TensorDict(
    fields={
        action: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.float32, is_shared=False),
        done: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
        next: TensorDict(
            fields={
                done: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
                observation: Tensor(shape=torch.Size([10, 3]), device=cpu, dtype=torch.float32, is_shared=False),
                reward: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.float32, is_shared=False),
                step_count: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.int64, is_shared=False),
                terminated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
                truncated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False)},
            batch_size=torch.Size([10]),
            device=None,
            is_shared=False),
        observation: Tensor(shape=torch.Size([10, 3]), device=cpu, dtype=torch.float32, is_shared=False),
        step_count: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.int64, is_shared=False),
        terminated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False),
        truncated: Tensor(shape=torch.Size([10, 1]), device=cpu, dtype=torch.bool, is_shared=False)},
    batch_size=torch.Size([10]),
    device=None,
    is_shared=False)

正如您所看到的,我們的環境現在多了一個條目 "step_count",它追蹤自上次重置以來的步驟數。鑑於我們將可選參數 max_steps=10 傳遞給轉換建構子,我們也在 10 步後截斷了軌跡(沒有像我們使用 rollout 呼叫要求的那樣完成 100 步的完整 rollout)。我們可以透過查看截斷條目來看到軌跡被截斷了

print(rollout["next", "truncated"])
tensor([[False],
        [False],
        [False],
        [False],
        [False],
        [False],
        [False],
        [False],
        [False],
        [ True]])

這就是 TorchRL 環境 API 的簡短介紹的全部內容!

下一步

要進一步探索 TorchRL 環境可以做什麼,請前往查看

  • step_and_maybe_reset() 方法將 step()step_mdp()reset() 打包在一起。

  • 有些環境,例如 GymEnv 支援透過 from_pixels 參數進行渲染。 請查閱類別的文件字串以瞭解更多資訊!

  • 批量環境,特別是 ParallelEnv,它允許您在多個處理程序上運行一個相同(或不同!)環境的多個副本。

  • 透過 Pendulum 教學 設計您自己的環境,並學習規格和無狀態環境。

  • 請參閱關於環境的更深入教學 在專門的教學中

  • 如果您對 MARL 感興趣,請查看 多代理環境 API

  • TorchRL 有許多工具可以與 Gym API 互動,例如透過 register_gym() 在 Gym 註冊中註冊 TorchRL 環境的方法、透過 set_info_dict_reader() 讀取資訊字典的 API,或透過 set_gym_backend() 控制 gym 後端的方式。

腳本的總執行時間: (0 分鐘 46.408 秒)

預估記憶體使用量: 320 MB

由 Sphinx-Gallery 產生的圖片集

文件

取得 PyTorch 的完整開發人員文件

檢視文件

教學

取得針對初學者和進階開發人員的深入教學

檢視教學

資源

尋找開發資源並取得問題解答

檢視資源