OpenPI 완전 분석 문서

대상 프로젝트: Physical-Intelligence/openpi 작성 기준: 2026-05-22 KST 기준 GitHub README, GitHub tree, 주요 raw 코드, Physical Intelligence 공식 블로그, arXiv 논문, DROID/ALOHA/LIBERO 관련 공개 자료 작성 목적: 팀 연구 시작 전, 창현님이 외부 도움 없이 OpenPI의 모델·코드·학습·추론·서빙·데이터 변환·확장 포인트를 이해하고 수정/발전시킬 수 있도록 하는 연구팀 온보딩/해부 문서


0. 먼저 읽어야 하는 결론

OpenPI는 단순히 “로봇 모델 checkpoint를 배포하는 repo”가 아니다. 구조적으로 보면 다음 네 층이 하나로 묶인 Physical AI/VLA 연구용 end-to-end stack이다.

[1] π-family model implementations
    ├─ π0       : flow-matching VLA, continuous action chunk 생성
    ├─ π0-FAST  : autoregressive VLA, FAST action tokenizer 기반 discrete action token 생성
    └─ π0.5     : π0 계열 업그레이드, knowledge insulation + flow-matching head

[2] embodiment/data adaptation layer
    ├─ policies/aloha_policy.py
    ├─ policies/droid_policy.py
    ├─ policies/libero_policy.py
    └─ transforms.py + training/config.py

[3] training / fine-tuning layer
    ├─ scripts/compute_norm_stats.py
    ├─ scripts/train.py
    ├─ scripts/train_pytorch.py
    ├─ training/data_loader.py
    ├─ training/checkpoints.py
    ├─ training/optimizer.py
    └─ training/weight_loaders.py

[4] runtime / remote inference layer
    ├─ scripts/serve_policy.py
    ├─ serving/websocket_policy_server.py
    └─ packages/openpi-client/src/openpi_client/*

이 repo를 이해할 때 가장 중요한 mental model은 다음이다.

OpenPI의 핵심은 “거대한 VLM backbone + robot action head”가 아니라, 그 모델을 실제 로봇 embodiment에 붙이기 위한 transform → normalize → model → unnormalize → robot action 파이프라인 전체다.

즉, 모델 구조만 보면 절반만 이해한 것이다. 실제로 연구/수정/성능 최적화를 하려면 다음 질문에 답할 수 있어야 한다.

  1. 내 로봇의 camera/state/action schema가 OpenPI 내부 표준 schema로 어떻게 바뀌는가?
  2. state/action normalization statistics는 어디서 오고, 학습/추론에서 언제 적용되는가?
  3. π0/π0.5는 action을 continuous flow matching으로 만들고, π0-FAST는 왜 token sequence로 만드는가?
  4. policy server를 띄웠을 때 robot laptop과 GPU server 사이에서 어떤 데이터가 오가는가?
  5. 학습할 때 LeRobot/RLDS dataset sample은 어떤 transform stack을 거쳐 Observation/Actions가 되는가?
  6. 병목 최적화 관점에서 vision encoder, LLM backbone, action sampling loop, token decoding, websocket serialization 중 어디가 실제 bottleneck인가?

이 문서는 위 질문들을 코드 경로 기준으로 답하도록 구성했다.


1. 검증 경계와 문서 사용법

1.1 확인한 주요 자료

이 문서는 다음 자료를 직접 확인한 내용을 기반으로 작성했다.

구분 자료 사용한 내용
Repo Physical-Intelligence/openpi README 모델 목록, checkpoint 목록, 요구 GPU memory, 설치, inference/fine-tuning/PyTorch 지원, troubleshooting
Repo tree GitHub directory pages top-level, src/openpi, models, policies, training, serving, examples, docs, packages/openpi-client 파일 구조
Raw code model.py, pi0.py, pi0_fast.py, policy.py, policy_config.py, transforms.py, training/config.py, data_loader.py, checkpoints.py, serve_policy.py, websocket server/client 등 핵심 코드 흐름 분석
Official PI blog π0, Open-sourcing π0, FAST, π0.5 blog 모델 의도와 design rationale
Papers π0 arXiv, FAST arXiv, Knowledge Insulation arXiv 모델/학습 방법의 논문-level 근거
Benchmarks/platforms DROID, ALOHA, LIBERO 자료 example별 robot/dataset 의미

1.2 주의할 점

현재 문서는 GitHub 웹 페이지와 공개 raw source로 확인 가능한 범위에서 만든 “실전용 1차 완전 분석본”이다. 내 실행 환경에서는 GitHub repo 전체를 로컬에 clone해서 모든 파일을 byte-level로 열어보는 것은 DNS 문제로 실패했다. 따라서 .github workflow 내부 YAML의 세부 step, 일부 patch file의 모든 내부 line, notebook cell 전체, binary/이미지/lockfile 세부 내용은 “파일 역할” 중심으로 정리했다.

그럼에도 실제 연구/수정에 필요한 핵심 경로, 즉 모델·데이터 transform·training·policy inference·remote serving·example 실행 경로는 raw code와 README를 바탕으로 상세히 분석했다.


2. OpenPI가 다루는 모든 모델

README 기준 OpenPI는 세 가지 모델 계열을 다룬다.

모델 계열 repo 내 의미 action 생성 방식 핵심 차이
π0 base flow-based VLA continuous action chunk를 flow matching으로 생성 PaliGemma/VLM backbone + action expert, inference는 denoising ODE/Euler step
π0-FAST autoregressive VLA FAST tokenizer가 만든 discrete action tokens를 next-token prediction으로 생성 action을 DCT+BPE token sequence로 압축 후 LLM-style decoding
π0.5 π0 upgraded version repo에서는 flow matching head만 지원 knowledge insulation으로 VLM knowledge transfer와 robot policy co-training 개선

2.1 Checkpoint 관점의 전체 모델 목록

README에 나온 checkpoint를 기준으로 보면 다음과 같이 나뉜다.

Base checkpoints

이름 config/모델 계열 용도 checkpoint path 해석
π0 Pi0Config, model_type=PI0 fine-tuning base gs://openpi-assets/checkpoints/pi0_base flow-matching VLA base
π0-FAST Pi0FASTConfig, model_type=PI0_FAST fine-tuning base gs://openpi-assets/checkpoints/pi0_fast_base autoregressive FAST base
π0.5 Pi0Config(pi05=True), model_type=PI05 fine-tuning base gs://openpi-assets/checkpoints/pi05_base π0.5 flow matching base

Expert / fine-tuned checkpoints

이름 용도 checkpoint path 설명
π0-FAST-DROID inference gs://openpi-assets/checkpoints/pi0_fast_droid DROID dataset fine-tuned π0-FAST. 새 DROID scene에서 zero-shot tabletop manipulation 목적
π0-DROID fine-tuning gs://openpi-assets/checkpoints/pi0_droid π0-FAST-DROID보다 inference는 빠르지만 language following은 약할 수 있음
π0-ALOHA-towel inference gs://openpi-assets/checkpoints/pi0_aloha_towel ALOHA towel folding
π0-ALOHA-tupperware inference gs://openpi-assets/checkpoints/pi0_aloha_tupperware tupperware 열고 내용물을 plate에 놓는 작업
π0-ALOHA-pen-uncap inference gs://openpi-assets/checkpoints/pi0_aloha_pen_uncap public ALOHA pen uncapping
π0.5-LIBERO inference gs://openpi-assets/checkpoints/pi05_libero LIBERO benchmark fine-tuned
π0.5-DROID inference/fine-tuning gs://openpi-assets/checkpoints/pi05_droid DROID + knowledge insulation, fast inference와 language-following 균형

여기서 “모델 계열”과 “checkpoint 이름”을 혼동하면 안 된다. 예를 들어 pi05_droid는 모델 구조로는 π0.5 계열이고, training config/data transform은 DROID embodiment용이다.


3. π0: flow-based vision-language-action model

3.1 π0의 핵심 아이디어

π0는 이미지·언어·행동을 하나의 generative policy 안에 넣은 generalist robot policy다. 논문/블로그 관점에서 π0의 핵심은 다음이다.

  1. VLM backbone을 사용한다. OpenPI 코드에서는 PaliGemma 계열 구조가 중심이다.
  2. 입력은 image tokens + language tokens + robot state/action 관련 tokens로 구성된다.
  3. action은 단일 action이 아니라 action chunk다. 즉, 한 번 infer하면 (action_horizon, action_dim) 모양의 여러 future action을 예측한다.
  4. action 생성은 diffusion/flow matching 계열이다. 학습 시 noisy action과 timestep을 주고 vector field를 예측하게 한다.
  5. inference 시 Gaussian noise에서 시작해 여러 denoising step을 거쳐 action chunk를 얻는다.

창현님 관점에서 가장 중요한 포인트는 π0는 LLM처럼 token을 하나씩 생성하는 모델이 아니라, continuous action tensor를 ODE처럼 update하는 모델이라는 점이다. 따라서 latency는 크게 다음에 좌우된다.

latency ≈ vision/prefix prefill 1회
        + num_steps × action-suffix forward
        + postprocess/unnormalize/serialization

num_steps=10이라면 action expert/LLM suffix pass가 10회 들어간다. 이 부분이 profiling에서 매우 중요하다.

3.2 코드 위치

파일 역할
src/openpi/models/pi0.py π0/π0.5 JAX/Flax NNX 구현 본체
src/openpi/models/pi0_config.py Pi0Config, variant, LoRA/freeze 설정
src/openpi/models/model.py 공통 Observation, Actions, BaseModelConfig, BaseModel, checkpoint restore
src/openpi/models/gemma.py PaliGemma/Gemma transformer wrapper
src/openpi/models/siglip.py image encoder
src/openpi/models/vit.py vision transformer 관련 구현
src/openpi/models/lora.py LoRA adapter/freeze 관련 코드

3.3 Pi0 클래스의 전체 구조

Pi0는 크게 다음 메서드로 이해하면 된다.

Pi0.__init__
  ├─ PaliGemma LLM/action expert 초기화
  ├─ SigLIP image encoder 초기화
  ├─ action input/output projection 정의
  ├─ π0.5 여부에 따라 AdaRMS time conditioning 또는 state/action-time MLP 구성

Pi0.embed_prefix(obs)
  ├─ image들을 SigLIP으로 token embedding화
  ├─ prompt token을 LLM embedding으로 변환
  └─ prefix token/mask/attention mask 생성

Pi0.embed_suffix(obs, noisy_actions, timestep)
  ├─ π0: state token + noisy action token + time embedding 결합
  ├─ π0.5: noisy action token + AdaRMS condition 생성
  └─ suffix token/mask/attention mask 생성

Pi0.compute_loss(rng, observation, actions, train)
  ├─ observation preprocess/augmentation
  ├─ noise, timestep sampling
  ├─ x_t = t * noise + (1 - t) * actions
  ├─ target vector field u_t = noise - actions
  ├─ prefix+suffix one-shot forward
  └─ predicted vector field와 target MSE

Pi0.sample_actions(rng, observation, num_steps, noise)
  ├─ observation preprocess
  ├─ prefix forward로 KV cache 생성
  ├─ Gaussian noise에서 시작
  ├─ num_steps번 suffix forward + Euler update
  └─ action chunk 반환

3.4 make_attn_mask: attention 구조의 핵심

pi0.pypi0_fast.py 모두 make_attn_mask(input_mask, mask_ar)를 사용한다. 이 함수는 단순 causal mask가 아니라 prefix-LM/block causal mask를 만든다.

핵심 로직은 다음이다.

1. mask_ar를 input_mask와 같은 shape으로 broadcast
2. mask_ar의 cumulative sum을 token axis로 계산
3. i번째 query token이 j번째 key token을 볼 수 있는 조건:
   cumsum[j] <= cumsum[i]
4. padding token은 input_mask로 제거

mask_ar 의미는 다음처럼 이해하면 된다.

mask_ar 패턴 의미
[1, 1, 1, 1] 순수 causal attention
[0, 0, 0, 1, 1, 1] 앞 3개는 bidirectional prefix, 뒤 3개는 causal suffix
[1, 0, 0, 1, 0] block causal: 같은 block 내부는 서로 attend, 이전 block은 attend 가능

π0에서 image token과 prompt token은 보통 prefix로 두어 서로 충분히 attend하게 하고, state/action suffix는 prefix 뒤에 두어 action 생성 조건으로 사용한다.

3.5 embed_prefix: image + language prefix 구성

embed_prefix(obs)는 observation 중에서 action 생성 전에 고정되는 조건부 정보를 embedding한다.

입력은 _model.Observation이다. 이 object는 다음 필드를 갖는다.

Observation
  ├─ images: dict[str, image tensor]
  ├─ image_masks: dict[str, bool mask]
  ├─ state: robot proprioceptive state
  ├─ tokenized_prompt
  ├─ tokenized_prompt_mask
  ├─ token_ar_mask        # π0-FAST용
  └─ token_loss_mask      # π0-FAST용

π0의 prefix는 일반적으로 다음 순서로 쌓인다.

[image tokens from camera 1]
[image tokens from camera 2]
[image tokens from camera 3]
[prompt/language tokens]

각 image는 self.PaliGemma.img로 embedding된다. 이것은 SigLIP vision encoder 경로다. 각 image token에는 image mask가 붙는다. prompt는 tokenizer가 이미 만든 token IDs를 LLM embedding table에 통과시켜 token embedding이 된다.

중요한 점:

  • image token은 prompt/action에 조건을 제공하는 visual context다.
  • prompt token은 language instruction이다.
  • prefix는 action sampling 동안 매 step 변하지 않는다.
  • 그래서 sample_actions에서는 prefix forward를 먼저 돌려 KV cache를 만들고, denoising loop에서는 suffix만 반복한다.

3.6 embed_suffix: state/action/timestep suffix 구성

embed_suffix(obs, noisy_actions, timestep)는 현재 denoising step에서 변하는 action-side 정보를 만든다.

π0의 경우

π0는 suffix에 state token과 action tokens를 넣는다.

[state token]
[action_0 token]
[action_1 token]
...
[action_H-1 token]

각 action token은 continuous vector다. 이 vector는 action_in_proj 같은 linear projection을 통해 transformer hidden dimension으로 들어간다.

timestep은 sinusoidal positional/time embedding으로 바뀐 뒤 action token과 결합된다. 이 부분은 diffusion/flow matching model에서 “현재 noise level이 얼마인지” 알려주는 역할이다.

π0.5의 경우

π0.5는 AdaRMS conditioning을 사용한다. 즉 timestep embedding을 token embedding에 단순 concat하는 대신, Gemma/action expert 내부 normalization/scale 쪽에 conditioning으로 넣는 구조다.

직관적으로는:

π0    : action token 자체에 time embedding을 섞는다.
π0.5  : transformer block 내부 normalization 경로에 time condition을 넣는다.

이 차이는 “knowledge insulation”과도 연결된다. π0.5는 VLM backbone의 기존 지식을 과도하게 망가뜨리지 않으면서 action expert 쪽을 학습하기 위한 구조적 개선을 포함한다.

3.7 compute_loss: flow matching 학습

π0/π0.5 학습의 가장 중요한 수식은 코드상 다음 형태다.

noise ~ N(0, I)
t ~ Beta(1.5, 1), scaled into [0.001, 1]
x_t = t * noise + (1 - t) * actions
u_t = noise - actions
model predicts v_t = f(x_t, t, observation)
loss = MSE(v_t, u_t)

여기서 관례가 약간 헷갈릴 수 있다.

  • 코드 주석에서는 t=1이 noise, t=0이 clean action이라고 본다.
  • 따라서 x_t = t * noise + (1 - t) * actions는 자연스럽다.
  • target vector field는 noise - actions다.
  • inference에서는 noise에서 시작해서 t를 1에서 0으로 줄여가며 update한다.

왜 Beta(1.5, 1)을 쓰나?

균등분포 대신 Beta 분포를 쓰면 특정 time region에 더 많은 학습 weight를 줄 수 있다. 정확한 의도는 논문/구현 설계의 영역이지만, diffusion/flow matching에서 timestep sampling distribution은 어느 noise level에서 vector field를 더 잘 학습하게 할지를 결정한다.

loss shape

compute_loss는 보통 action chunk 단위 loss를 반환한다.

loss shape ≈ [batch, action_horizon]

이후 scripts/train.pyloss_fn에서 평균을 내어 scalar loss로 만든다.

3.8 sample_actions: inference의 실제 계산 경로

π0/π0.5 inference는 다음 구조다.

1. observation preprocess
2. prefix embedding 생성
3. prefix LLM forward로 KV cache 생성
4. x_1 = Gaussian noise 또는 사용자가 지정한 noise
5. for k in 0..num_steps-1:
      t = 1 - k / num_steps
      suffix = embed_suffix(obs, x_t, t)
      v_t = LLM/action_head(prefix_cache, suffix)
      x_{t-dt} = x_t + dt * v_t
6. x_0를 actions로 반환

이때 num_steps는 latency와 성능 사이의 직접 trade-off다.

num_steps 장점 단점
작음 latency 낮음, real-time 유리 action 품질 저하 가능
denoising trajectory가 더 정교할 수 있음 suffix forward 반복 증가로 latency 증가

창현님이 profiling 중인 shallow/distilled π0 계열에서 num_steps=10을 쓰고 있다면, model-only latency를 볼 때 반드시 다음처럼 분해해야 한다.

T_total = T_preprocess
        + T_prefix_prefill
        + Σ_{i=1}^{num_steps} T_suffix_step_i
        + T_postprocess

Pytorch Profiler/Nsight Systems에서 step별 kernel group을 확인하면, num_steps 반복 구조가 timeline에 주기적으로 나타날 가능성이 높다.


4. π0-FAST: autoregressive VLA + FAST action tokenizer

4.1 π0-FAST의 핵심 아이디어

π0-FAST는 π0처럼 continuous flow를 반복 integration하는 대신, action chunk를 discrete token sequence로 바꾼 뒤 LLM의 next-token prediction 문제로 푼다.

FAST의 핵심은 action sequence를 그대로 scalar binning하지 않는다는 점이다. robot action은 시간적으로 강하게 correlated되어 있고, 특히 고주파 제어에서는 인접 step이 비슷한 구조를 갖는다. FAST는 이를 활용해:

  1. action chunk를 frequency domain처럼 다루는 DCT 기반 표현으로 바꾼다.
  2. BPE류 tokenizer로 반복 패턴을 압축한다.
  3. action chunk 하나를 비교적 짧은 token sequence로 표현한다.
  4. VLA는 prompt/image/state 조건에서 action token들을 autoregressive하게 생성한다.

4.2 코드 위치

파일 역할
src/openpi/models/pi0_fast.py π0-FAST model implementation
src/openpi/models/gemma_fast.py FAST용 Gemma/PaliGemma autoregressive backbone
src/openpi/models/tokenizer.py PaliGemma tokenizer + FAST tokenizer wrapper
src/openpi/models/utils/fsq_tokenizer.py tokenizer utility
src/openpi/transforms.py TokenizeFASTInputs, ExtractFASTActions

4.3 Pi0FASTConfig

Pi0FASTConfigBaseModelConfig를 상속한다. 주요 default는 다음 개념이다.

model_type       = PI0_FAST
action_dim       = 32
action_horizon   = 32
max_token_len    = 250
paligemma_variant = gemma_2b 계열
fast_model_tokenizer = FASTTokenizer 또는 custom tokenizer

inputs_spec은 π0와 다르게 token_ar_mask, token_loss_mask를 요구한다. 이유는 π0-FAST가 next-token prediction을 하기 때문이다.

4.4 embed_inputs: image + tokenized prompt/action sequence

π0-FAST의 embed_inputs는 π0의 prefix/suffix 분리와 다르게, image token과 tokenized prompt/action sequence를 하나의 sequence로 구성한다.

[image tokens]
[tokenized language/state/action tokens]

여기서 token_ar_mask가 매우 중요하다. FAST token sequence에는 language prompt, state representation, action target tokens가 섞일 수 있다. 어떤 token에 loss를 걸지, 어떤 token이 causal하게 다음 token을 예측해야 하는지는 tokenizer/transform이 만든 mask로 결정된다.

4.5 compute_loss: next-token cross entropy

π0-FAST는 flow matching MSE가 아니라 token CE loss를 쓴다.

핵심 흐름:

1. observation preprocess
2. embed_inputs로 image+token sequence embedding 생성
3. make_attn_mask로 causal/prefix attention mask 생성
4. input sequence에서 마지막 token을 제외하고 forward
5. target은 tokenized sequence를 한 칸 shift한 next token
6. logits → log_softmax
7. token_loss_mask가 True인 위치만 CE 계산

즉 학습 목표는 다음이다.

maximize p(action_tokens | image_tokens, prompt_tokens, state_tokens)

4.6 sample_actions: autoregressive decoding

π0-FAST inference는 다음과 같다.

1. observation preprocess
2. image + prompt/state prefix embedding 생성
3. left-to-right align
4. prefix forward로 KV cache 생성
5. max_decoding_steps까지 token 생성
6. EOS가 나오면 early stop
7. generated tokens를 FAST tokenizer로 action chunk로 복원

코드에는 temperature가 있다.

temperature 의미
0.0 argmax decoding, deterministic
>0 categorical sampling, stochastic

4.7 π0 vs π0-FAST latency 비교 관점

항목 π0/π0.5 π0-FAST
action representation continuous tensor discrete tokens
training loss flow matching MSE next-token CE
inference loop num_steps denoising max_decoding_steps autoregressive decoding
parallelism action chunk tokens를 suffix로 병렬 처리 가능 token을 순차 생성하므로 decode loop dependency 큼
장점 action chunk를 비교적 빠르게 생성 가능 LLM-style scaling/next-token training과 잘 맞음
단점 denoising step 반복 autoregressive token decoding latency

README에서도 π0-DROID가 π0-FAST-DROID보다 inference는 빠를 수 있지만 language following은 약할 수 있다고 설명한다. 이 trade-off는 연구 주제로 매우 좋다.


5. π0.5와 Knowledge Insulation

5.1 π0.5의 목적

π0.5는 π0의 upgraded version이다. 공식 설명 기준으로는 더 나은 open-world generalization을 목표로 하며, knowledge insulation을 통해 heterogeneous data를 더 잘 다룬다.

중요한 점은 README가 명시하듯이:

이 repo에서는 π0.5에 대해 현재 flow matching head만 training/inference 지원한다.

즉 OpenPI repo 관점에서 π0.5는 Pi0Config(pi05=True)로 활성화되는 π0 구현의 variant로 보는 것이 가장 실용적이다.

5.2 코드상 차이

Pi0.__init__에서 self.pi05 = config.pi05가 핵심 분기다.

π0.5인 경우:

1. action expert 쪽에 AdaRMS conditioning 사용
2. timestep embedding을 action token과 단순 concat하지 않고 conditioning vector로 사용
3. config.model_type은 PI05
4. model transform에서 discrete_state_input 옵션이 고려됨

π0인 경우:

1. state token을 suffix에 추가
2. action token과 time embedding을 concat/MLP로 결합
3. 일반 RMS/attention 구조

5.3 Knowledge Insulation의 직관

VLM backbone은 이미 이미지/언어에 대한 많은 지식을 갖고 있다. 로봇 action expert를 붙여 대규모 robot data로 co-training하면 다음 문제가 생길 수 있다.

robot action objective가 VLM backbone을 너무 크게 바꿈
→ 기존 visual/language knowledge가 손상
→ open-world generalization 저하

Knowledge insulation의 직관은 다음이다.

VLM backbone의 일반 지식은 보존하고,
robot action generation에 필요한 specialized path/action expert 쪽을 효율적으로 학습한다.

창현님 관점에서 이것은 representation drift control 문제로 보면 좋다. GPU/system 성능보다는 model architecture/training dynamics 쪽이지만, fine-tuning 시 freeze/LoRA/EMA/normalization 선택과 직접 연결된다.


6. OpenPI의 표준 데이터 구조

6.1 ObservationActions

src/openpi/models/model.py가 repo 전체의 데이터 계약을 정의한다.

내부 표준 입력은 다음과 같다.

Observation
  images: dict[str, float array]
    - key 예: base_0_rgb, left_wrist_0_rgb, right_wrist_0_rgb
    - 값 범위: float32 [-1, 1]

  image_masks: dict[str, bool]
    - 해당 camera view가 실제로 유효한지 표시

  state: float array
    - low-dimensional robot proprioceptive state

  tokenized_prompt: int array | None
  tokenized_prompt_mask: bool array | None

  token_ar_mask: int array | None
    - π0-FAST autoregressive mask

  token_loss_mask: bool array | None
    - π0-FAST loss 위치 mask

Actions
  actions: float array with shape [batch, action_horizon, action_dim]

6.2 이미지 key

model.py의 default image keys는 다음 세 개다.

base_0_rgb
left_wrist_0_rgb
right_wrist_0_rgb

이것은 매우 중요하다. 만약 내 로봇이 camera 2개만 쓴다면 다음 중 하나를 해야 한다.

  1. unused camera slot에 zero image를 넣고 image_mask=False로 둔다.
  2. 모델 type에 따라 FAST에서는 mask convention이 다를 수 있으므로 policy 예제를 참고한다.
  3. 새 model/config를 만들어 image_keys를 명시적으로 바꾼다. 단, checkpoint와 pretraining distribution이 달라지므로 신중해야 한다.

UR5 예제 README가 좋은 힌트를 준다. UR5는 base image와 wrist image만 있을 수 있으므로 right wrist slot을 zero로 채우고 mask를 조절한다.

6.3 이미지 전처리

Observation.from_dictpreprocess_observation은 다음을 담당한다.

단계 역할
Observation.from_dict nested dict를 typed dataclass로 변환
uint8 image 처리 uint8 [0,255] 이미지를 float32 [-1,1]로 변환
torch uint8 처리 PyTorch tensor면 channel order 변환까지 처리
preprocess_observation image key 존재 확인, resize, augmentation, mask fill
train augmentation crop/resize/rotate/color jitter 등 image augmentation 적용

성능 관점:

  • robot client에서 이미지를 224×224 uint8로 보내면 network bandwidth가 줄어든다.
  • server에서 Observation.from_dict가 float 변환을 수행한다.
  • profiling 시 image resize가 CPU 병목인지, GPU model 병목인지 구분해야 한다.

7. transforms.py: OpenPI 수정의 핵심 파일

OpenPI에서 새로운 robot/dataset을 붙일 때 가장 많이 건드릴 가능성이 큰 파일은 transforms.py 자체가 아니라, transforms.py의 transform들을 조합하는 training/config.pypolicies/*_policy.py다. 하지만 transform들의 의미를 모르면 config를 절대 안정적으로 수정할 수 없다.

7.1 Transform stack의 기본 개념

OpenPI의 transform은 모두 다음 protocol을 따른다.

DataTransformFn:
  input : nested dict
  output: nested dict

그리고 Group은 input transform과 output transform을 함께 담는다.

Group
  inputs  : model 입력 전에 적용할 transform sequence
  outputs : model 출력 후 적용할 transform sequence

중요한 설계:

Group.push(inputs=[A], outputs=[B])
  • input transform은 기존 뒤에 append된다.
  • output transform은 기존 앞에 prepend된다.

이렇게 해야 input에서 한 변환을 추가했을 때 output에서 그 역변환이 반대 순서로 적용된다.

예:

input : absolute action → delta action
model : delta action 예측
output: delta action → absolute action

7.2 RepackTransform

RepackTransform은 dataset/environment별 key를 OpenPI 표준 key로 바꾸는 transform이다.

예를 들어 LIBERO data config에서는 다음 개념의 mapping이 있다.

dataset key                    → policy/model expected key
image                          → observation/image
wrist_image                    → observation/wrist_image
state                          → observation/state
actions                        → actions
prompt                         → prompt

정확히 말하면 RepackTransform은 flatten된 key path를 이용해 nested dict를 재구성한다.

수정할 때 체크리스트:

  1. dataset sample에서 실제 key 이름을 확인한다.
  2. robot runtime에서 server에 보내는 observation key 이름을 확인한다.
  3. 두 schema가 최대한 일치하도록 repack mapping을 만든다.
  4. policies/*Inputs가 기대하는 key와 맞는지 확인한다.

7.3 Normalize / Unnormalize

OpenPI는 state/action normalization을 매우 중요하게 다룬다.

training input path:
  raw state/action
  → data transforms
  → Normalize
  → model transforms
  → model

inference output path:
  model output normalized action
  → model output transforms
  → Unnormalize
  → data output transforms
  → robot action

두 normalization mode가 있다.

mode 수식 사용 상황
z-score (x - mean) / std 일반 normalization
quantile (x - q01)/(q99-q01)*2 - 1 π0-FAST/π0.5 계열에서 자주 사용

DataConfigFactory.create_base_config를 보면 use_quantile_normmodel_type != PI0일 때 true가 된다. 즉 일반 π0는 z-score, π0.5/π0-FAST는 quantile normalization 경향이 있다.

7.4 DeltaActions / AbsoluteActions

많은 robot dataset은 absolute joint target을 저장한다. 하지만 π0 계열은 delta action으로 학습된 경우가 있다.

DeltaActions(mask)는 다음을 수행한다.

actions[..., selected_dims] -= state[..., selected_dims]

AbsoluteActions(mask)는 inference output에서 반대로:

actions[..., selected_dims] += state[..., selected_dims]

여기서 mask는 어떤 action dimension을 delta로 바꿀지 결정한다.

예:

make_bool_mask(6, -1)
→ first 6 dims는 delta, 마지막 1 dim은 absolute

로봇에서 gripper는 보통 absolute open/close position으로 두는 경우가 많으므로 delta 변환하지 않는다.

7.5 TokenizePrompt

π0/π0.5용 prompt tokenizer다.

input dict에 prompt가 있어야 함
prompt string을 PaliGemma tokenizer로 token IDs + mask로 변환

π0.5에서는 discrete_state_input 옵션도 고려된다. 이 경우 state가 prompt tokenization에 들어갈 수 있다.

7.6 TokenizeFASTInputsExtractFASTActions

π0-FAST용이다.

TokenizeFASTInputs:

prompt + state + actions(optional)
→ tokenized_prompt
→ tokenized_prompt_mask
→ token_ar_mask
→ token_loss_mask

훈련 시 actions가 있으므로 action target tokens까지 만든다. 추론 시 actions가 없으므로 prefix tokens만 만들고 model이 action tokens를 생성한다.

ExtractFASTActions:

generated action token IDs
→ FAST tokenizer가 continuous action chunk로 decode
→ data["actions"]에 복원

8. training/config.py: 프로젝트 전체를 묶는 wiring file

OpenPI에서 config는 단순 hyperparameter 모음이 아니다. config가 사실상 다음 전체 graph를 정의한다.

model architecture
+ dataset source
+ repack transform
+ robot-specific input/output transform
+ model-specific tokenizer/resize/padding transform
+ normalization stats source
+ optimizer/lr schedule
+ checkpoint loading
+ freezing/LoRA/FSDP/EMA

8.1 DataConfig

DataConfig는 데이터가 어떻게 model-ready format으로 바뀌는지를 담는다.

field 의미
repo_id LeRobot dataset repo id 또는 fake
asset_id normalization stats directory 이름
norm_stats state/actions normalization statistics
repack_transforms raw dataset key를 policy key로 변환
data_transforms robot-specific transform
model_transforms resize/tokenize/pad 등 model-specific transform
use_quantile_norm quantile normalization 여부
action_sequence_keys action chunk를 만들 key
prompt_from_task LeRobot task field를 prompt로 사용할지
rlds_data_dir DROID RLDS training용
action_space DROID action space
datasets RLDS dataset mixture

8.2 ModelTransformFactory

모델 타입에 따라 transform이 달라진다.

π0

InjectDefaultPrompt
ResizeImages(224, 224)
TokenizePrompt(PaligemmaTokenizer)
PadStatesAndActions(action_dim)

π0.5

π0와 비슷하지만 discrete_state_input 옵션이 tokenizer에 전달된다.

π0-FAST

InjectDefaultPrompt
ResizeImages(224, 224)
TokenizeFASTInputs(FASTTokenizer)

output:
ExtractFASTActions(FASTTokenizer)

즉 π0-FAST는 model output이 처음에는 token sequence이므로, 반드시 output transform에서 action chunk로 복원해야 한다.

8.3 LeRobotAlohaDataConfig

ALOHA용 data config다.

핵심:

raw dataset:
  observation.images.top
  observation.state
  action

repack:
  images/cam_high
  state
  actions

이후 AlohaInputs, AlohaOutputs가 실제 ALOHA convention을 OpenPI convention에 맞춘다.

옵션:

field 의미
use_delta_joint_actions=True joint action을 state 대비 delta로 바꿈
default_prompt prompt 없을 때 넣을 instruction
adapt_to_pi=True standard ALOHA convention을 PI internal runtime convention으로 맞춤

8.4 LeRobotLiberoDataConfig

LIBERO용이다. README가 custom dataset 예제로 LIBERO를 사용하기 때문에 이 클래스를 매우 잘 읽어야 한다.

핵심 구성:

repack_transform:
  observation/image       <- image
  observation/wrist_image <- wrist_image
  observation/state       <- state
  actions                 <- actions
  prompt                  <- prompt

data_transforms:
  LiberoInputs(model_type)
  LiberoOutputs()

model_transforms:
  ModelTransformFactory()(model_config)

LIBERO에서 raw actions는 이미 delta action이라 기본적으로 추가 delta transform을 적용하지 않는다. 단, old Pi0 checkpoint 호환을 위해 extra_delta_transform 옵션이 있다.

8.5 RLDSDroidDataConfig

DROID full dataset pretraining/fine-tuning을 위한 RLDS format config다.

특징:

  • RLDS data loader를 사용한다.
  • DROID full dataset은 규모가 크므로 LeRobot보다 RLDS 경로가 효율적이다.
  • action space가 joint position이면 delta conversion을 추가한다.
  • 기본 dataset list에는 DROID v1.0.1과 filter json path가 들어간다.

8.6 LeRobotDROIDDataConfig

소규모 custom DROID dataset을 LeRobot format으로 변환해 fine-tuning할 때 쓰는 예시 config다.

핵심:

  • custom DROID dataset이 수십 시간 이하라면 LeRobot format이 관리하기 쉽다.
  • joint velocity action을 가정하므로 추가 delta transform을 적용하지 않는다.

8.7 TrainConfig

TrainConfig는 실제 학습 run 하나를 정의한다.

중요 field:

field 의미
name config 이름. CLI에서 pi05_libero처럼 사용
model Pi0Config, Pi0FASTConfig
weight_loader base checkpoint / PaliGemma checkpoint / no-op
pytorch_weight_path PyTorch training 시작 weight
pytorch_training_precision bfloat16 또는 float32
lr_schedule cosine schedule 등
optimizer AdamW 등
ema_decay EMA 사용 여부/decay
freeze_filter frozen parameter 지정
data DataConfigFactory
batch_size global batch size
num_train_steps training step 수
save_interval checkpoint 저장 간격
fsdp_devices JAX FSDP shard device 수

9. policy_config.pypolicy.py: 추론 pipeline의 실제 중심

9.1 create_trained_policy 전체 흐름

src/openpi/policies/policy_config.pycreate_trained_policy는 사용자 입장에서 가장 중요한 함수 중 하나다.

전체 흐름:

create_trained_policy(train_config, checkpoint_dir, ...)
  ├─ checkpoint_dir download/cache
  ├─ PyTorch checkpoint인지 확인: model.safetensors 존재 여부
  ├─ PyTorch면 train_config.model.load_pytorch(...)
  ├─ JAX면 checkpoint_dir/params를 restore해서 train_config.model.load(...)
  ├─ data_config = train_config.data.create(...)
  ├─ norm_stats 없으면 checkpoint_dir/assets에서 로드
  ├─ input transform stack 구성
  │   ├─ optional repack_transforms
  │   ├─ InjectDefaultPrompt
  │   ├─ data_config.data_transforms.inputs
  │   ├─ Normalize
  │   └─ data_config.model_transforms.inputs
  ├─ output transform stack 구성
  │   ├─ data_config.model_transforms.outputs
  │   ├─ Unnormalize
  │   ├─ data_config.data_transforms.outputs
  │   └─ repack_transforms.outputs
  └─ Policy 객체 반환

이 함수가 중요한 이유는 학습과 추론에서 같은 normalization/data transform을 강제하기 때문이다.

9.2 PyTorch/JAX 자동 감지

create_trained_policy는 checkpoint directory에 model.safetensors가 있으면 PyTorch model로 간주한다.

checkpoint_dir/model.safetensors exists
  → PyTorch path
else
  → JAX/Orbax params path

실무 주의:

  • JAX checkpoint는 보통 params/ 구조를 갖는다.
  • PyTorch로 변환한 checkpoint는 model.safetensors를 갖는다.
  • checkpoint path를 잘못 주면 모델 loading path부터 꼬인다.

9.3 Policy.infer line-by-line식 설명

src/openpi/policies/policy.pyPolicy.infer(obs)는 실제 policy server가 호출하는 함수다.

흐름:

1. 입력 obs dict를 copy한다.
   - transform이 in-place 수정할 수 있기 때문이다.

2. input transform stack을 적용한다.
   - repack
   - default prompt injection
   - robot-specific input transform
   - Normalize
   - Resize/tokenize/pad 또는 FAST tokenization

3. JAX model이면:
   - 각 leaf를 jnp.asarray로 바꾸고 batch dimension을 추가한다.
   - rng를 split한다.

4. PyTorch model이면:
   - numpy array를 torch tensor로 바꾼다.
   - device로 move한다.
   - batch dimension을 추가한다.

5. noise argument가 있으면 sample_kwargs에 넣는다.
   - deterministic profiling에서 fixed noise를 넣는 데 유용하다.

6. `_model.Observation.from_dict(inputs)`로 typed observation 생성.

7. model.sample_actions(...) 호출 시간을 잰다.

8. output dict 생성:
   - state
   - actions

9. batch dimension 제거하고 numpy로 변환.

10. output transform stack 적용.
    - FAST token → action decode
    - Unnormalize
    - robot-specific output transform

11. `policy_timing["infer_ms"]` 추가.

12. 최종 dict 반환.

성능 profiling 관점에서 policy_timing["infer_ms"]는 model sampling 시간 중심이다. 하지만 end-to-end latency에는 다음이 추가된다.

client image resize/serialization
+ websocket send
+ server unpack
+ input transforms
+ model infer_ms
+ output transforms
+ server pack/send
+ client unpack
+ robot command dispatch

따라서 model-only latency와 robot closed-loop latency는 반드시 분리해서 측정해야 한다.


10. Remote inference 구조

10.1 왜 remote inference인가?

로봇 제어 laptop/NUC는 보통 강력한 GPU가 없다. OpenPI는 GPU server와 robot runtime을 분리한다.

[Robot control laptop]
  - camera capture
  - robot state read
  - websocket client
  - action execution

        ⇅ msgpack over websocket

[GPU server]
  - OpenPI model checkpoint
  - policy transforms
  - normalization
  - model inference

이 구조는 dependency hell도 줄인다. 로봇 환경에는 ROS/MuJoCo/DROID runtime이 있고, policy server에는 JAX/PyTorch/CUDA/GPU dependency가 있다. 둘을 한 환경에 섞으면 매우 불안정해질 수 있다.

10.2 scripts/serve_policy.py

지원 environment mode:

ALOHA
ALOHA_SIM
DROID
LIBERO

기본 checkpoint mapping:

env default config default checkpoint
ALOHA pi05_aloha gs://openpi-assets/checkpoints/pi05_base
ALOHA_SIM pi0_aloha_sim gs://openpi-assets/checkpoints/pi0_aloha_sim
DROID pi05_droid gs://openpi-assets/checkpoints/pi05_droid
LIBERO pi05_libero gs://openpi-assets/checkpoints/pi05_libero

서버 실행 예:

uv run scripts/serve_policy.py --env DROID

직접 checkpoint를 지정하는 예:

uv run scripts/serve_policy.py policy:checkpoint \
  --policy.config=pi05_droid \
  --policy.dir=gs://openpi-assets/checkpoints/pi05_droid

10.3 WebsocketPolicyServer

src/openpi/serving/websocket_policy_server.py는 다음을 한다.

1. websocket server open
2. client connect 시 metadata 전송
3. loop:
     - msgpack_numpy로 observation 수신
     - policy.infer(obs)
     - server_timing 기록
     - msgpack_numpy로 action dict 전송
4. /healthz endpoint 제공

서버 timing에는:

server_timing["infer_ms"]
server_timing["prev_total_ms"]

같은 값이 들어간다. 이를 이용해 model inference와 이전 request total time을 대략적으로 볼 수 있다.

10.4 WebsocketClientPolicy

packages/openpi-client/src/openpi_client/websocket_client_policy.py는 robot side에서 사용한다.

흐름:

1. host/port로 websocket URI 구성
2. server가 뜰 때까지 retry
3. 첫 recv로 server metadata 수신
4. infer(obs):
    - obs를 msgpack으로 pack
    - websocket send
    - response recv
    - bytes면 unpack해서 dict 반환
    - str이면 server error로 보고 RuntimeError

이 package는 dependency가 작게 설계되어 robot runtime에 쉽게 설치할 수 있다.


11. Training pipeline

11.1 전체 학습 순서

OpenPI fine-tuning은 일반적으로 다음 순서다.

1. dataset 준비
2. dataset을 LeRobot 또는 RLDS format으로 변환
3. DataConfig/TrainConfig 작성
4. normalization stats 계산
5. train.py 실행
6. checkpoint 저장
7. serve_policy.py로 checkpoint serving
8. robot/sim evaluation

11.2 normalization stats 계산

명령:

uv run scripts/compute_norm_stats.py --config-name pi05_libero

compute_norm_stats.py 흐름:

1. config_name으로 TrainConfig 로드
2. data_config 생성
3. RLDS data면 RLDS dataloader 생성
4. 아니면 LeRobot/Torch dataloader 생성
5. repack + data_transforms만 적용
   - model tokenization은 아직 필요 없음
   - string prompt는 제거
6. state/actions에 대해 running stats 계산
7. config.assets_dirs / data_config.repo_id 위치에 저장

왜 prompt string을 제거하는가?

  • norm stats는 state/action 수치에만 필요하다.
  • string은 JAX/numpy stats 계산에 필요 없고 방해된다.

11.3 scripts/train.py 핵심 흐름

학습 script는 다음 단계로 진행된다.

main(config)
  ├─ logging init
  ├─ batch_size가 device_count로 나누어지는지 확인
  ├─ JAX compilation cache 설정
  ├─ rng split
  ├─ FSDP mesh 생성
  ├─ checkpoint manager 초기화
  ├─ wandb init
  ├─ data_loader 생성
  ├─ 첫 batch sanity check/logging
  ├─ train state 초기화 또는 restore
  ├─ train_step jax.jit
  ├─ for step in range(...):
  │    ├─ ptrain_step
  │    ├─ loss/grad_norm/param_norm logging
  │    ├─ next batch
  │    └─ checkpoint save
  └─ checkpoint_manager wait

11.4 init_train_state

init_train_state는 다음을 한다.

1. optimizer 생성
2. model config로 model parameter shape 초기화
3. weight_loader로 base checkpoint partial/full weights 로드
4. model state에 partial params merge
5. frozen params를 bfloat16으로 변환
6. opt_state 초기화
7. EMA params 초기화
8. FSDP sharding 적용

LoRA/freeze fine-tuning에서는 freeze_filter가 매우 중요하다. frozen parameter는 gradient update 대상이 아니며, 일부 frozen params는 bf16으로 변환되어 memory를 줄일 수 있다.

11.5 train_step

train_step은 구조적으로 간단하다.

1. state.model_def + state.params로 model reconstruct
2. model.train()
3. loss_fn:
    - model.compute_loss(rng, observation, actions, train=True)
    - 평균 loss
4. trainable filter에 대해서만 gradient 계산
5. optimizer update
6. model state update
7. EMA update
8. logging info 계산:
    - loss
    - grad_norm
    - param_norm

중요한 점:

  • model.compute_loss가 모델 계열별 loss를 결정한다.
    • π0/π0.5: flow matching MSE
    • π0-FAST: next-token CE
  • train script는 모델별 loss 차이를 모른다. 공통 interface만 호출한다.

11.6 checkpoint 저장

training/checkpoints.py는 checkpoint를 두 종류로 나눠 저장한다.

train_state:
  - optimizer state
  - step
  - train용 state

params:
  - inference에 쓸 parameter subset
  - EMA params가 있으면 EMA params를 inference params로 분리

assets:
  - normalization stats

따라서 inference할 때 checkpoint_dir/paramscheckpoint_dir/assets/<asset_id>가 모두 중요하다.


12. Data loader 구조

12.1 두 종류 dataset

OpenPI는 크게 두 data source를 지원한다.

source 코드 용도
LeRobot dataset create_torch_dataset custom dataset, LIBERO, ALOHA, small DROID
RLDS DROID create_rlds_dataset full DROID 규모 training

12.2 LeRobot path

create_torch_dataset
  ├─ repo_id == fake이면 FakeDataset
  ├─ LeRobotDatasetMetadata(repo_id)
  ├─ LeRobotDataset(repo_id, delta_timestamps=...)
  └─ prompt_from_task면 PromptFromLeRobotTask transform 적용

delta_timestamps는 action chunk를 만들기 위해 현재 timestep 이후 action_horizon개 action을 가져오는 데 사용된다.

12.3 Transform 적용 순서

transform_dataset은 다음 순서로 transform한다.

raw sample
  → repack_transforms.inputs
  → data_transforms.inputs
  → Normalize
  → model_transforms.inputs
  → Observation.from_dict + actions

이 순서가 중요하다.

  • normalization은 tokenization 전에 state/action에 적용된다.
  • robot-specific transform이 먼저 action dimension/convention을 맞춘다.
  • model-specific transform이 prompt tokenization, image resize, state/action padding을 수행한다.

12.4 TorchDataLoader와 JAX sharding

OpenPI는 JAX training에서도 PyTorch DataLoader를 사용한다. DataLoader가 numpy batch를 만들고, JAX process-local sharded array로 바꾼다.

성능 관점:

  • num_workers를 늘리면 CPU data loading이 빨라질 수 있지만 memory/CPU usage가 증가한다.
  • worker process에서는 JAX GPU preallocation을 끄도록 environment variable을 설정한다.
  • image preprocessing/augmentation이 CPU 병목이면 DataLoader worker 수, image resize 위치, caching 전략이 중요하다.

13. PyTorch support

README 기준 OpenPI는 2025년 9월 PyTorch implementation을 추가했다. 단, 기능 차이가 있다.

13.1 지원 여부

기능 JAX PyTorch
π0 inference/training 지원 지원
π0.5 inference/training 지원 지원
π0-FAST 지원 미지원
mixed precision training 지원/JAX mixed style 미지원
FSDP training 지원 미지원
LoRA training 지원 미지원
EMA training 지원 미지원

13.2 PyTorch 코드 위치

파일/폴더 역할
src/openpi/models_pytorch/gemma_pytorch.py Gemma/PaliGemma PyTorch wrapper
src/openpi/models_pytorch/pi0_pytorch.py π0/π0.5 PyTorch implementation
src/openpi/models_pytorch/preprocessing_pytorch.py PyTorch preprocessing
src/openpi/models_pytorch/transformers_replace/models/gemma/* HF transformers Gemma patch
src/openpi/models_pytorch/transformers_replace/models/paligemma/* HF PaliGemma patch
src/openpi/models_pytorch/transformers_replace/models/siglip/* HF SigLIP patch

13.3 transformers patch가 필요한 이유

README는 patch 이유를 세 가지로 설명한다.

  1. AdaRMS 지원
  2. activation precision control
  3. KV cache를 update 없이 사용할 수 있게 함

즉 OpenPI PyTorch implementation은 vanilla HuggingFace PaliGemma/Gemma를 그대로 쓰는 것이 아니라, π0/π0.5 구조에 필요한 patch를 적용한다.

설치 시 주의:

cp -r ./src/openpi/models_pytorch/transformers_replace/* \
  .venv/lib/python3.11/site-packages/transformers/

uv hardlink mode에서는 이 patch가 uv cache에도 영향을 줄 수 있으므로, 완전히 되돌리려면 uv cache clean transformers가 필요할 수 있다.

13.4 PyTorch 변환

JAX checkpoint를 PyTorch checkpoint로 바꾸는 흐름:

uv run examples/convert_jax_model_to_pytorch.py \
  --checkpoint_dir /path/to/jax/checkpoint \
  --config_name <config name> \
  --output_path /path/to/converted/pytorch/checkpoint

변환 후 inference는 같은 policy_config.create_trained_policy API를 쓸 수 있다. checkpoint directory 안에 model.safetensors가 있으면 PyTorch path로 자동 감지된다.

13.5 성능 관점

README는 torch.compile을 쓰면 JAX와 PyTorch inference speed가 comparable하다고 설명한다. 하지만 실제로 창현님이 profiling해야 할 것은 다음이다.

1. torch.compile warmup/compile time과 steady-state latency 분리
2. dynamic shape 때문에 graph break가 생기는지 확인
3. action sampling loop가 Python loop인지 compiled loop인지 확인
4. image preprocessing이 GPU graph 밖 CPU에서 도는지 확인
5. bf16/float32 precision path가 kernel selection에 미치는 영향 확인

14. 예제별 사용법

14.1 공통 설치

권장 OS는 Ubuntu 22.04다. README는 다른 OS를 공식 지원하지 않는다고 설명한다.

git clone --recurse-submodules git@github.com:Physical-Intelligence/openpi.git
cd openpi

GIT_LFS_SKIP_SMUDGE=1 uv sync
GIT_LFS_SKIP_SMUDGE=1 uv pip install -e .

이미 clone했다면:

git submodule update --init --recursive

GIT_LFS_SKIP_SMUDGE=1은 Git LFS 파일을 clone/sync 시점에 즉시 대량 다운로드하지 않도록 막는 용도다. OpenPI는 LeRobot 등을 dependency로 다루기 때문에 이 옵션이 필요하다고 README가 설명한다.

14.2 사전학습 checkpoint inference

가장 간단한 흐름:

from openpi.training import config as _config
from openpi.policies import policy_config
from openpi.shared import download

config = _config.get_config("pi05_droid")
checkpoint_dir = download.maybe_download("gs://openpi-assets/checkpoints/pi05_droid")
policy = policy_config.create_trained_policy(config, checkpoint_dir)

action_chunk = policy.infer(example)["actions"]

여기서 example은 raw model input이 아니다. policy.infer 앞단 transform이 기대하는 environment/policy schema여야 한다. 예를 들어 DROID server라면 DROID policy가 기대하는 camera/state/prompt key를 넣어야 한다.

14.3 Simple client

examples/simple_client는 robot 없이 server inference를 테스트하는 최소 예제다.

서버:

uv run scripts/serve_policy.py --env DROID

클라이언트:

uv run examples/simple_client/main.py --env DROID

이 예제는 observation을 서버로 보내고 inference rate를 출력한다. 팀에서 처음 OpenPI를 테스트할 때 가장 먼저 실행하기 좋다.

14.4 LIBERO benchmark

Docker 권장:

SERVER_ARGS="--env LIBERO" docker compose -f examples/libero/compose.yml up --build

custom checkpoint:

export SERVER_ARGS="--env LIBERO policy:checkpoint --policy.config pi05_libero --policy.dir ./my_custom_checkpoint"
export CLIENT_ARGS="--args.task-suite-name libero_10"
docker compose -f examples/libero/compose.yml up --build

Docker 없이 실행하려면 별도 Python 3.8 venv와 LIBERO dependency 설치가 필요하다. README에서도 Docker를 권장한다.

14.5 DROID inference

DROID는 remote inference 전제가 강하다.

GPU server:

uv run scripts/serve_policy.py --env=DROID

또는 직접 checkpoint:

uv run scripts/serve_policy.py policy:checkpoint \
  --policy.config=pi05_droid \
  --policy.dir=gs://openpi-assets/checkpoints/pi05_droid

DROID control laptop:

cd $OPENPI_ROOT/packages/openpi-client
pip install -e .
pip install tyro

이후 examples/droid/main.py를 DROID scripts directory로 복사하고 camera ID/IP/port를 설정해 실행한다.

14.6 ALOHA real robot

Docker:

export SERVER_ARGS="--env ALOHA --default_prompt='take the toast out of the toaster'"
docker compose -f examples/aloha_real/compose.yml up --build

Docker 없이:

uv venv --python 3.10 examples/aloha_real/.venv
source examples/aloha_real/.venv/bin/activate
uv pip sync examples/aloha_real/requirements.txt
uv pip install -e packages/openpi-client
python -m examples.aloha_real.main

별도 터미널에서 ROS node:

roslaunch aloha ros_nodes.launch

서버:

uv run scripts/serve_policy.py --env ALOHA \
  --default_prompt='take the toast out of the toaster'

14.7 ALOHA sim

Docker:

export SERVER_ARGS="--env ALOHA_SIM"
docker compose -f examples/aloha_sim/compose.yml up --build

Docker 없이:

uv venv --python 3.10 examples/aloha_sim/.venv
source examples/aloha_sim/.venv/bin/activate
uv pip sync examples/aloha_sim/requirements.txt
uv pip install -e packages/openpi-client
MUJOCO_GL=egl python examples/aloha_sim/main.py

서버:

uv run scripts/serve_policy.py --env ALOHA_SIM

EGL 문제가 있으면 libegl1-mesa-dev, libgles2-mesa-dev 설치나 MUJOCO_GL=glx path를 고려한다.

14.8 UR5 custom dataset 예제

examples/ur5/README.md는 실제 실행 예제라기보다 “새 robot을 붙이는 방법”의 template이다.

핵심 구성:

UR5Inputs:
  joints + gripper → state
  base_rgb/wrist_rgb → image slots
  missing right wrist → zero image + mask handling
  prompt 전달

UR5Outputs:
  model action에서 robot이 쓰는 first 7 dims만 반환

LeRobotUR5DataConfig:
  repack raw LeRobot keys
  UR5Inputs/UR5Outputs 연결
  optional delta action transform
  ModelTransformFactory 연결

TrainConfig:
  model=Pi0Config()
  data=LeRobotUR5DataConfig(...)
  weight_loader=pi0_base
  num_train_steps=30000

이 파일은 팀에서 새 로봇 arm/hand/mobile base를 붙일 때 가장 직접적인 참고 자료다.


15. 전체 파일/폴더 인덱스

아래는 GitHub tree에서 확인한 파일/폴더 기준 인덱스다.

15.1 top-level

경로 역할
.github/ CI/workflow, CODEOWNERS
.github/workflows/pre-commit.yml pre-commit workflow
.github/workflows/test.yml test workflow
.github/CODEOWNERS code owner 설정
.vscode/settings.json VSCode project settings
docs/ docker, norm stats, remote inference 문서
examples/ embodiment/benchmark별 실행 예제
packages/openpi-client/ robot side lightweight client package
scripts/ train, serve, norm stats, docker helper
src/openpi/ 메인 Python package
third_party/ submodules: aloha, libero
.dockerignore docker build 제외 파일
.gitignore git ignore
.gitmodules ALOHA/LIBERO submodule 정의
.pre-commit-config.yaml formatting/lint hook
.python-version project Python version
CONTRIBUTING.md contribution guide
LICENSE Apache-2.0 license
LICENSE_GEMMA.txt Gemma 관련 license
README.md 프로젝트 메인 문서
pyproject.toml dependency/build config
uv.lock uv lockfile

15.2 docs

경로 역할
docs/docker.md Docker setup, rootless Docker, NVIDIA container toolkit 주의사항
docs/norm_stats.md normalization stats 재사용/재계산, asset_id/action space 정의
docs/remote_inference.md remote server/client 사용법

15.3 examples

경로 역할
examples/inference.ipynb pretrained model inference notebook
examples/policy_records.ipynb recorded policy behavior 분석 notebook
examples/convert_jax_model_to_pytorch.py JAX checkpoint → PyTorch checkpoint 변환
examples/simple_client/ 최소 websocket client 테스트
examples/libero/ LIBERO benchmark 실행/변환
examples/droid/ DROID inference/training/data conversion
examples/aloha_real/ real ALOHA 실행
examples/aloha_sim/ ALOHA simulation 실행
examples/ur5/ custom UR5 fine-tuning template

examples/simple_client/

파일 역할
Dockerfile simple client docker image
README.md minimal client 사용법
compose.yml client/server docker compose
main.py dummy/random observation을 server에 보내고 inference rate 출력
requirements.in source dependency spec
requirements.txt compiled dependency lock

examples/libero/

파일 역할
Dockerfile LIBERO docker image
README.md LIBERO benchmark 실행법
compose.yml LIBERO server/client compose
convert_libero_data_to_lerobot.py LIBERO data를 LeRobot format으로 변환
main.py LIBERO evaluation client/runtime
requirements.in dependency source spec
requirements.txt dependency lock

examples/droid/

파일 역할
README.md DROID inference guide
README_train.md DROID full training/fine-tuning guide
compute_droid_nonidle_ranges.py idle filtering/non-idle range 계산
convert_droid_data_to_lerobot.py custom DROID data를 LeRobot format으로 변환
main.py DROID robot runtime client

examples/aloha_real/

파일 역할
Dockerfile ALOHA real docker image
README.md real ALOHA 실행/scene setup/checkpoint guide
compose.yml ALOHA real compose
constants.py ALOHA runtime constants
convert_aloha_data_to_lerobot.py ALOHA data 변환
env.py ALOHA environment wrapper
main.py ALOHA real main control script
real_env.py real robot environment implementation
requirements.in dependency source spec
requirements.txt dependency lock
robot_utils.py robot utility functions
video_display.py camera/video display utility

examples/aloha_sim/

파일 역할
Dockerfile sim docker image
README.md ALOHA sim 실행법
compose.yml sim compose
env.py sim environment wrapper
main.py sim main script
requirements.in dependency source spec
requirements.txt dependency lock
saver.py sim rollout/data saving utility

examples/ur5/

파일 역할
README.md custom UR5 dataset/config/policy transform template

15.4 packages/openpi-client

경로 역할
packages/openpi-client/pyproject.toml client package metadata/dependency
packages/openpi-client/src/openpi_client/__init__.py package init
base_policy.py common BasePolicy interface
websocket_client_policy.py websocket remote policy client
msgpack_numpy.py numpy array를 msgpack으로 serialize/deserialize
msgpack_numpy_test.py serialization test
image_tools.py client-side image resize/uint8 conversion
image_tools_test.py image utility test
action_chunk_broker.py action chunk buffering/broker utility
runtime/ runtime 관련 client utilities

15.5 scripts

파일 역할
scripts/__init__.py package marker
scripts/compute_norm_stats.py state/action normalization stats 계산
scripts/serve_policy.py policy websocket server 실행
scripts/train.py JAX training entrypoint
scripts/train_pytorch.py PyTorch training entrypoint
scripts/train_test.py training tests
scripts/docker/compose.yml generic docker compose
scripts/docker/install_docker_ubuntu22.sh Ubuntu 22.04 Docker install helper
scripts/docker/install_nvidia_container_toolkit.sh NVIDIA container toolkit install helper
scripts/docker/serve_policy.Dockerfile policy server Dockerfile

15.6 src/openpi

경로 역할
src/openpi/__init__.py package init
src/openpi/conftest.py pytest config
src/openpi/py.typed type checking marker
src/openpi/transforms.py data transform core
src/openpi/transforms_test.py transform tests
src/openpi/models/ JAX model implementations
src/openpi/models_pytorch/ PyTorch model implementations/patches
src/openpi/policies/ environment-specific policy adapters
src/openpi/serving/ websocket server
src/openpi/shared/ download/image/normalize/array utilities
src/openpi/training/ config/data loading/training/checkpoint/optimizer

15.7 src/openpi/models

파일 역할
__init__.py model package init
model.py 공통 model types, Observation, BaseModel, restore
pi0.py π0/π0.5 flow matching implementation
pi0_config.py π0 config, model variant, LoRA/freeze config
pi0_fast.py π0-FAST autoregressive model
gemma.py JAX Gemma/PaliGemma module
gemma_fast.py FAST용 Gemma module
siglip.py SigLIP vision encoder
vit.py Vision Transformer building blocks
tokenizer.py PaliGemma/FAST tokenizer wrapper
lora.py LoRA modules
lora_test.py LoRA tests
model_test.py base model tests
pi0_test.py π0 tests
tokenizer_test.py tokenizer tests
utils/fsq_tokenizer.py finite scalar quantization tokenizer utility

15.8 src/openpi/models_pytorch

파일/폴더 역할
gemma_pytorch.py PyTorch Gemma/PaliGemma model wrapper
pi0_pytorch.py PyTorch π0/π0.5 implementation
preprocessing_pytorch.py PyTorch preprocessing
transformers_replace/models/gemma/configuration_gemma.py patched Gemma config
transformers_replace/models/gemma/modeling_gemma.py patched Gemma implementation
transformers_replace/models/paligemma/modeling_paligemma.py patched PaliGemma implementation
transformers_replace/models/siglip/check.py SigLIP patch/check helper
transformers_replace/models/siglip/modeling_siglip.py patched SigLIP implementation

15.9 src/openpi/policies

파일 역할
aloha_policy.py ALOHA input/output schema 변환
droid_policy.py DROID input/output schema 변환
libero_policy.py LIBERO input/output schema 변환
policy.py generic Policy wrapper, inference call, timing, recorder
policy_config.py checkpoint/config에서 Policy 생성
policy_test.py policy tests

15.10 src/openpi/serving

파일 역할
websocket_policy_server.py websocket server, health check, msgpack serialization

15.11 src/openpi/shared

파일 역할
__init__.py package init
array_typing.py type annotations/checking utilities
download.py gs/local download/cache utility
download_test.py download tests
image_tools.py image resize/pad utility
image_tools_test.py image tools tests
nnx_utils.py Flax NNX utilities, module jit, path regex
normalize.py normalization stats save/load/running stats
normalize_test.py normalization tests

15.12 src/openpi/training

파일 역할
checkpoints.py Orbax checkpoint manager, assets/params/train_state 저장/복원
config.py 모든 training/data/model config registry
data_loader.py LeRobot/RLDS data loader, transform application
data_loader_test.py data loader tests
droid_rlds_dataset.py DROID RLDS dataset interface
optimizer.py optimizer/lr schedule config
sharding.py JAX FSDP/data sharding utilities
utils.py TrainState, logging/array utilities
weight_loaders.py base checkpoint/PaliGemma weight loading
misc/polaris_config.py internal/special config set
misc/roboarena_config.py RoboArena config set

16. 새 로봇/데이터셋을 붙이는 절차

팀에서 OpenPI를 기반으로 새 연구를 시작한다면 이 절차가 가장 중요하다.

16.1 1단계: robot I/O schema 정의

먼저 다음을 명확히 적는다.

camera:
  - 몇 개?
  - 각 camera 이름?
  - RGB/BGR?
  - resolution?
  - wrist/base/external 구분?

state:
  - joint position?
  - joint velocity?
  - gripper position?
  - base pose/velocity?
  - dimension?

action:
  - joint position target?
  - joint velocity command?
  - end-effector delta pose?
  - gripper absolute/delta?
  - control frequency?
  - action_dim?
  - action_horizon?

이 단계 없이 코드를 수정하면 반드시 schema mismatch가 생긴다.

16.2 2단계: OpenPI 표준 slot에 매핑

OpenPI 기본 image slot:

base_0_rgb
left_wrist_0_rgb
right_wrist_0_rgb

예:

내 robot camera:
  front_cam  → base_0_rgb
  wrist_cam  → left_wrist_0_rgb
  없음       → right_wrist_0_rgb zero image + mask False

16.3 3단계: MyRobotInputs / MyRobotOutputs 작성

src/openpi/policies/my_robot_policy.py를 만든다고 가정하면:

MyRobotInputs:
  raw observation dict
  → state vector 구성
  → images dict 구성
  → image_mask 구성
  → prompt 전달
  → training이면 actions 전달

MyRobotOutputs:
  normalized/unormalized 후 model action
  → robot command dimension으로 crop/reorder/convert

절대 하면 안 되는 것:

  • action dimension이 안 맞는데 zero padding만 믿고 넘기기
  • gripper convention [0=open,1=close]인지 반대인지 확인하지 않기
  • radian/degree 혼동
  • joint position/velocity action 혼동
  • state order와 action order 다르게 두기

16.4 4단계: LeRobotMyRobotDataConfig 작성

training/config.py에 custom data config를 만든다.

구성:

repack_transform:
  dataset key → MyRobotInputs가 기대하는 key

data_transforms:
  inputs=[MyRobotInputs(...)]
  outputs=[MyRobotOutputs(...)]

optional delta transform:
  absolute action이면 DeltaActions
  inference output에는 AbsoluteActions

model_transforms:
  ModelTransformFactory()(model_config)

16.5 5단계: TrainConfig 추가

예:

TrainConfig(
  name="pi05_my_robot",
  model=Pi0Config(pi05=True, action_dim=..., action_horizon=...),
  data=LeRobotMyRobotDataConfig(repo_id="..."),
  weight_loader=CheckpointWeightLoader("gs://openpi-assets/checkpoints/pi05_base/params"),
  batch_size=...,
  num_train_steps=...,
)

주의:

  • action_dim은 model output dimension이다. 실제 robot action dim보다 클 수 있고 padding될 수 있다.
  • checkpoint pretraining action space와 내 action space가 얼마나 맞는지 확인해야 한다.
  • norm stats를 base에서 reuse할지 새로 계산할지 실험해야 한다.

16.6 6단계: norm stats

두 실험을 모두 해보는 것이 좋다.

A. base checkpoint의 asset_id를 재사용
B. 내 dataset으로 compute_norm_stats.py 실행

로봇/action convention이 base와 매우 비슷하면 A가 좋을 수 있다. 다르면 B가 안전하다.

16.7 7단계: smoke test

학습 전에 반드시 fake/small batch로 확인한다.

1. dataset sample 하나 load
2. repack transform 결과 print
3. MyRobotInputs 결과 shape 확인
4. Normalize 후 값 range 확인
5. model_transforms 후 token/image/action shape 확인
6. model.compute_loss 1회 실행
7. policy.infer dummy observation 1회 실행

이 과정을 skip하면 학습 중간에 shape mismatch, action convention mismatch, prompt 누락, norm stat 누락으로 시간을 크게 잃는다.


17. 성능 엔지니어링 관점의 분석

창현님 커리어 목표 관점에서 OpenPI는 “모델 연구”와 “시스템 성능 연구”가 동시에 가능한 좋은 대상이다.

17.1 π0/π0.5 inference bottleneck 후보

1. image preprocessing / resize / uint8→float 변환
2. SigLIP vision encoder prefix pass
3. PaliGemma/Gemma prefix prefill
4. num_steps번 반복되는 action suffix forward
5. action_out_proj / small MLP
6. JAX/PyTorch framework overhead
7. websocket serialization/deserialization
8. robot loop에서 action chunk scheduling

17.2 π0-FAST inference bottleneck 후보

1. image prefix prefill
2. autoregressive token decoding loop
3. KV cache access/update
4. output projection to vocab logits
5. FAST token decode to actions

π0-FAST는 AR decoding이므로 token 수가 latency를 지배할 수 있다. FAST가 training을 빠르게 만들 수 있어도 inference는 token-by-token dependency 때문에 느려질 수 있다.

17.3 profiling 권장 분해

첫 번째 baseline은 다음처럼 나눠야 한다.

A. model-only latency
   - fixed observation
   - fixed noise 가능
   - warmup 후 CUDA sync 포함 측정

B. policy-only latency
   - transforms 포함
   - websocket 제외

C. server end-to-end latency
   - websocket unpack/pack 포함
   - server_timing 확인

D. robot closed-loop latency
   - camera capture
   - state read
   - network
   - server
   - action dispatch

17.4 실험 knobs

knob 기대 효과 위험
num_steps 감소 π0/π0.5 latency 직접 감소 action quality 저하
action_horizon 증가 server call 빈도 감소 open-loop error 증가
image resolution 감소 vision latency 감소 perception quality 저하
PyTorch torch.compile steady-state latency 감소 가능 compile overhead/graph break
JAX jit warmup 관리 steady-state 안정화 first-run latency 큼
bf16 사용 memory bandwidth/throughput 개선 numerical issue
remote server GPU 강화 model latency 감소 network/serialization bottleneck은 그대로
client-side image resize network bandwidth 감소 client CPU 병목 가능

17.5 Nsight Systems에서 볼 것

1. CPU thread가 GPU kernel launch를 굶기고 있는가?
2. denoising loop 사이에 Python/JAX dispatch gap이 있는가?
3. H2D/D2H copy가 반복되는가?
4. image preprocessing이 CPU에서 길게 도는가?
5. websocket recv/send가 model보다 큰가?
6. GPU kernel들이 짧고 fragment되어 launch overhead가 큰가?

17.6 Nsight Compute에서 볼 것

핵심 kernel을 골라 다음을 확인한다.

1. GEMM/attention kernel의 Tensor Core utilization
2. memory throughput vs compute throughput
3. occupancy
4. achieved occupancy와 theoretical occupancy 차이
5. shared memory/register pressure
6. attention/KV cache kernel의 memory access pattern
7. small MLP/projection kernel이 launch overhead 중심인지

17.7 커리어적으로 좋은 연구 주제

OpenPI 기반으로 창현님에게 특히 좋은 주제는 다음이다.

  1. π0/π0.5 denoising step distillation + latency-quality Pareto frontier
  2. VLA policy server end-to-end latency decomposition: model-only vs robot-loop
  3. action chunk scheduling: horizon/replanning frequency/open-loop drift trade-off
  4. π0 flow matching vs π0-FAST AR decoding의 systems-level 비교
  5. JAX vs PyTorch implementation profiling: XLA vs torch.compile
  6. KV cache/prefix reuse 최적화 for repeated robot inference
  7. edge/off-robot serving: network serialization + GPU scheduling co-design

관련해서 창현님이 공부 중인 책/지식과의 연결은 다음과 같다.

창현님 학습 축 OpenPI에서 연결되는 지점
AI Systems Performance Engineering model-only/e2e latency 분해, profiler workflow, framework overhead
PMPP/CUDA/Triton attention/GEMM/custom kernel 최적화, memory hierarchy, Tensor Core utilization
Computer Architecture GPU memory bandwidth, cache, instruction throughput, data movement cost
Systems Performance server/client, websocket, CPU scheduling, profiling methodology
OS/Kernel/eBPF robot loop jitter, network latency, process scheduling, tracing
선형대수/미분기하/리만기하 action space, SE(3)/joint manifold, flow/vector field, delta action representation

18. Troubleshooting map

증상 가능 원인 확인/해결
missing norm stats compute_norm_stats.py 미실행 또는 asset_id mismatch config의 repo_id/asset_id/assets_dir 확인
action dimension mismatch action_dim, policy output crop, padding 불일치 PadStatesAndActions, MyRobotOutputs 확인
prompt missing prompt key 누락, default_prompt 없음 InjectDefaultPrompt, data prompt field 확인
CUDA OOM batch size/num_steps/model size/FSDP 설정 문제 batch 감소, LoRA, FSDP, EMA off, memory fraction 확인
DROID camera mismatch camera ID 설정 오류 ZED_Explorer/camera key mapping 확인
ALOHA poor performance scene distribution mismatch README scene setup/checkpoint prompt 확인
LIBERO EGL error MuJoCo rendering backend 문제 MUJOCO_GL=egl 또는 glx, Docker 권장
PyTorch checkpoint가 JAX로 로드됨 model.safetensors 없음 converted checkpoint directory 확인
FAST output이 이상함 ExtractFASTActions 미적용, tokenizer mismatch ModelTransformFactory와 config tokenizer 확인
training loss diverges norm stats q01/q99/std 이상 norm_stats.json 확인, rare dimension clipping/수동 조정

19. 연구팀 온보딩용 추천 순서

팀원이 OpenPI를 처음 본다면 다음 순서로 읽히는 것이 효율적이다.

Day 1: README + 이 문서 0~8장
Day 2: model.py, transforms.py, policy_config.py, policy.py
Day 3: pi0.py, pi0_fast.py
Day 4: training/config.py, data_loader.py, train.py
Day 5: examples/simple_client, docs/remote_inference.md 실행
Day 6: target embodiment example(DROID/ALOHA/LIBERO/UR5) 실행
Day 7: profiler baseline 구축

실제 수정은 다음 순서로 한다.

1. simple_client로 server/client 정상 동작 확인
2. target checkpoint로 policy.infer 1회 확인
3. target robot/sim observation schema 출력
4. policy input transform 통과 후 shape/range 확인
5. model-only latency 측정
6. e2e latency 측정
7. fine-tuning dataset 변환
8. norm stats 계산
9. 100-step debug training
10. full fine-tuning

20. 참고 자료

OpenPI / Physical Intelligence

  • GitHub: https://github.com/Physical-Intelligence/openpi
  • Open-sourcing π0 blog: https://www.physicalintelligence.company/blog/openpi
  • π0 blog: https://www.physicalintelligence.company/blog/pi0
  • π0 arXiv: https://arxiv.org/abs/2410.24164
  • FAST blog: https://www.physicalintelligence.company/research/fast
  • FAST arXiv: https://arxiv.org/abs/2501.09747
  • π0.5 blog: https://www.physicalintelligence.company/blog/pi05
  • Knowledge Insulation arXiv: https://arxiv.org/abs/2503.00605

Robot datasets / benchmarks

  • DROID: https://droid-dataset.github.io/
  • DROID paper: https://arxiv.org/abs/2403.12945
  • ALOHA: https://tonyzhaozh.github.io/aloha/
  • LIBERO: https://libero-project.github.io/
  • LIBERO paper: https://arxiv.org/abs/2306.03310

창현님 관점의 추가 학습 연결

  • flow matching / diffusion ODE: action generation이 vector field integration이라는 관점에서 이해
  • SE(3), SO(3), Lie algebra: end-effector action space를 joint vector가 아닌 pose delta로 확장할 때 필요
  • CUDA/Triton/Nsight: repeated suffix forward, AR decoding, KV cache, small-kernel launch overhead 분석에 필요
  • Systems Performance/eBPF: robot runtime jitter, websocket latency, CPU scheduling, data loader multiprocessing 분석에 필요

21. 마지막 요약

OpenPI를 완전히 이해하기 위한 핵심은 다음 한 문장이다.

OpenPI는 π0/π0‑FAST/π0.5 모델 자체보다, 이 모델을 여러 robot embodiment에 맞게 변환하고 normalization하며 remote inference/fine-tuning까지 연결하는 end-to-end robotics AI systems stack이다.

연구에서 가장 먼저 해야 할 일은 모델 architecture를 읽는 것이 아니라, 다음 path를 실제로 trace하는 것이다.

raw robot observation
→ repack transform
→ robot-specific input transform
→ Normalize
→ model-specific transform
→ Observation.from_dict
→ model.sample_actions
→ model-specific output transform
→ Unnormalize
→ robot-specific output transform
→ robot command

이 path를 print/profiling/shape-check로 완전히 장악하면, 그 다음부터는 모델 개선, distillation, compiler optimization, CUDA/Triton kernel optimization, remote serving 최적화가 모두 체계적으로 가능해진다.