관측은 배포할 때 실제로 얻을 수 있어야 한다
정책의 관측 구성은 현재 판단에 사용할 상태/영상·이력/지시문을 정하는 일이다. 관측 하나가 모든 물리 상태를 알려 주지는 않는다. 예를 들어 한 장의 영상만으로 속도/가림 뒤 물체 상태를 확정하기 어려울 수 있어 이력이 도움이 될 수 있지만, 시간을 정렬하지 않은 영상 여러 장은 오히려 다른 상태를 섞는다. 필요한 정보와 가용 시각을 먼저 정의한다.
입력 기준 시각이 t=0.10 s이고 그때까지 취득/수신한 영상이 0.05/0.10 s라면 두 시점 이력을 쓸 수 있다고 하자. 파일에 0.15 s 영상이 있어도 온라인 0.10에 아직 얻을 수 없었다면 입력에 넣지 않는다. 학습 때 미래를 보게 하고 배포 때 없애면 다른 문제를 푼다. 미래 행동은 정답 시퀀스로 사용할 수 있지만 미래 관측을 입력으로 쓰는 것과 구분해야 한다. 오프라인 데이터의 모든 값이 그 시점에 가용했던 것은 아니다.
이번 합성 계약에서는 첫 행동의 예정 적용 시각을 0.12 s, 제어 간격을 0.05 s로 둔다. H=3 행동 시퀀스의 적용 시각은 0.12/0.17/0.22 s다. H는 예측할 행동 수다. 관측 취득 0.10과 첫 적용 0.12 사이 20 ms를 명시하고, 학습 label의 시각/기준과 실행 지연을 맞춘다. 모델이 미래 행동을 출력했다는 이유로 미래 관측을 이미 받았다고 표시하지 않는다.
shape의 축 이름까지 계약에 넣는다
예제 영상 입력의 축을[B,T,V,C,H_img,W_img]로 정의한다. B는 batch 수, T는 관측 이력 길이, V는 카메라 수, C는 색 채널, H_img/W_img는 영상 높이/너비다. 이 이름은 이번 예제의 규약이며 모든 정책 API의 순서가 같다는 뜻은 아니다. B=1/T=2/V=2/C=3/H_img=2/W_img=4라면 영상 성분은 1×2×2×3×2×4=96개다. uint8이면 원소 payload96 byte, float32로 바꾸면 384 byte며 배열/컨테이너 부가 비용은 제외한다.
그림 M21.02-1. 각 칸은 서로 다른 역할/근거다. 아래 방향은 자료/처리의 연결이며 실제 성공을 자동으로 보장하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
같은 두 시점의 state가 관절 2개/그리퍼 1개라면 shape[B,T,D]=[1,2,3]으로 6성분이다. D는 state 성분 수다. 카메라 이름·RGB/축 순서와 관절 이름/단위·그리퍼 표현을 함께 기록한다. 카메라 두 개를 시간 두 개처럼 잘못 이어도 원소 수가 같을 수 있어 shape 숫자만으로 축 의미를 검증할 수 없다. LeRobot v3의 시간 창 문서는 저장 자료와 시간 창 tensor의 구분을 연결하는 자료다.
무엇을 출력할지와 어느 기준에서 출력할지를 나눈다
관절 공간 행동은 각 관절의 목표를 지정하고, TCP 공간 행동은 공구 위치/방향의 목표를 지정한다. 후자를 관절 명령으로 바꾸려면 프레임/공구와 IK·도달/충돌 검토가 필요하다. 관절 공간이라도 현재 장치/영점과 단위가 같아야 한다. TCP 좌표를 쓴다고 다른 로봇에서 자동으로 실행 가능한 것도 아니다.
표현 기준에도 차이가 있다. 절대값은 목표를 바로 지정한다. 고정 기준 상대값은 예측 때의 한 기준값에 각 offset을 더한다. 누적 증분은 이전 목표에 차례로 더한다. 현재 LeRobot 공식 Action Representations는 relative와 delta를 이처럼 구분한다. 다른 구현이 delta라는 말을 다르게 쓸 수 있으므로 용어만 쓰지 말고 기준 상태·고정/갱신·누적 여부를 적는다.
한 관절 기준 q_ref=0.4 rad와 배열(0.10,0.05,−0.02)을 주자. 이를 절대 목표로 읽으면 그대로 0.10/0.05/−0.02 rad다. 고정 기준 상대라면 각 값을 0.4에 더해 0.50/0.45/0.38 rad다. 누적 증분이라면 첫 0.50, 다음 0.50+0.05=0.55, 마지막 0.55−0.02=0.53 rad다. 같은 세 숫자가 세 경로를 뜻하므로 모델 출력 shape만 맞추는 것으로 부족하다.
속도라면 단위가 rad/s이며 간격을 곱해 위치 변화를 계산하는 또 다른 계약이다. 예측한 목표가 실제로 모두 달성됐다고 가정한 기준과, 매번 새 실제 관측으로 갱신한 기준도 다르다. 실행/재계획 시 사용하는 기준과 해당 시각을 보존한다. 회전/TCP 표현은 해당 프레임과 회전 합성 규칙을 적용해야 하며 단순 성분 덧셈을 모든 3차원 자세에 확대하지 않는다. 그리퍼를 상대 변환에서 제외하는 계약도 별도로 명시한다.
정규화 통계는 행동 표현과 짝을 이룬다
정규화는 값의 크기를 학습에 맞게 바꾸는 변환이다. 이번에는 train 행동 평균 μ_a=0.3 rad, 표준편차 σ_a=0.1 rad로 z=(a−μ_a)/σ_a를 쓴다. z는 무차원이다. 물리 행동 a=0.5 rad는 z=2, 모델 출력 z=1.5는 역변환 a=zσ_a+μ_a=0.45 rad다. 실행 인터페이스에 z=1.5를 그대로 rad로 보내지 않는다.
state의 표준편차가 0.2 rad여도 이 행동 출력에 대신 쓰면 1.5×0.2+0.3=0.6 rad로 다른 목표다. shape가 같으면 코드가 조용히 통과할 수 있다. state/action 통계·성분 순서, 단위·절대/상대 표현과 전처리/후처리를 checkpoint 계약에 묶는다. 상대값으로 학습한다면 상대 변환 뒤의 통계를 사용하고, 역정규화 후 같은 기준을 더해 절대 목표로 복원하는 순서를 확인한다.
정규화 좌표의 clip과 물리 제한도 다르다. z=1.5를 임의로 1로 자르면 위 행동은 0.4 rad가 되어 원래 예측 0.45와 달라진다. clip 여부/범위와 실제 전송 목표를 기록한다. σ가 0/작으면 적용하는 floor/제외 정책도 학습·배포에서 같아야 한다. 통계적 clipping이 로봇의 속도/충돌 제한을 검증해 주는 것은 아니다.
시퀀스 끝의 패딩은 실제 행동이 아니다
episode 끝에 H개의 실제 행동이 없으면 다른 episode의 행을 붙이지 않는다. 제외하거나 길이를 맞추는 padding을 쓰고 각 원소가 실제로 유효한지 mask를 둔다. mask는 여기서 유효 1/패딩 0이다. padding 숫자가 그럴듯해도 관측한 명령으로 취급하지 않는다. 관측 이력의 초반 결측과 미래 행동의 후반 결측도 구분한다.
한 성분의 정규화 오차가(1,2,0), mask가(1,1,0)이라면 유효 평균제곱오차는(1²+2²)/2=2.5다. 전체 길이 3으로 나누면 5/3≈1.667로 패딩 비율에 따라 손실이 작아진다. 이 단위는 유효 개수로 나누는 규약을 택했으며 특정 ACT 구현의 기본 손실과 동일하다고 주장하지 않는다. 유효 개수가 0이면 평균이 정의되지 않으므로 제외/오류 정책을 둔다.
아래 선택 계산은 이 규약을 확인하는 완전한 표준 Python 예다. 정책 학습이나 tensor framework 실행은 아니다.
mu_action, std_action = 0.3, 0.1
pred_z = 1.5
action = pred_z * std_action + mu_action
errors, mask = [1.0, 2.0, 0.0], [1, 1, 0]
valid = sum(mask)
if valid == 0:
raise ValueError("no valid actions")
loss = sum(e * e * m for e, m in zip(errors, mask)) / valid
print(f"action_rad={action:.3f}; valid_mse={loss:.3f}")
출력은 action_rad=0.450; valid_mse=2.500이다. 기존 5.5 정규화/행동 표현과 기존 5.3 Dataset 경계를 연결해 보자. 기본 활동은 아래 숫자만으로 가능하다.