非同步機器人推理:解耦動作預測和執行

釋出於 2025 年 7 月 10 日
在 GitHub 上更新

摘要: 機器人策略變得越來越龐大,並且傾向於預測未來一系列的動作,而不是單一的下一個動作。這導致機器人在等待新動作執行時處於空閒狀態,在執行時引入了明顯的延遲,並且缺乏響應性。非同步推理透過將動作預測與動作執行解耦,收緊了控制迴圈,消除了執行時的延遲,並實現了更具適應性的控制。在這篇博文中,我們介紹了非同步推理背後的基礎知識,以及如何利用它來提高機器人策略在現實世界中的效能。

目錄

開始入門

按照我們的教程開始使用非同步推理。

順序推理(上)與非同步推理(下)。透過允許重新規劃和更緊湊的控制迴圈,非同步推理實現了 (1) 嘗試恢復,以及 (2) 任務完成速度提升約 2 倍。順序推理在抓取物體失敗後仍會繼續執行當前的動作序列,而非同步推理可以重新規劃並執行新的動作序列。兩種設定使用相同的策略!

非同步推理:深度解析

透過非同步推理,我們將動作執行與動作預測解耦。考慮到當前流行的模型如 [ACT]、[OpenVLA]、[PI0] 和 [SmolVLA] 的趨勢,這一點尤其重要,因為它們傾向於根據觀察 oto_t 輸出一系列動作 at:t+Ha_{t:t+H},而不是單個動作 ata_t。您可以透過使用 LeRobot 執行所有這些模型來親自驗證這一點。

順序使用動作序列會導致 (1) 執行時延遲,影響任務執行時間,以及 (2) 由於在很大程度上是開環行動而缺乏響應性。非同步推理透過將動作預測與動作執行解耦來緩解這兩個限制。我們在 SmolVLA 中引入了非同步推理,發現它可以在任務成功率相當的情況下,將任務完成時間縮短約 2 倍。

具體來說,我們設計了一個包含兩個元件的系統,其中策略推理和動作執行在兩個不同的程序中執行,甚至可以在透過網路連線的兩臺不同機器上進行。

  • 一個 PolicyServer(策略伺服器),託管在加速硬體上,能夠使用比真實機器人上分配的更多計算資源來執行推理。
  • 一個 RobotClient(機器人客戶端)將接收到的動作入隊並執行它們,同時計算下一個動作序列。

PolicyServerRobotClient 之間的通訊依賴於 gRPC,它保證了比同類 REST API 快約 5 倍的效能。所有這些的結果是一個從不等待推理的機器人。

Async inference scheme

非同步推理,突出顯示:(1) 客戶端傳送第一個觀察進行推理,不久後接收到第一個動作序列;(2) 客戶端在尚未用盡當前動作序列時傳送另一個觀察進行處理;(3) 客戶端接收到一個更新的動作序列,並將其與之前正在執行的剩餘部分進行聚合。


1. 為什麼順序推理不夠用

假設一個策略 π \pi 將當前觀察 ot o_t 對映到未來 H H 個動作的序列。形式上,π:O    A,At=(at,at+1,at+H)=π(ot)\pi : \mathcal{O} \;\mapsto\; \mathcal{A}, \mathbf{A}_t = \begin{pmatrix} a_{t}, & a_{t+1}, & \dots & a_{t+H} \end{pmatrix} = \pi(o_t)

因此,傳統的控制迴圈將包括以下步驟:

  1. 捕獲 ot o_t
  2. 執行 π(ot) \pi(o_t) 以獲得 At=π(ot) \mathbf{A}_t = \pi(o_t)
  3. At\mathbf{A_t} 入隊,並開始從佇列中彈出動作來執行。
  4. 如果佇列為空,等待 At+H \mathbf{A}_{t+H} ,否則重複步驟 3。

在步驟 2 中,機器人處於空閒狀態。延遲隨著模型大小的增加而增長(並且模型會隨著時間的推移而變得越來越龐大),並可能迅速佔據互動時間(通常約為 1/fps),如下面的影片所示(來自我們的 Discord 社群 🤗)

這直接導致 (1) 任務完成時間效能降低——機器人需要等待下一個動作序列被計算出來——以及 (2) 響應性降低,原因在於 (2.1) 在有動作可用時進行大範圍的開環行動,以及 (2.2) 在等待下一個動作序列時完全空閒。

Sequential inference – idle periods highlighted Time to select action – spikes indicate inference

(左)順序推理,突出顯示了空閒時段。(右)選擇動作的時間,顯示了當本地佇列耗盡時觸發推理導致的峰值(在 2021 款 MacBook Pro 上使用 ACT 模型,推理延遲約為 100 毫秒,即 30fps 下約 3 幀)。


2. 非同步推理,簡而言之

我們的系統透過重疊計算和執行來消除空閒期

  1. RobotClient 將最新的觀察流式傳輸到 PolicyServer
  2. 當伺服器執行推理時,客戶端執行當前佇列中的動作。
  3. 新動作到達後,會被合併到佇列中,迴圈繼續。

關鍵思想是,機器人已經知道接下來幾個時間步該做什麼,因此它可以在伺服器計算新動作時繼續移動。

Async inference diagram

非同步推理透過解耦這兩個過程,在時間上將當前動作序列的執行與下一個動作序列的計算重疊起來,這兩個過程甚至可以在透過網路連線的完全不同的機器上執行。

這帶來了更緊湊的控制迴圈,和一個從不等待推理的機器人。反過來,這使得任務完成時間縮短了約 2 倍,任務成功率相當,並且由於更緊湊的迴圈,控制更具適應性(見下方影片)。


3. 系統架構

元件 角色 技術
RobotClient(機器人客戶端) 在機器人上執行,流式傳輸觀察資料,維護一個動作佇列,執行動作 Python, gRPC
PolicyServer(策略伺服器) 託管策略,執行批次推理,將動作序列發回 Python、gRPC,可能使用加速硬體(GPU/TPU)

因為 gRPC 基於 HTTP/2 並使用協議緩衝區,它能實現低延遲的二進位制訊息傳遞和開箱即用的雙向流,這反過來幫助我們維持更緊湊的控制迴圈和低於 100ms 的往返延遲(在我們的本地網路上,並將 SmolVLA 託管在 NVIDIA RTX 4090 上)。

RobotClient 在機器人上執行,並透過 gRPC 將觀察資料流式傳輸到 PolicyServerPolicyServer 準備接收到的觀察資料以進行推理,並將一個動作序列發回給 RobotClient

機器人客戶端

From client perspective

從客戶端的角度看,觀察資料根據本地佇列狀態流式傳輸到伺服器。傳入的動作序列在重疊部分與當前可用的動作佇列進行聚合。

RobotClient 維護一個本地動作佇列,並遵循一個簡單而有效的策略:當佇列長度低於可配置的閾值時傳送新的觀察資料(在 SmolVLA 論文中為 \(g\),在程式碼中為 chunk_size_threshold)。這個閾值以最大序列大小的比例表示,作為一個觸發條件,平衡了計算負載和響應性。

Client to server

客戶端根據本地佇列狀態將觀察資料流式傳輸到伺服器

從客戶端的角度來看,過程如下:

  1. 佇列監控:客戶端持續監控其動作佇列長度與序列大小閾值引數。當佇列低於此閾值時,它會發出訊號,表示應傳送新的觀察資料進行處理。

  2. 觀察資料流式傳輸:一旦滿足閾值條件,客戶端捕獲當前觀察資料並透過 gRPC 將其流式傳輸到 PolicyServer。至關重要的是,觀察資料是流式傳輸的,而不是透過一元 RPC 傳送的,因為它們通常會超過 4MB 的最大訊息大小(高解析度的多個攝像頭捕獲會導致這種情況)。

  3. 動作序列聚合:當從伺服器收到新的動作序列時,客戶端會將其與當前佇列中任何剩餘的動作在重疊部分進行合併。這就是自定義聚合器發揮作用的地方,它們以不同方式處理當前和傳入序列之間的重疊部分。目前,我們支援透過指定一個自定義的 aggregate_fn(chunk1: torch.Tensor, chunk2: torch.Tensor) -> torch.Tensor 函式來靈活地聚合序列,該函式對每個重疊的時間步呼叫,並且可以由使用者提供。重疊部分(圖中以淺藍色顯示)需要仔細處理。我們可以設計不同的聚合策略:

    • 替換:簡單地用新的預測替換重疊的動作
    • 加權混合:使用時間權重組合重疊動作(較近的動作獲得更高的權重)

這個系統是高度可配置的,因為可以根據網路延遲、模型推理時間和期望的響應性來調整序列大小閾值。較低的閾值意味著更頻繁的更新(和更高的計算成本),而較高的閾值則以可能導致佇列枯竭為代價減少了通訊開銷。最後,我們通常在一個執行緒中從 PolicyServer 接收動作,並在另一個執行緒中執行它們。這使得客戶端在一個單獨的執行緒中監聽傳入的序列,而不會阻塞執行,並始終消耗當前序列,直到新的序列完全可用。

策略伺服器

在收到來自 RobotClient 的觀察資料後,PolicyServer 會對接收到的觀察資料進行必要的清理,使其準備好進行推理。這個過程如下圖所示:

Server pipeline

在伺服器上執行的觀察清理流程,突出顯示了與 (1) 鍵匹配、(2) 預處理和 (3) 推理準備相關的三個主要步驟。

一旦觀察資料準備好,就會與上一次用於推理的觀察資料進行比較。這樣可以避免陷入一個迴圈,即處理非常相似的觀察資料,從而觸發不必要的推理和執行相似的動作(這反過來又會導致處理非常相似的觀察資料)。我們根據關節空間的相似性來比較觀察資料,這為我們提供了一種近似且快速的方法來測量機器人的變化。顯然,這個指標不適應環境的動態變化(物體改變位置或施加干擾),但我們發現它在大多數情況下是一個很好的權衡,並且在避免不必要的推理和狀態崩潰方面非常有效。至關重要的是,RobotClient 保留了對給定觀察資料是否必須處理的控制權,以避免死鎖。客戶端傳送並標記為 must_go=True 的觀察資料無論相似性度量如何都會被處理。

Policy workflow

策略工作流,其中傳入的觀察資料與上一次用於推理的資料進行比較,只有在足夠不同或標記為 `must_go` 時才進行處理。

最後,為確保 PolicyServer 始終處理最新的可用觀察資料,我們會阻塞傳入的觀察資料,直到前一個觀察資料被成功處理。為此,我們在 PolicyServer 上利用佇列來確保傳入的觀察資料在伺服器準備好處理它們之前不會入隊(見下文)。

Client pings server

客戶端每 1/fps 秒 ping 一次伺服器,但在前一個觀察資料成功處理之前,觀察資料不會入隊進行處理。


4. 分析非同步推理

就所有實際目的而言,在非同步推理中有兩個重要的時間尺度:

  • 環境步長 environment_dt=1/fps\texttt{environment\_dt} = 1/\texttt{fps},描述機器人執行一個動作的速度。
  • 推理延遲 inference_time\texttt{inference\_time}:前向傳播 + 網路往返時間。我們可以假設網路往返時間相對於策略推理時間可以忽略不計,儘管這可能不適用於所有設定。

重要的是,比率 c=environment_dtinference_time c = \frac{\texttt{environment\_dt}}{\texttt{inference\_time}} 會導致不同的行為

  • c1c \ll 1:環境演化速度快於推理速度。在這種情況下,佇列會很快清空,我們會退化為順序控制。
  • c1c \ge 1:伺服器能跟上。佇列總是(幾乎)滿的。

關鍵是,cc 影響在任何給定時間佇列中可用動作的數量。為了避免上述順序極限控制,可以:

  1. 為策略伺服器使用更多計算資源,將伺服器託管在 GPU 上,透過分配更多計算資源來減少 inference_time\texttt{inference\_time}
  2. 更頻繁地向伺服器傳送觀察資料,當佇列長度 kk 低於其最大大小的一部分 g=k/Hg = k/H 時傳送新的觀察資料。
    • g=0g=0 再現了順序推理(佇列為空,等待)。
    • g=1g=1 每個時間步都發送一個觀察資料(最大計算量,最小延遲)。

實驗(見下圖)表明,當傳送的觀察資料未被過濾掉時(它們都是必須處理的),g0.7g\approx0.7 提供了一個很好的權衡。我們建議設定 g=0.5g=0.5 並遵循我們的文件來根據您的需求調整此引數。

Queues

在任何給定時間佇列中可用動作的數量,作為 g 的函式。g 值越大,更新越頻繁,計算成本也越高。g 值接近 0 則再現了順序推理(佇列為空,等待)。在我們的實驗中,我們發現 g~0.7 是一個很好的權衡。


5. 在您的設定中使用非同步推理

非同步推理是提高機器人策略效能的一種簡單而有效的方法。在我們使用 SmolVLA 的實驗中,非同步推理在任務成功率相當的情況下,任務完成時間提速約 2 倍,並且由於更緊湊的迴圈,控制更具適應性。

要使用非同步推理執行您的策略,您只需按照我們的教程,並使用您自己的自定義引數(例如,策略路徑或動作序列大小閾值)。非同步推理支援支援動作序列分塊的策略!


結論

我們介紹了非同步推理,這是一種簡單而有效的方法,可以提高機器人策略的效能。在我們使用 SmolVLA 的實驗中,非同步推理在任務成功率相當的情況下,任務完成時間提速約 2 倍,並且由於更緊湊的迴圈,控制更具適應性。

我們很高興能與社群分享這項工作,並期待看到它如何被用來提高機器人策略的效能。我們歡迎在 huggingface/lerobot 上提交 PR 來改進和擴充套件非同步推理框架,並樂於在我們的 Discord 社群 🤗 中進一步討論。

社群

註冊登入 發表評論

© . This site is unofficial and not affiliated with Hugging Face, Inc.