이 문서는 B200 cluster (NVIDIA driver 580, Open Kernel Module, Ubuntu 22.04, glibc 2.35) 에서 RoboMME (ManiSkill 3 + SAPIEN 3) closed-loop sim 을 돌리기 위한 환경 셋업 가이드. 최소 5번의 막힘을 거쳐 도달한 working configuration.
# 0. submodule + 두 env 셋업
cd ~/repos/Robotics/robomme_policy_learning
git config submodule.third_party/robomme_benchmark.url https://github.com/RoboMME/robomme_benchmark.git
git submodule update --init third_party/robomme_benchmark
# 1. sim/VLM client conda env (Python 3.11)
conda create -n robomme python=3.11 -y
ROBOMME=/home/nas_main/taewoongkang/conda_envs/envs/robomme # 본인 경로로
$ROBOMME/bin/pip install -r examples/robomme/requirements.txt
$ROBOMME/bin/pip install -e third_party/robomme_benchmark
$ROBOMME/bin/pip install -e packages/openpi-client
$ROBOMME/bin/pip install opencv-python-headless h5py # opencv-python NOT (libGL.so.1 없음)
$ROBOMME/bin/pip install --upgrade mplib # 0.1.1 → 0.2.1 (segfault 회피)
# 2. NVIDIA Vulkan headless 동작에 필요한 GLVND + libdrm (conda-forge)
conda install -n robomme -c conda-forge -y \
libglvnd libgl libglx libegl libopengl libdrm libvulkan-loader
# 3. uv-based OpenPi (VLA server)
GIT_LFS_SKIP_SMUDGE=1 uv sync
GIT_LFS_SKIP_SMUDGE=1 uv pip install -e .
mkdir -p ~/openpi_data && export OPENPI_DATA_HOME=~/openpi_data
# 4. 매 실행 시 export 필요한 env vars
export LD_LIBRARY_PATH=$ROBOMME/lib:$LD_LIBRARY_PATH
export VK_ICD_FILENAMES=/etc/vulkan/icd.d/nvidia_icd.json
export USE_HF=1 # ms-swift HF cache 사용
export OPENPI_DATA_HOME=~/openpi_data
NVIDIA driver 580 series + Ubuntu 22.04 + 헤드리스 컴퓨트 노드는 default 상태에서 Vulkan 이 동작하지 않음. 깊이 추적해서 발견한 것들:
| 증상 | 원인 | Fix |
|---|---|---|
vk::createInstanceUnique: ErrorIncompatibleDriver |
conda env에 GLVND lib 없음 → libGLX_nvidia 가 init 단계에서 dispatch 실패 | conda-forge libglvnd libgl libglx libegl libopengl 설치 |
| 같은 에러, GLVND 깔아도 | conda env 의 libdrm 이 너무 옛 버전 | conda-forge libdrm (2.4.125+) 설치 |
libGL.so.1: cannot open shared object |
opencv-python 의 GUI deps |
pip uninstall opencv-python && pip install opencv-python-headless --force-reinstall --no-deps |
libnvidia-glcore: undefined symbol __malloc_hook (LD_DEBUG) |
glibc 2.34+ 에서 제거된 hook 을 NVIDIA 580 lib 가 weak ref. 메시지는 noise, 실제 동작에 영향 없음 | 무시 OK. Vulkan instance 안 되는 다른 이유 (위 행 참고) |
libnvidia-glcore: undefined symbol ErrorF / miCreateDefColormap |
NVIDIA 580 의 libnvidia-glcore 가 X server 컨텍스트 가정으로 빌드. 헤드리스에서 dlsym 실패 메시지. noise | 무시 OK |
mplib.Planner.__init__ segfault |
mplib 0.1.1 + 새 시스템 lib ABI 불일치 | pip install --upgrade mplib (0.2.1) + 아래 monkey-patch |
set_base_pose: incompatible function arguments (mplib 0.2.1) |
ManiSkill 3.0.0b21 이 numpy array 넘기는데 mplib 0.2.1 은 mplib.pymp.Pose 객체 요구 |
driver 시작 시 monkey-patch (아래) |
vulkaninfo 가 ModelScope 에서 8GB 모델 받느라 90분 timeout |
ms-swift 가 default ModelScope (중국, throttled) 사용 | USE_HF=1 env var + hf download Qwen/Qwen3-VL-4B-Instruct 미리 받기 |
hf download Yinpei/vlm_subgoal_predictor \
--include "memer/grounded_subgoal/*" \
--local-dir ~/ckpts/robomme-memer-lora-source
unzip ~/ckpts/robomme-memer-lora-source/memer/grounded_subgoal/checkpoint-1300.zip \
-d ~/ckpts/robomme-memer-lora-checkpoint-1300
# 실제 adapter 경로: ~/ckpts/robomme-memer-lora-checkpoint-1300/checkpoint-1300/
hf download Qwen/Qwen3-VL-4B-Instruct
ms-swift 3.x 라인. 4.x 는 swift.llm 모듈 제거 + PtEngine →
TransformersEngine rename 했으므로 학습된 LoRA 와 inference path 가 안 맞음.pip install ms-swift==3.12.6. transformers 도 자동으로
4.57.6 으로 다운그레이드됨 (qwen-vl-utils 0.0.14, peft 0.18.1 매칭).MemER MODEL_TYPE 은 symbolic-grounded-subgoal/79999 VLA 사용.
# 11.55 GB
hf download Yinpei/mme_vla_suite \
--include "symbolic-grounded-subgoal/79999.zip" \
--local-dir runs/ckpts/mme_vla_suite
# unzip — ⚠️ zip 내부에 절대경로 nesting 됨 (home/daiyp/MME-VLA-Suite/...).
# 추출 후 79999/ 만 제 위치로 옮기고 home/ 은 삭제.
cd runs/ckpts/mme_vla_suite/symbolic-grounded-subgoal
yes | unzip -q -o 79999.zip
mv home/daiyp/MME-VLA-Suite/runs/ckpts/mme_vla_suite/symbolic-grounded-subgoal/79999 ./79999
rm -rf home 79999.zip
# 최종 구조: 79999/{_CHECKPOINT_METADATA, assets, params}
export OPENPI_DATA_HOME=~/openpi_data
.venv/bin/python scripts/download_pi05_base.py
# (gs://openpi-assets/checkpoints/pi05_base 에서 받음, 익명 GCS 가능)
mkdir -p runs/assets/mme_vla_suite/robomme
cp assets/norm_stats.json runs/assets/mme_vla_suite/robomme/
mplib==0.2.1 + mani-skill==3.0.0b21 호환성. Driver/eval script 최상단에:
import mplib
import numpy as np
_orig_set_base_pose = mplib.Planner.set_base_pose
def _patched_set_base_pose(self, pose):
if not isinstance(pose, mplib.pymp.Pose):
pose = np.asarray(pose, dtype=float)
pose = mplib.pymp.Pose(p=pose[:3].tolist(), q=pose[3:].tolist())
return _orig_set_base_pose(self, pose)
mplib.Planner.set_base_pose = _patched_set_base_pose
upstream 에 PR 보내거나 mplib 0.2.x 호환 mani-skill 버전 확인하는 것이 정공법. 일단은 monkey-patch.
export LD_LIBRARY_PATH=$ROBOMME/lib:$LD_LIBRARY_PATH
export VK_ICD_FILENAMES=/etc/vulkan/icd.d/nvidia_icd.json
# 1. Vulkan 자체 검증 — 8 × NVIDIA B200 enumerate 되어야 함
$ROBOMME/bin/vulkaninfo --summary | grep "deviceName"
# expected: deviceName = NVIDIA B200 (×8)
# 2. SAPIEN 최소 렌더 — RenderSystem + Scene + take_picture
$ROBOMME/bin/python -c "
import sapien
scene = sapien.Scene(); scene.add_ground(0)
cam = scene.add_camera(name='c', width=64, height=64, fovy=1, near=0.01, far=10)
scene.update_render(); cam.take_picture()
print('SAPIEN OK')
"
# 3. ManiSkill PickCube — 빌트인 task 동작 확인
$ROBOMME/bin/python -c "
import gymnasium as gym, mani_skill.envs
env = gym.make('PickCube-v1', obs_mode='rgb', render_mode='sensors', num_envs=1)
env.reset(); env.close(); print('ManiSkill OK')
"
# 4. RoboMME BinFill — 모든 wrapper 포함, mplib monkey-patch 필요
$ROBOMME/bin/python -c "
import mplib, numpy as np
_orig=mplib.Planner.set_base_pose
def _p(self,pose):
if not isinstance(pose, mplib.pymp.Pose):
pose=np.asarray(pose,dtype=float)
pose=mplib.pymp.Pose(p=pose[:3].tolist(),q=pose[3:].tolist())
return _orig(self,pose)
mplib.Planner.set_base_pose=_p
import sys; sys.path.insert(0,'examples/robomme')
from env_runner import EnvRunner
r = EnvRunner(env_id='BinFill', video_save_dir='./tmp', max_steps=10)
r.make_env(0)
obs = r.get_init_obs()
print(f'BinFill OK image={obs[\"images\"][0].shape}')
r.close_env()
"
scripts/eval.sh 패턴)# Terminal 0 (or tmux pane 0): VLA policy server, GPU 0
CUDA_VISIBLE_DEVICES=0 \
OPENPI_DATA_HOME=~/openpi_data \
uv run scripts/serve_policy.py --seed=7 --port=8000 \
policy:checkpoint \
--policy.dir=runs/ckpts/mme_vla_suite/symbolic-grounded-subgoal/79999 \
--policy.config=mme_vla_suite
# Terminal 1: sim + VLM client, GPU 1
conda activate robomme
export LD_LIBRARY_PATH=$ROBOMME/lib:$LD_LIBRARY_PATH
export VK_ICD_FILENAMES=/etc/vulkan/icd.d/nvidia_icd.json
export USE_HF=1
CUDA_VISIBLE_DEVICES=1 python examples/robomme/eval.py \
--args.model_seed=7 --args.port=8000 \
--args.policy_name=symbolic-grounded-subgoal --args.model_ckpt_id=79999 \
--args.use-memer --args.subgoal-type=grounded_subgoal \
--args.memer_adapter_path=~/ckpts/robomme-memer-lora-checkpoint-1300/checkpoint-1300 \
--args.only_tasks=BinFill
⚠️
examples/robomme/eval.py에 mplib monkey-patch 를 import 시점에 적용하도록 추가해야 함 (또는 sitecustomize.py / .pth 로 inject).
GT trajectory replay 로 LoRA 동작만 검증하려면:
USE_HF=1 CUDA_VISIBLE_DEVICES=<idle> python scripts/eval_robomme_memer_lora.py \
--lerobot-path ~/Dataset/robomme/BinFill_lerobot \
--episode-index 0 \
--adapter-path ~/ckpts/robomme-memer-lora-checkpoint-1300/checkpoint-1300 \
--output-dir eval_outputs/robomme_BinFill_ep0
108 calls / ~178 s on B200 sdpa. 출력은 sister repo
(~/repos/Robotics/memer/scripts/render_robomme_subtask_video.py) 의
renderer schema 와 호환되므로 visualization.mp4 만들 수 있음.
apptainer exec --nv docker://nvidia/cuda:... — --nv 가 host 의
broken libGLX_nvidia 를 그대로 bind. 컨테이너로 우회 못 함.libnvidia-vulkan-producer.so 별도 추출 — 580 series 는 별도
파일 없음, libGLX_nvidia.so.0 자체에 Vulkan code 포함.__malloc_hook, ErrorF, miCreateDefColormap 등 X.org symbol stub
shim — 100+ 심볼이 줄줄이라 비현실적이고, 실제로는 noise 였음
(LD_DEBUG 가 dlsym 실패를 fatal 로 카테고리하지만 lib 동작은 영향 없음)./home/nas_main/sungwonhwang/.conda/envs/mav (CARLA 사용자 env). CARLA UE5
가 헤드리스 Vulkan 으로 동작하던 그 env 의 conda-forge libglvnd +
libdrm 이 NVIDIA Vulkan ICD 를 깨우는 결정적 dep 이라는 걸 발견.
RoboCasa (MuJoCo+EGL) 가 이 클러스터에서 작동했던 이유 (= EGL path 는
GLVND 거치지 않고 직접 libEGL_nvidia 호출) 와 대조적으로, Vulkan path 는
GLVND dispatch 가 필요하다는 걸 학습.