robocasa_human_lerobot(410/1382 파손) → X-WAM-RoboCasa(1235 완전본, 256×256 mp4)로 전환 권장.lerobot_utils.py의 ACTION_KEY_ORDERING_HDF5만 데이터와 일치.info.json의 fps: 10은 오기 — 실제 20 Hz. 독립 증거 3가지. 이걸 믿었으면 action_per_frame을 절반으로 잡고 학습할 뻔했다.1차 조사는 ~/Dataset/robocasa_human_lerobot 하나만 보고 "LIBERO 레시피와 정확히 일치"라고 결론냈다. 그런데 두 가지가 미검증이었다:
used_action_channel_ids / action_per_frame / norm_stat 세 설정을 직접 좌우한다. 틀리면 학습은 돌지만 정책이 잘못 배운다.소스 코드 순서와 실제 데이터가 어긋나는 것을 발견해, 데이터를 기준으로 재확정했다. state 25-dim은 문서가 없어 사원수 연산으로 역공학했다.
| 경로 | 크기 | 포맷 | 내용 |
|---|---|---|---|
~/Datasets/X-WAM-RoboCasa | 5.2G | X-WAM json+mp4 | 주 소스. 1235 eps / 341K frames / 24 task / 256×256 / 20fps / 3 cam RGB+depth / abs EE + raw 7-dim |
~/Datasets/robocasa_xwam | 1.6G | X-WAM json+mp4 | 1320 eps / 365K frames. depth 없음, raw_actions만 |
~/Dataset/robocasa_human_lerobot | 6.4G | LeRobot v2.0 | 410/1382만 존재(파손). 128×128. fps:10 오기 |
~/Datasets/robocasa_lerobot_cams | 690M | npz | 카메라 T(4×4)/K(3×3) + base_to_eef_pos. 기하 전용, LingBot 무관 |
~/repos/Robotics/robocasa/datasets/v0.1 | 2.3G | 원본 hdf5 | 31개(single 26 + multi 5). state-only(이미지 없음) → 재렌더 필요 |
정본은 robocasa/utils/lerobot_utils.py:65-69:
| idx | 내용 | abs / rel | 기준 프레임 | 정규화 | 물리 스케일 |
|---|---|---|---|---|---|
| 0:3 | EEF position | relative (델타) | base | [-1, 1] | × 0.05 m |
| 3:6 | EEF rotation (axis-angle) | relative (델타) | base | [-1, 1] | × 0.5 rad |
| 6 | gripper_close | 명령 | — | ±1 이진 | +1 닫기 / −1 열기 |
| 7:10 | base x / y / yaw | 속도 (JOINT_VELOCITY) | base | [-1, 1] | × 0.5 rad/s |
| 10 | torso | 관절 위치 (JOINT_POSITION) | — | [-1, 1] | × 0.05 |
| 11 | control_mode | 플래그 | — | ±1 | −1 arm 모드 / +1 base 모드 |
default_pandaomron.json 원문: "input_type": "delta", "input_ref_frame": "base", output_max: [0.05,0.05,0.05, 0.5,0.5,0.5]. → 월드도 EEF도 아닌 로봇 베이스 프레임 기준이다.
part_controller_config dict 조립 순서(right → torso → base → right_gripper)대로면 torso가 idx 6이어야 한다. 하지만 실제 데이터는 idx 6이 gripper다. RoboCasa v0.5 데이터셋은 그 순서와 다른 조합으로 생성됐다.
| dim | 검증 방법 | 결과 | 결론 |
|---|---|---|---|
| 6 | gripper_qpos 평균 비교 (5프레임 lag 포함) | +1 → 0.0208 / −1 → 0.0387 | gripper |
| 7 / 8 / 9 | base 프레임 Δx / Δy / Δyaw 상관 | +0.899 / +0.931 / +0.991 | forward / lateral / yaw |
| 7:11 | dim11(mode)와의 동시발생 | non-zero 프레임의 100%가 mode == +1 | base 모드 전용 |
| 10 | 희소성 + 값 분포 | 15,571 중 10 프레임만 non-zero, 값 −0.5~−0.557 연속 | torso |
commanded_delta × 0.05 vs 실제 EEF 변위 회귀 → 기울기 0.22 (x 0.219 / y 0.218 / z 0.224, corr 0.91~0.93). OSC 임피던스 컨트롤러(kp=150)가 한 스텝에 ~20%만 실현한다. LIBERO도 동종 신호라 학습은 문제없지만, 액션을 적분해 궤적으로 해석하면 안 된다.
원본 hdf5의 action_dict가 rel_pos / rel_rot_axis_angle / rel_rot_6d / gripper — 전부 rel_ prefix로 relative임이 명시돼 있다. v0.5부터 actions_abs(절대) 키가 별도로 있으나, openpi 변환 스크립트는 actions(relative)만 썼다.
robocasa_human_lerobot state 25-dim (역공학)검증: q_base⁻¹ ⊗ q_eef_world를 손으로 계산해 dims 14:18과 소수점 4자리까지 일치. R_baseT(p_eef − p_base) = dims 11:14 일치. LingBot-VA는 state를 안 쓰지만, 절대 pose를 재구성하려면 11:18이 필요하다.
fps: 10은 잘못된 메타데이터 — 실제 20 Hz1차 분석의 "10fps → stride 1 → action_per_frame=4 = LIBERO 정확 일치"는 틀렸다. 독립 증거 3가지:
| # | 증거 | 수치 |
|---|---|---|
| 1 | Δgripper_qpos / gripper_qvel | 0.0487 → dt = 1/20.5 s (timestamp가 주장하는 0.1 s 아님) |
| 2 | commanded↔realized 기울기를 X-WAM(공식 20fps)과 비교 | 0.22 vs 0.20 — 동일 → 행 1개 = 컨트롤 스텝 1개, 데시메이션 없음 |
| 3 | 에피소드 길이 분포를 X-WAM과 비교 | min 12 / median 245 vs 250 / max 889 vs 889 → 동일 원본 demo |
→ 올바른 설정은 stride 2 → action_per_frame = 8 (영상 10fps, README 권장 5–15fps 범위). LIBERO cfg가 아니라 va_demo_cfg(256×256, action_per_frame=8)와 맞는다.
_action_post_process는 액션 배열에 stride를 적용하지 않는다 (required_action_num = latent_frame_num × frame_stride × 4). 영상만 2배 다운샘플되고 액션은 20Hz 전량이 들어간다 → 정보 손실 없음.robocasa_human_lerobot | X-WAM-RoboCasa | |
|---|---|---|
| 완결성 | 410 / 1382 (파손) | 1235 / 1235 |
| 해상도 | 128×128 | 256×256 |
| 영상 | parquet 내 PNG | mp4 H.264 (VAE 직투입) |
| 액션 | 12-dim raw | raw_actions 7-dim + 절대 EE pose 둘 다 |
| LingBot cfg | — | va_demo_cfg (256, apf 8) 정합 |
실측 raw_actions q01/q99 (85K 프레임 샘플):
소스 코드만 믿으면 틀린다. robosuite의 컨트롤러 조립 순서대로면 torso가 idx 6이어야 했지만 실제 데이터는 gripper였다. 그리고 fps 메타데이터마저 틀렸다. 이걸 그대로 믿었으면 action_per_frame을 절반으로 잡고 학습했을 것이고, 증상이 조용해서 한참 뒤에나 알아챘을 것이다.
주 데이터셋을 X-WAM-RoboCasa로 바꾸는 게 맞다. 완전성 · 해상도 · 영상포맷 · 액션표현 4개 축 모두 우세하고, 1차 조사의 최대 blocker(410/1382 파손으로 인한 silent index 오정렬)가 통째로 사라진다.
LingBot이 픽셀을 안 읽으므로 X-WAM이 LeRobot 포맷이 아닌 것은 문제가 아니다. action 컬럼만 있는 최소 LeRobot 껍데기로 충분하고, 이미지 키를 선언하지 않으면 meta.video_keys가 비어서 mp4 존재 검사도 걸리지 않는다.
raw_actions[:, :7] 그대로, used_action_channel_ids=range(0,7), env_type='none'. 최소 변경.left_ee_pos(3) + left_ee_rotm(9)→quat(4) = 7-dim 절대 pose를 get_relative_pose로 세그먼트 첫 프레임 기준 상대화. 단 _action_post_process가 env_type=='robotwin_tshape'에서만 호출하므로 분기 추가 필요 (lerobot_latent_dataset.py:260에 ## TODO support get_relative_pose for other dataset 주석이 이미 있다).meta/{info,episodes,tasks,stats} + action-only parquet (+ action_config 주입)empty_emb.ptrobbyant/lingbot-va-base 다운로드, lingbot env에 lerobot==0.3.3 scipy wandb --no-deps 설치va_robocasa_cfg.py (va_demo_cfg 베이스: 256×256, action_per_frame=8, 위 q01/q99)sbm으로 본 학습긴 에피소드 처리 — median 250 / p95 496 / max 889 frames @ 20Hz. stride 2여도 latent frame 최대 ~111, 카메라 3개면 latent width 48 → 시퀀스 길이가 크다. 세그먼트 분할 전략을 정해야 한다.