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 기준값과 수치가 완전히 일치한다. 최악 시나리오 배제.

부수 확인

남은 것