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파이프라인 전체다.
즉, 모델 구조만 보면 절반만 이해한 것이다. 실제로 연구/수정/성능 최적화를 하려면 다음 질문에 답할 수 있어야 한다.
- 내 로봇의 camera/state/action schema가 OpenPI 내부 표준 schema로 어떻게 바뀌는가?
- state/action normalization statistics는 어디서 오고, 학습/추론에서 언제 적용되는가?
- π0/π0.5는 action을 continuous flow matching으로 만들고, π0-FAST는 왜 token sequence로 만드는가?
- policy server를 띄웠을 때 robot laptop과 GPU server 사이에서 어떤 데이터가 오가는가?
- 학습할 때 LeRobot/RLDS dataset sample은 어떤 transform stack을 거쳐
Observation/Actions가 되는가? - 병목 최적화 관점에서 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의 핵심은 다음이다.
- VLM backbone을 사용한다. OpenPI 코드에서는 PaliGemma 계열 구조가 중심이다.
- 입력은 image tokens + language tokens + robot state/action 관련 tokens로 구성된다.
- action은 단일 action이 아니라 action chunk다. 즉, 한 번 infer하면
(action_horizon, action_dim)모양의 여러 future action을 예측한다. - action 생성은 diffusion/flow matching 계열이다. 학습 시 noisy action과 timestep을 주고 vector field를 예측하게 한다.
- 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.py와 pi0_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.py의 loss_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는 이를 활용해:
- action chunk를 frequency domain처럼 다루는 DCT 기반 표현으로 바꾼다.
- BPE류 tokenizer로 반복 패턴을 압축한다.
- action chunk 하나를 비교적 짧은 token sequence로 표현한다.
- 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
Pi0FASTConfig는 BaseModelConfig를 상속한다. 주요 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 Observation과 Actions
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개만 쓴다면 다음 중 하나를 해야 한다.
- unused camera slot에 zero image를 넣고
image_mask=False로 둔다. - 모델 type에 따라 FAST에서는 mask convention이 다를 수 있으므로 policy 예제를 참고한다.
- 새 model/config를 만들어 image_keys를 명시적으로 바꾼다. 단, checkpoint와 pretraining distribution이 달라지므로 신중해야 한다.
UR5 예제 README가 좋은 힌트를 준다. UR5는 base image와 wrist image만 있을 수 있으므로 right wrist slot을 zero로 채우고 mask를 조절한다.
6.3 이미지 전처리
Observation.from_dict와 preprocess_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.py와 policies/*_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를 재구성한다.
수정할 때 체크리스트:
- dataset sample에서 실제 key 이름을 확인한다.
- robot runtime에서 server에 보내는 observation key 이름을 확인한다.
- 두 schema가 최대한 일치하도록 repack mapping을 만든다.
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_norm은 model_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 TokenizeFASTInputs와 ExtractFASTActions
π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.py와 policy.py: 추론 pipeline의 실제 중심
9.1 create_trained_policy 전체 흐름
src/openpi/policies/policy_config.py의 create_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.py의 Policy.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/params와 checkpoint_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 이유를 세 가지로 설명한다.
- AdaRMS 지원
- activation precision control
- 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 기반으로 창현님에게 특히 좋은 주제는 다음이다.
- π0/π0.5 denoising step distillation + latency-quality Pareto frontier
- VLA policy server end-to-end latency decomposition: model-only vs robot-loop
- action chunk scheduling: horizon/replanning frequency/open-loop drift trade-off
- π0 flow matching vs π0-FAST AR decoding의 systems-level 비교
- JAX vs PyTorch implementation profiling: XLA vs torch.compile
- KV cache/prefix reuse 최적화 for repeated robot inference
- 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 최적화가 모두 체계적으로 가능해진다.