Index
2026-07-21 — Engineering

RoboLab(Isaac Sim) × B200 구동 가능성 검증

DreamZero | 오진에서 시작해 환경 문제로 귀결된 디버깅 기록

TL;DR

50/50
steps 완주
3.24
it/s (렌더만)
8
Vulkan devices
18 GB
RoboLab 설치
43 GB
ckpt
0.00000
flash−sdpa 오차

1 배경 — 문제가 두 번 바뀌었다

출발점은 "DreamZero를 RoboLab에서 돌려보고 싶다"였다. 그런데 "robolab"이 무엇인지에 대한 오해로 문제 정의가 두 차례 뒤집혔다.

단계가정도출된 결론
1차robolab = 실제 로봇 랩불가능 worker pod ingress가 닫혀 외부 로봇이 접속 불가. login node 상시 서빙은 클러스터 규칙 위반
2차robolab = 별도 GPU 머신접근 불가 SSH private key 없음, known_hosts에 github.com뿐
실제RoboLab = Isaac Lab 기반 시뮬레이션 벤치마크가능 시뮬과 정책 서버를 같은 pod에 배치 → 네트워크 제약 소멸
핵심 전환 — RoboLab은 ~/repos/Robotics/RoboLab에 이미 클론된 NVIDIA NVlabs의 벤치마크(RoboLab-120, 100+ manipulation task)였다. 시뮬레이터이므로 모든 것이 한 worker pod 안에서 완결된다. 앞선 두 단계의 블로커가 전부 무의미해졌다.

그리고 policies/dreamzero/{run.py,client.py}DreamZero 공식 어댑터가 이미 포함되어 있었다. 기본값이 localhost:5000이라 단일 pod 구성이 설계상 자연스럽다.

이로써 남은 실질 질문은 단 하나로 좁혀졌다: Isaac Sim이 B200에서 도는가? RoboLab README가 NVIDIA RTX GPU required를 명시하고 VRAM 가이드가 전부 L40(48GB) 기준이라, datacenter GPU에서는 실패할 것으로 예상했다.

2 실패 연쇄와 근본 원인

설치(uv sync, 18GB) 후 import부터 연달아 막혔다. 그런데 표면 증상과 진짜 원인이 달랐다.

증상표면 해석 (오답)실제 원인
ImportError: libGL.so.1login node에 OpenGL 없음libglvnd 로더만 부재
Vulkan 라이브러리 검색 0건B200이 Vulkan 미지원libvulkan.so.1 로더만 부재

결정적 단서 — 드라이버 쪽은 멀쩡했다

/usr/lib/x86_64-linux-gnu/libEGL_nvidia.so.0 ✓ 존재 /usr/lib/x86_64-linux-gnu/libGLX_nvidia.so.0 ✓ 존재 /etc/vulkan/icd.d/nvidia_icd.json ✓ 존재 (api_version 1.4.312) /usr/share/glvnd/egl_vendor.d/10_nvidia.json ✓ 존재

진단

NVIDIA Container Toolkit이 벤더 구현은 주입했지만, 그 위에 얹히는 벤더 중립 로더 계층은 이미지에 없었다. libglvnd와 Vulkan 로더는 애플리케이션과 드라이버 사이의 dispatch 레이어인데, 이게 없으면 드라이버가 아무리 멀쩡해도 libGL.so.1을 찾는 프로그램은 전부 실패한다.

하드웨어 제약이 아니라 컨테이너 이미지 구성 문제였고, 따라서 sudo 없이 유저 레벨로 해결 가능했다.

해결

conda create -y -p ~/repos/Robotics/RoboLab/.gl -c conda-forge libglvnd libglu conda install -y -p ~/repos/Robotics/RoboLab/.gl -c conda-forge \ libglvnd-glx-conda-x86_64 libglvnd-egl-conda-x86_64 libvulkan-loader
함정libglvnd 본체는 libOpenGL.so.0 / libGLdispatch.so.0만 제공한다. 정작 필요한 libGL.so.1 / libEGL.so.1 / libGLX.so.0*-conda-x86_64 하위 패키지가 제공하며, 설치 경로가 lib/가 아니라 x86_64-conda-linux-gnu/sysroot/usr/lib64/다. 두 경로를 모두 LD_LIBRARY_PATH에 넣어야 한다.

3 결과

Vulkan 디바이스 열거

vkCreateInstance -> 0 (VK_SUCCESS) physical device count = 8 [0..7] 'NVIDIA B200' type=2 vendor=0x10de api=1.4.312
type=2 = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU. 소프트웨어 렌더러(lavapipe) 폴백이 아니라 실제 하드웨어 경로임이 확정됐다. 이 시점에서 "RT core 부재로 렌더링 붕괴" 시나리오가 배제됐다.

참고: Vulkan 열거는 CUDA_VISIBLE_DEVICES를 따르지 않아 8장이 모두 보인다. 렌더 GPU는 --/renderer/activeGpu=N으로 별도 지정해야 한다.

Isaac Sim 부팅 & 에피소드 실행

BananaInBowlTask: 50/50 steps, 3.24 it/s, EXIT=0 → output/run_empty_env/BananaInBowlTask/log_0_env0.json
GPU 열거
8× B200 183GB
activeGpu 반영
device 5 ✓
CUDA P2P
5428 GB/s
P2P latency
2.13 us
success: False는 정상이다. run_empty는 정책 없이 빈 액션을 넣으므로 바나나를 못 집는 게 기대 동작이다. 검증 대상은 성공률이 아니라 시뮬+렌더 파이프라인의 구동 여부였다.

무해한 경고

GLFW initialization failed, failed to open the default display — X 서버 없이 창을 안 띄우는 headless 모드라 당연하다. 렌더링은 Vulkan 경로로 별도 진행된다.

속도 해석 주의 — 3.24 it/s는 정책 추론이 빠진 순수 시뮬+렌더 속도다. README의 1.4 it/s는 ~200ms 추론을 포함한 수치이므로 직접 비교는 성립하지 않는다. 다만 소프트웨어 폴백이었다면 이 자릿수가 나올 수 없다. DreamZero(H100 기준 ~3s/chunk)를 붙이면 병목은 렌더링이 아니라 정책 추론 쪽이 된다.

4 Takeaway

  1. 초기 가설이 틀렸다. "datacenter GPU라 Isaac Sim 불가"는 README 문구에서 유추한 추정이었을 뿐 검증된 사실이 아니었다. 증상 레벨(ImportError)에서 판단을 멈췄다면 멀쩡히 돌아가는 경로를 포기했을 것이다. 벤더 라이브러리 존재 여부까지 내려가 확인한 것이 분기점이었다.
  2. 하드웨어 제약과 환경 구성 문제를 혼동하지 말 것. 전자는 우회 불가, 후자는 대개 유저 레벨로 해결된다. 이 둘을 섞으면 잘못된 포기로 이어진다.
  3. 재사용 가능한 자산 확보. .gl conda prefix + LD_LIBRARY_PATH 패턴은 이 클러스터에서 Isaac Sim / Omniverse / OpenGL 계열을 쓰는 모든 향후 작업에 그대로 적용된다.

재사용 스니펫

GL=~/repos/Robotics/RoboLab/.gl export LD_LIBRARY_PATH=$GL/lib:$GL/x86_64-conda-linux-gnu/sysroot/usr/lib64:$LD_LIBRARY_PATH export OMNI_KIT_ACCEPT_EULA=Y # 렌더 GPU는 CUDA_VISIBLE_DEVICES와 별개 (Vulkan은 CVD를 따르지 않음) python examples/run_empty.py --task BananaInBowlTask --headless --/renderer/activeGpu=5

5 Next

미해결

다음 단계

  1. 체크포인트 다운로드 + env torch 버전 정합성 확인
  2. 단일 sbatch 안에서 서버(GPU 2장 분산) + RoboLab 클라이언트(GPU 1장) 동시 기동, --task BananaInBowlTask로 소규모 end-to-end
  3. 통과 시 전체 벤치마크 확장 — 반드시 sbatch. RoboLab 자체 추정이 100 태스크당 30 GPU-hour이므로 login node 디버깅 허용 범위를 크게 초과
  4. 대안: --remote-uri로 호스팅 엔드포인트에 붙으면 14B 서빙 GPU를 절약 가능

6 업데이트 — 체크포인트 확보 & 실행 env 구성

시뮬레이터 쪽이 확인됐으니 정책 쪽을 준비했다. 기존 dreamzero env는 실행 불가능한 상태였다 — torchaudio만 2.8/cu129로 튀어 있고 flash-attn이 없는, 부분 업그레이드를 시도하다 중단된 흔적이었다. 기존 env를 덮지 않고 새 env를 생성했다.

패키지구 env (사용 불가)신 env dreamzero-robolab요구
torch2.7.1+cu1282.8.0+cu1292.8.0
torchvision0.22.1+cu1280.23.0+cu1290.23.0
torchaudio2.8.0+cu1292.8.0+cu1292.8.0
transformers4.46.24.51.3ckpt: 4.51.3
flash-attn없음2.8.3.post1필수

체크포인트

GEAR-Dreams/DreamZero-DROID는 public repo라 HF 토큰 불필요. 전체 ~65GB 중 tensorrt/(~19GB)는 GB200 전용이라 제외.

uvx --from "huggingface_hub[cli]" hf download GEAR-Dreams/DreamZero-DROID \ --repo-type model --local-dir ./checkpoints/DreamZero-DROID --exclude "tensorrt/*" → 43GB, safetensors 10/10, EXIT=0
~30GB 전송 회피config.json에서 diffusion_model_pretrained_path / image_encoder_pretrained_path / text_encoder_pretrained_path가 모두 null임을 확인했다. 즉 모든 가중치가 safetensors에 통합돼 있어 Wan2.1-I2V-14B와 umt5-xxl을 따로 받을 필요가 없었다.

함정 1 — Invalid cross-device link

[Errno 18] Invalid cross-device link: 'flash_attn-2.8.3.post1+cu12torch2.8cxx11abiTRUE-cp311-cp311-linux_x86_64.whl' -> '/home/.../.cache/pip/wheels/.../...whl'
로그 말미의 ERROR: Failed building wheel만 보면 컴파일 실패로 오독하기 쉽다. 실제로는 prebuilt wheel을 이미 받아둔 상태였고, 임시 디렉토리가 /tmp(로컬 디스크)이고 목적지가 ~/.cache/pip(NAS gpfs)라 os.rename이 파일시스템 경계를 넘지 못한 것뿐이다. TMPDIR을 NAS로 지정해 해결. NAS 홈 + 로컬 /tmp 조합인 이 클러스터에서 반복될 패턴이다.

부수 주의: PATH의 기본 nvcc~/cudas/cuda-13.0을 가리켜 torch cu129와 불일치한다. CUDA_HOME=/usr/local/cuda-12.8 명시 필요.

함정 2 — flash-attn 지원 판정이 커널 존재를 확인하지 않는다

def _gpu_supports_flash_attention(): # attention.py:26 if not (FLASH_ATTN_2_AVAILABLE or FLASH_ATTN_3_AVAILABLE): return False cap = torch.cuda.get_device_capability() return cap[0] >= 8 # B200 = (10, 0) → 무조건 True
이 체크는 import 가능 여부 + compute capability만 본다. 해당 아키텍처용 커널이 wheel에 실제로 컴파일돼 있는지는 확인하지 않는다. 따라서 "flash-attn이 설치됐지만 sm_100 커널이 없는" 경우 체크를 통과한 뒤 런타임에 터진다. 그 경우 정답은 flash-attn을 제거하는 것이다 — 미설치 시에는 SDPA 폴백으로 정상 동작하기 때문. 설치 성공에 안심하지 않고 실제 커널 호출까지 검증한 이유다.

B200 실동작 검증

flash_attn 2.8.3.post1 device NVIDIA B200 cap (10, 0) flash_attn_varlen_func OK -> (128, 8, 64) torch.bfloat16 max|flash - sdpa| = 0.00000 → NUMERIC MATCH
sm_100 커널이 실제로 포함돼 있고 SDPA 기준값과 수치가 완전히 일치한다. 최악 시나리오 배제.

부수 확인

남은 것