Index
2026-05-11 — Engineering

torchcodec 전사 표준화 — GR00T-Dreams video backend

GR00T-Dreams | AV1 지원 · 0.73 ms / 2-frame · dlopen LD_LIBRARY_PATH 해결 · gr00t-idm env 적용

TL;DR

17×
2-frame seek 가속
0.73 ms
torchcodec (2-frame)
12.8 ms
PyAV (2-frame)
end-to-end 가속

1 배경 / 목적

mg30_real_h50 비디오는 AV1 codec (libsvtav1)으로 인코딩되어 있어 decord가 cannot find video stream 오류를 낸다. PyAV (libdav1d SW 디코더)로 우회해 동작은 확인했으나, Pi0.5 학습 스크립트 (launch_pi05_b0_ref.sh)가 이미 torchcodec을 쓰고 있다는 지적이 있었다.

측정 결과 torchcodec이 PyAV 대비 17× 빠른 것을 확인 → 전사적으로 torchcodec으로 표준화. 단, conda 환경의 libstdc++ CXXABI 버전 mismatch로 import 자체가 실패하는 문제를 먼저 해결해야 했다.

2 작업 내용

① Backend 후보 벤치마크 (mg30_real_h50 left cam, 30 random seek + 2-frame decode)

Backend2-frame seek3-cam aggregate비고
decord✗ AV1 open 실패
opencv VideoCapture✗ seek 후 read() False
torchvision.io✓ 동작 (deprecated 경고)
PyAV (libdav1d)12.8 ms38 ms✓ 동작
torchcodec0.73 ms~2 ms✓ 채택

② dlopen 체인 진단 + LD_LIBRARY_PATH 해결

torchcodec import 시 실패 원인:

libtorchcodec_core7.so → libavcodec.so.61 → libopenvino.so.2520 → libstdc++.so.6 (CXXABI_1.3.15) → libnppicc.so.12 (NVIDIA NPP)

동적 링커가 시스템 libstdc++ (CXXABI ≤1.3.9)를 먼저 로드하여 conda의 새 libstdc++ (1.3.15)가 invisible.

Python 코드 안에서 os.environ['LD_LIBRARY_PATH']를 설정해도 무효 — dlopen은 import 시점(Python 시작 이전)에 발생하므로 SLURM shell에서 미리 export해야 한다.

③ 해결: SLURM shell에서 LD_LIBRARY_PATH 노출

GR00T_VENV=/home/nas_main/taewoongkang/conda_envs/envs/gr00t-idm export LD_LIBRARY_PATH=\ "$GR00T_VENV/lib:\ $(ls -d $GR00T_VENV/lib/python3.10/site-packages/nvidia/*/lib 2>/dev/null | tr '\n' ':'):\ $LD_LIBRARY_PATH"

첫 segment: conda libstdc++ + libavcodec + libopenvino (시스템보다 우선)

두 번째 segment: venv-bundled CUDA 12 libs (libnppicc, libcublas, libcudart 등)

④ 설치 (gr00t-idm, 260509 적용 완료)

conda activate gr00t-idm pip install torchcodec nvidia-npp-cu12 conda install -c conda-forge 'ffmpeg=7.*' # libavcodec.so.61 제공

⑤ dataset_h50_pixel_v2.py 교체

PyAV av.open(...) → torchcodec VideoDecoder(path, num_ffmpeg_threads=1). 수동 timestamp seek → decoder.get_frames_at(indices=[base+0, base+16]). tensor (T,C,H,W) uint8permute(0,2,3,1).numpy()로 PIL-호환 변환.

⑥ 사용 예시

from torchcodec.decoders import VideoDecoder decoder = VideoDecoder('path/to/video.mp4', num_ffmpeg_threads=1) # num_ffmpeg_threads=1 권장: 128×128 small frame에서 MT overhead가 더 큼 frames = decoder.get_frames_at(indices=[0, 16]) # frames.data: torch.uint8 (T, C, H, W) arr = frames.data.permute(0, 2, 3, 1).contiguous().numpy() # (T, H, W, C)

3 결과 (수치)

측정 항목PyAVtorchcodec비율
2-frame seek (1 cam)12.8 ms0.73 ms17×
3-cam aggregate (per __getitem__)38 ms~2 ms19×
Smoke __getitem__ warm (6 cam-frames)44-48 ms12 ms
Smoke __getitem__ cold (first open)314 ms650 msdecoder open 비용
Mini train it/s (B200 1 GPU, bs 4)11.4710.82≈ 동등 (model forward bound)
steady-state training throughput이 동등한 이유: SiglipImageProcessor (resize 224 + normalize)가 raw video decode보다 더 큰 bottleneck이기 때문. raw decode가 4× 빨라진 덕에 dataloader worker 부담↓ → 더 큰 batch / 적은 worker 가능.

env별 Python 버전 주의

envPythonsite-packages 경로
gr00t-idm3.10$VENV/lib/python3.10/site-packages/nvidia/*/lib
pi053.12$VENV/lib/python3.12/site-packages/nvidia/*/lib
dreamgen3.10동일 패턴

4 Takeaway

GR00T-Dreams 전사 표준 = torchcodec: mg30_real_h50 AV1 + dreamgen 합성 데이터 (AV1) 모두 처리 가능. PyAV/decord는 fallback.
LD_LIBRARY_PATH는 SLURM shell에서만 export: Python 내부에서는 dlopen이 이미 완료된 후라 무효. launch_pi05_b{0,1,2}_ref.shrun_idm_train_robocasa_h50_v2_8gpu.sh가 같은 패턴 적용 중 — 신규 launch 작성 시 cargo-cult 권장.

왜 PyAV가 아닌 torchcodec인가

PyAV도 동작하며 dataloader bottleneck이 되지 않을 수준(12.8 ms)이다. 그러나 (1) Pi0.5 기존 코드베이스가 이미 torchcodec을 씀 → 통일성, (2) AV1 SW dav1d가 향후 GPU decode로 전환 시 torchcodec이 더 자연스럽게 지원, (3) index-based seek (get_frames_at)이 timestamp 계산 없이 깔끔하다는 이점. cold open 시 650ms 비용은 per-worker 캐시로 첫 호출 1회만 발생하므로 실제 학습에서 무시 가능.

5 Next Steps