본문으로 건너뛰기

© 2026 Molayo

HuggingFace헤드라인2026. 05. 07. 01:54

비동기 로봇 추론: 실행 예측과 실행의 분리

요약

로봇 정책 모델이 미래 행동 블록을 예측함에 따라 발생하는 '실행 지연' 문제를 해결하기 위해 비동기 추론(Asynchronous Inference) 기법이 제안됩니다. 이 방식은 행동의 '예측(Policy Server)'과 실제 로봇에서의 '실행(Robot Client)' 과정을 분리하여, 서버가 다음 행동을 계산하는 동안 클라이언트가 현재 큐에 있는 행동을 계속 실행하게 합니다. 이를 통해 전통적인 순차적 추론에서 발생하던 대기 시간(idleness)을 제거하고, 제어 루프를 단축하며 로봇의 반응성과 작업 완료 속도를 크게 향상시킬 수 있습니다.

핵심 포인트

  • 비동기 추론은 행동 예측과 실제 실행 과정을 분리하여 로봇의 지연 시간을 최소화합니다.
  • PolicyServer(추론)와 RobotClient(실행)를 별도의 프로세스/장치로 구성하고 gRPC 통신을 사용하면 성능이 향상됩니다.
  • 순차적 추론 시 발생하는 대기 시간(idleness) 문제를 해결하여, 로봇의 작업 완료 속도를 최대 2배까지 가속화할 수 있습니다.
  • 비동기 처리는 로봇이 다음 행동 청크를 기다리느라 멈추는 현상을 방지하고, 더 적응적인 제어를 가능하게 합니다.

비동기 로봇 추론: 실행 예측과 실행의 분리

TL;DR 로봇 정책은 점점 더 부피가 커지고 있으며, 단일 다음 행동이 아닌 미래 행동의 블록을 예측합니다. 이는 로봇이 새로운 행동을 수행할 때까지 대기하게 되어 실행 시 눈에 띄는 지연을 유발하고 반응성을 떨어뜨립니다. 비동기 추론은 실행 예측과 실행을 분리하여 제어 루프를 단축하고, 실행 시 지연을 제거하며 더 적응적인 제어를 가능하게 합니다. 이 블로그 글에서는 비동기 추론의 기본 원리와 실제 세계에서 로봇 정책 성능을 향상시키는 방법을 다룹니다.

  • 시작하기
  • 비동기 추론: 심층 분석
    1. 순차적 추론의 한계
    1. 비동기 추론, 간단히
    1. 시스템 아키텍처
    1. 비동기 추론 분석
    1. 설정에 비동기 활용하기
  • 결론

비동기 추론을 시작하려면 튜토리얼을 따라보세요.

순차적 추론 (첫 번째) versus 비동기 추론 (두 번째). 재계획과 더 단축된 제어 루프를 허용하는 비동기 추론은 (1) 복구 시도와 (2) ~2 배의 작업 완료 속도 향상을 제공합니다. 순차적 추론은 물체를 잡으려 할 실패 후에도 현재 행동 블록을 계속 수행하며, 비동기 추론은 재계획하고 새로운 행동 블록을 수행할 수 있습니다. 두 설정 모두 동일한 정책을 사용합니다!

비동기 추론에서는 실행 예측과 실행을 분리합니다. 이는 현재 인기 있는 모델들 [ACT], [OpenVLA], [PI0], 및 [SmolVLA]이 관찰에 대해 단일 행동이 아닌 행동 블록을 출력하는 경향이 있다는 점을 고려할 때 특히 관련이 있습니다. LeRobot 을 사용하여 모든 모델을 실행하여 이를 확인하세요.

블록을 순차적으로 사용하면 (1) 실행 시 지연과 작업 실행 시간의 영향, 및 (2) 넓은 오픈 루프 동작으로 인한 반응성 부족이 발생합니다.
비동기 추론은 실행 예측과 실행의 분리를 통해 이러한 한계를 완화합니다.
우리는 SmolVLA 에서 비동기 추론을 도입했으며, 유사한 작업 성공률로 ~2 배의 작업 완료 시간 단축 효과를 발견했습니다.

특히 정책 추론과 행동 실행은 두 개의 다른 프로세스에서 수행되며, 네트워크를 통해 연결된 두 개의 다른 기계에 있을 수 있는 2 구성 요소 시스템을 설계합니다:

  • PolicyServer: 가속화된 하드웨어에 호스팅되며, 실제 로봇에 할당된 컴퓨팅 리소스보다 더 많은 리소스를 사용하여 추론을 실행할 수 있습니다.
  • RobotClient: 수신한 행동을 대기열에 추가하고 다음 블록이 계산되는 동안 실행합니다.

PolicyServerRobotClient 간의 통신은 gRPC를 기반으로 하며, 이는 비교 가능한 REST API 보다 ~5 배 빠른 성능을 보장합니다. 그 결과로 로봇은 추론을 기다리지 않습니다.

비동기 추론, 강조: (1) 클라이언트가 추론을 위해 첫 번째 관찰을 보내고, 곧바로 첫 번째 블록을 수신; (2) 현재 블록을 소모하지 않은 상태에서 다른 관찰을 처리를 위해 보내기; (3) 클라이언트가 이전 실행 중 남은 부분과 함께 업데이트된 행동 블록을 수신.

정책이 현재 관찰을 미래 행동의 시퀀스로 매핑한다고 가정합니다. 공식적으로, .
따라서 전통적인 제어 루프는 다음 단계를 포함합니다:

Capture .
Run to obtain .
Enqueue and start acting popping actions from the queue.
If the queue is empty, wait for , otherwise repeat step 3.

단계 2 동안 로봇은 **idleness (비활성 상태)**입니다. 지연 시간은 모델 크기에 따라 증가하며 (모델들은 시간이 지남에 따라 점점 더 부피가 커지는 경향이 있습니다), 이는 상호작용 시간 (보통 1/fps) 을 빠르게 지배할 수 있습니다 (아래 비디오에서 확인 가능, 우리 Discord 커뮤니티 🤗 에서 제공됨):

이는 다음 결과를 초래합니다: (1) 작업 완료 시간에 대한 성능 저하---로봇이 다음 행동 청크를 계산하기 위해 기다려야 합니다---와 (2) 응답성 감소, 이는 (2.1) 행동이 이용 가능한 동안 광범위하게 오픈 루프 (open-loop) 로 작동하고 (2.2) 다음 행동 청크를 기다리는 동안 완전한 비활성 상태 때문입니다.

(왼쪽)순차적 추론으로 강조된 idleness 기간. (오른쪽)행동 선택 시간은 로컬 큐가 고갈되어 추론이 트리거될 때 스파이크가 발생함을 보여줍니다 (추론 지연 시간은 약 ~100ms---3 프레임@30fps---2021 MacBook Pro 에서 ACT 모델을 사용하여).

우리의 시스템은 계산과 실행을 겹쳐서 idleness 기간을 제거합니다:

RobotClient

는 최신 관측치를 PolicyServer 에 스트리밍합니다.

  • 서버가 추론을 수행하는 동안 클라이언트는 현재 큐의 행동을 실행합니다. - 새로운 행동이 도착하면 큐에 병합되고 루프가 계속됩니다.

핵심 아이디어는 로봇이 다음 몇 시간 단계 (timesteps) 동안 무엇을 해야 하는지 이미 알고 있으므로, 서버에서 신선한 행동이 계산되는 동안 계속 움직일 수 있다는 것입니다.

비동기적 추론은 현재 행동 청크의 실행과 다음 추론을 시간적으로 겹치며, 이 두 프로세스를 분리하여 (전혀 다른 기계에 possibly 네트워크를 통해 연결되어) 실행할 수 있습니다.

이는 더 긴밀한 제어 루프와 추론을 기다리지 않는 로봇을 만들어냅니다. 이는 ~2 배의 작업 완료 시간 가속도 및 유사한 작업 성공률과 더 긴밀한 루프에서 오는 더 적응적인 제어를 가져옵니다 (아래 비디오 참조).

ComponentRoleTechnology
RobotClient
Runs on-board, streams observations, maintains an action queue, executes actions
Python, gRPC
PolicyServer
Hosts the policy, performs batched inference, sends action chunks backPython, gRPC, possibly accelerated hardware (GPU/TPU)

gRPC 는 HTTP/2 기반이며 프로토콜 버퍼를 사용하여 낮은 지연 시간 바이너리 메시징과 양방향 스트리밍을 기본으로 제공하므로, 이는 더 긴밀한 제어 루프와 100ms 미만 라운드 트립 지연 시간을 유지하는 데 도움을 줍니다 (우리 로컬 네트워크에서 NVIDIA RTX 4090 에서 SmolVLA 를 호스팅).

RobotClient

는 보드에서 실행되며 gRPC 를 통해 PolicyServer 에 관측치를 스트리밍합니다.
PolicyServer 는 수신된 관측치를 추론을 위해 준비하고, RobotClient 에 행동 청크를 전송합니다.
클라이언트의 관점에서는, 관측치는 로컬 큐 상태에 따라 서버로 스트리밍됩니다. 도착한 청크는 현재 이용 가능한 행동 큐와 겹치는 부분에서 집계됩니다.

RobotClient

는 로컬 행동 큐를 유지하며 단순하지만 효과적인 전략을 따릅니다: 큐 길이가 설정 가능한 임계값 (η) 아래로 떨어질 때 새로운 관측치를 전송 (SmolVLA 논문에서 g, 코드에서 chunk_size_threshold).
이 임계값 값은 최대 청크 크기의 분수로 표현되며, 계산 부하와 응답성을 균형 있게 하는 트리거 조건으로 작용합니다.

The client streams observations to the server, according to the local queue status.

From the client's perspective, the process unfolds as follows:

Queue monitoring: The client continuously monitors its action queue length against achunk size thresholdparameter. When the queue drops below this threshold, it signals that a new observation should be sent for processing.Observation streaming: Once the threshold condition is met, the client captures the current observation and streams it to thePolicyServer via gRPC. Crucially,observations are streamed rather than being sent via a unary RPCbecause they typically exceed the maximum message size of 4MB (multiple camera captures at high resolution result in this).Action chunk aggregation: When a new action chunk arrives from the server, the client merges it with any remaining actions in the current queue over the overlapping portion. This is wherecustom aggregatorscome into play, handling overlapping sections between the current and incoming chunks differently. As of now, we support flexibly aggregation between the chunks via the specification of a customaggregate_fn(chunk1: torch.Tensor, chunk2: torch.Tensor) -> torch.Tensor function, which is called for each overlapping timestep and can be user-provided. The overlapping portions (shown in light blue in the diagram) require careful handling. We can design different aggregation strategies:Replace: Simply replace overlapping actions with the newer predictionsWeighted blend: Combine overlapping actions using temporal weights (closer actions get higher weight)

This system is highly configurable, as the chunk size threshold can be tuned based on network latency, model inference time, and desired responsiveness.
A lower threshold means more frequent updates (and higher computational cost), while a higher threshold reduces communication overhead at the expense of potential queue starvation.
Lastly, we typically receive actions from PolicyServer in a thread, and perform them in another one. This keeps the client listening for incoming chunks in a separate thread, without blocking execution and always consuming the current chunk until a new one becomes fully available.

Upon receiving observations from the RobotClient, the PolicyServer receives observations from the RobotClient, and performs the necessary observation cleaning to make received observations ready for inference. This process is illustrated in the image below:

The observation cleaning pipeline running on the server, highlighting the three main steps related to (1) Keys matching (2) Preprocessing and (3) Preparation for inference.

Once the observation has been prepared, it is compared with the last observation used for inference.
This avoids collapsing into a loop whereby very similar observations are processed, thus triggering unnecessary inference and similar actions being executed (which in turn, result in very similar observations being processed again).
We compare observations in terms of their joint-space similarity, which provides us an approximate and quick way of measuring changes in the robot. Clearly, this metric is not adaptive to dynamic changes in the environment (an object changing its position, or disturbances being applied), but we found it to be a good trade-off for the majority of the cases, and to be very effective in avoiding unnecessary inference and state collapse.
Critically, the RobotClient

주어진 관찰이 처리되어야 하는지 제어할 수 있도록, 데드락 (deadlock) 을 피하기 위해 관찰을 필터링합니다.

클라이언트에서 전송되고 must_go=True 태그가 붙은 관찰은 유사성 지표에 관계없이 처리됩니다.

정책 워크플로우 (Policy workflow): 수신된 관찰은 마지막 추론 (inference) 에 사용된 관찰과 비교되며, 충분히 다르거나 must_go 인 경우에만 처리됩니다.

마지막으로, PolicyServer 가 항상 최신 이용 가능한 관찰을 처리하도록 보장하기 위해 이전 관찰이 성공적으로 처리될 때까지 incoming observations 를 블록합니다. 이를 통해 우리는 PolicyServer 의 큐 (queue) 를 활용하여 서버가 관찰을 처리할 준비가 될 때까지 incoming observations 를 큐에 등록하지 않도록 합니다 (아래 참조).

클라이언트는 1/fps 초마다 서버를 핑 (ping) 하지만, 이전 관찰이 성공적으로 처리될 때까지 관찰은 처리를 위해 큐에 등록되지 않습니다.

실용적인 관점에서, 비동기 추론 (async inference) 에는 두 가지 시간 척도가 중요합니다:

환경 단계 (Environment step): 로봇이 행동을 수행하는 속도를 나타냅니다.추론 지연 (Inference latency): 포워드 패스 + 네트워크 라운드트립. 정책 추론 시간에 비해 네트워크 라운드트립을 무시할 수 있다고 가정할 수 있지만, 모든 설정에서 그렇지 않을 수도 있습니다.

중요하게, 비율은 다른 행동을 유도합니다:

  • : 환경이 추론보다 빠르게 진화합니다. 이 시나리오에서는 큐가 빠르게 비어지며 우리는 순차적 제어 (sequential control) 로 퇴보합니다.
  • : 서버는 따라잡습니다. 큐는 항상 (거의) 가득 차 있습니다.

비록 중요한 것은 주어진 시간당 큐에 사용할 수 있는 행동의 수를 결정합니다. aforementioned sequential limit 을 피하기 위해 다음을 할 수 있습니다:

정책 서버에 더 많은 컴퓨팅 리소스를 사용: GPU 에 서버를 호스팅하고, 결과적으로 더 많은 컴퓨팅 리소스를 할당하여 지연 (latency) 를 줄입니다.

  • 관찰을 더 자주 서버에 전송: 큐 길이가 최대 크기의 분수 (fraction) 미만으로 떨어질 때 새로운 관찰을 전송합니다.

이러한 방법은 순차적 추론 (빈 큐, 대기) 을 재현합니다.

  • 각 시간 단계마다 관찰을 전송: 최대 컴퓨팅, 최소 지연.

실험 (아래 그래프 참조) 은 관찰이 필터링되지 않을 때 (모두 must-go) 이 좋은 트레이드오프를 제공합니다. 이 매개변수를 필요에 맞게 튜닝하기 위해 설정과 우리의 문서를 따르는 것을 권장합니다.

주어진 시간당 큐에 사용할 수 있는 행동의 수, g 의 함수입니다. 더 큰 g 값은 더 빈번한 업데이트와 더 높은 컴퓨팅 비용을 의미합니다. 0 에 가까운 g 값은 순차적 추론을 재현합니다 (빈 큐, 대기). 실험에서 우리는 g~0.7 이 좋은 트레이드오프임을 발견했습니다.

비동기 추론은 로봇 정책의 성능을 개선하는 간단하면서도 효과적인 방법입니다. SmolVLA 를 사용한 우리의 실험에서는 비동기 추론이 ~2 배의 작업 완료 시간 속도 향상과 유사한 작업 성공률, 그리고 더 긴 루프 (tighter loop) 에서 오는 더 적응적인 제어를 제공합니다.

비동기 추론을 사용하여 정책을 실행하려면, 정책 경로 또는 청크 크기 임계값 (chunk size threshold) 과 같은 커스텀 매개변수 (예: policy path) 를 포함하여 우리의 튜토리얼을 따르시면 됩니다. 비동기 추론은 행동 청크링 (action chunking) 을 지원하는 정책을 지원합니다!

우리는 로봇 정책의 성능을 개선하는 간단하면서도 효과적인 방법을 제공하는 비동기 추론을 소개했습니다. SmolVLA 를 사용한 우리의 실험에서는 비동기 추론이 ~2 배의 작업 완료 시간 속도 향상과 유사한 작업 성공률, 그리고 더 긴 루프 (tighter loop) 에서 오는 더 적응적인 제어를 제공합니다.

, 그리고 이 내용을 더 논의하기 위해 우리의 Discord 커뮤니티 🤗 에 참여할 수 있습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Hugging Face Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
2

댓글

0