OpenVLA에 로봇 데이터를 넣을 때는 행동 벡터의 길이보다 각 값의 뜻을 먼저 맞춰야 합니다. Bridge 원본 데이터의 연속 그리퍼 값은 뒤에 도달한 열림·닫힘 상태를 기준으로 정리하고, RT-1의 상대 그리퍼 명령은 앞에서 이어 온 상태를 갱신해 절대 표현으로 바꿉니다. 두 입력에 같은 이진화 함수를 적용하면 전혀 다른 행동 라벨을 만들 수 있습니다.
2026년 10월 16일 확인한 OpenVLA의 데이터셋별 변환 코드는 이 차이를 함수로 나눕니다. bridge_orig_dataset_transform()은 binarize_gripper_actions()를, rt1_dataset_transform()은 rel2abs_gripper_actions()를 호출합니다. 아래 설명과 가상 배열은 이 소스의 처리 순서를 읽은 결과이며, 데이터 변환이나 모델 학습을 실행한 기록은 아닙니다.
Bridge의 중간 값은 다음에 도달한 상태를 따라간다
binarize_gripper_actions() 구현은 값이 0.95보다 크면 열림, 0.05보다 작으면 닫힘으로 구분합니다. 그 사이 값은 열리거나 닫히는 도중의 구간으로 취급합니다. 단순히 0.5에서 잘라 반올림하는 방식과는 다릅니다.
함수는 시퀀스를 뒤에서 앞으로 훑습니다. 확실한 끝점 상태를 만나면 그 상태를 기억하고, 앞쪽의 중간 값들을 그 상태로 채웁니다. 가령 그리퍼가 열린 상태에서 점차 닫힌다면, 닫힘으로 이어지는 중간 구간에도 닫힘 라벨이 붙습니다.
다음은 함수를 설명하기 위해 만든 가상 입력을 손으로 계산한 예입니다. Bridge 변환의 전체 전처리 전후가 아니라, 이 함수에 전달한 그리퍼 배열만 비교합니다.
| 함수 입력 | 이 규칙으로 얻는 값 | 이유 |
|---|---|---|
[1.0, 0.7, 0.4, 0.0, 0.0] |
[1.0, 0.0, 0.0, 0.0, 0.0] |
중간 두 값 뒤에 닫힘 끝점이 있음 |
[1.0, 0.7, 0.4] |
[1.0, 0.4, 0.4] |
끝점 없이 종료해 마지막 입력값으로 끝부분을 채움 |
두 번째 행이 중요한 경계 조건입니다. 마지막 구간이 중간 값에서 끝나면 함수는 그 구간의 이진화를 포기하고 마지막 행동 값을 사용합니다. 따라서 함수 이름만 보고 출력 전체가 언제나 0과 1로만 구성된다고 가정하면 이 사례를 놓칩니다. 정확히 0.05와 0.95인 값도 코드의 엄격한 부등식상 중간 구간에 들어갑니다.
RT-1의 0은 닫힘이 아니라 변화 없음이다
RT-1 경로는 gripper_closedness_action을 읽어 상대 명령을 절대 표현으로 바꿉니다. 같은 유틸리티 코드에서 입력이 +0.1보다 크면 닫기, −0.1보다 작으면 열기로 분류하고, 나머지는 이전 상태를 유지합니다. 최종 출력은 열림 1, 닫힘 0입니다.
예를 들어 상대 명령 [0, 0, +1, 0, −1, 0]을 가정하면 절대 표현은 [1, 1, 0, 0, 1, 1]이 됩니다. 앞의 두 0은 닫으라는 명령이 아니라 변화 없음입니다. 세 번째 시점에 닫고, 다음 시점에는 닫힌 상태를 유지하며, 다섯 번째 시점에 엽니다.
처음 두 시점이 열림으로 채워지는 데에는 함수의 초기화 가정이 있습니다. 구현은 처음 나타난 유효 상대 명령의 반대 상태에서 시작합니다. 첫 명령이 닫기라면 그전에는 열려 있었다고 두는 것입니다. 소스의 설명도 첫 상대 명령이 이미 닫힌 그리퍼에 다시 닫기를 지시하는 식의 중복 명령이 아니라고 가정합니다. 시퀀스 전체에 유효한 열기·닫기 명령이 없으면 열린 상태를 사용합니다.
자체 데이터가 초기 그리퍼 상태를 별도 센서로 제공한다면, 그 관측과 이 초기화 가정이 일치하는지 먼저 대조할 수 있습니다. 이미 닫힌 상태로 녹화를 시작했고 첫 기록도 닫기라면, 앞 구간의 의미가 이 함수의 전제와 달라집니다.
Bridge는 그리퍼뿐 아니라 이동 라벨의 시간축도 바꾼다
Bridge 원본 변환은 처음의 영 행동 스텝을 제거한 뒤 그리퍼 이진화를 적용합니다. 이어 relabel_bridge_actions()는 인접한 로봇 상태의 첫 여섯 성분을 빼 이동 라벨을 다시 만듭니다.
movement[t] = state[t + 1, :6] - state[t, :6]
action[t] = concat(movement[t], gripper[t])
위 표기는 코드의 배열 연결을 설명한 의사 표현입니다. 실제 구현은 tf.concat()으로 여섯 이동 성분 뒤에 그리퍼 성분을 이어 붙입니다.
다음 상태가 있어야 차분을 만들 수 있으므로 이 단계에서 마지막 스텝도 잘라 냅니다. 시간축을 따라가는 일반적인 길이 N의 입력을 생각하면, 첫 스텝 제거 후 N−1, 상태 차분 뒤 N−2개의 구간이 남는 흐름입니다. 영상·상태·행동을 서로 다른 길이로 남겨 두면 같은 인덱스가 같은 순간을 가리키는지 해석하기 어려워집니다.
이 변경은 기록된 행동 라벨을 그대로 쓰는 대신, 상태에서 실제로 도달한 변화량을 계산하는 선택입니다. 그리퍼 값만 살펴보고 변환 전후의 행동이 같다고 판단하면 이동 성분과 마지막 구간의 변화를 함께 놓치게 됩니다.
데이터셋 이름이 변환 경로를 선택한다
Bridge라는 이름 아래에서도 원본 배포와 Open X-Embodiment에 포함된 버전은 입력 구조가 다릅니다. bridge_oxe_dataset_transform()은 world_vector, rotation_delta, open_gripper를 읽으며 원본 경로의 그리퍼 이진화 호출을 그대로 거치지 않습니다. 다만 첫 스텝 제거와 상태 차분을 이용한 재라벨링은 이 경로에도 있습니다.
데이터셋 설정도 이 구분을 반영합니다. 예를 들어 기본 영상 키는 bridge_orig에서 image_0, bridge_oxe에서 image입니다. 둘 다 Bridge 계열이라는 이유로 로더 이름만 바꿔 끼우면 영상 키에서부터 읽는 구조가 달라질 수 있습니다.
새 데이터를 연결할 때 남겨 둘 설명은 구체적일수록 좋습니다. 원본 그리퍼 값이 상태인지 상대 명령인지, 어느 시점의 행동을 뜻하는지, 변환 후 몇 개의 시간 구간이 남는지를 한 에피소드로 추적하면 됩니다. 오픈 로봇 데이터셋 비교에서 말하는 행동 의미 호환이 바로 이 수준의 차이입니다. 동일한 배열 크기를 만드는 것에 더해, 같은 숫자가 같은 로봇 행동을 가리키도록 맞추는 작업입니다.