outputs/*/serve.log 258개 런 분석 | 관측 창: 2026-09-18 ~ 09-21 00:41 (UTC)type=molmobot 서빙이 09-18 13:21 UTC 첫 런치 이후 144회 런치 / 17,085 connection / 서버 예외 0건. 144/144가 첫 connection에 도달(중앙값 40 s).Policy does not support state saving, disabling concurrency 출력 (pi 정책 114회 런치는 0회). 원인은 MolmoBotGoalPolicy가 로컬 StatefulPolicy를 상속해 서버의 isinstance(..., molmo_spaces StatefulPolicy)가 False가 되는 것.Semaphore(1) 대기 (평균 39.0 s, 최대 219.7 s) — throughput 손실, episode 내용은 불변.policy.reset()을 안 부름 → connection의 99.2%(16,941/17,085)가 직전 episode의 obs_history/action_buffer를 이월한 채 시작. SR에 미친 영향은 측정된 바 없음.09-17 커밋 aaa3f8d는 serve.py에 type == "molmobot" 분기(+19줄)를 추가해 MolmoBot(F=2, goal 지원) 정책을 websocket 서버로 띄울 수 있게 했다. 260918 카드는 이 변경에 대해 “실제 websocket 연결/하네스 연동 스모크 기록 없음 — 코드 추가만 완료”라고 명시했고, Next Step으로 실제 접속·rollout 스모크를 남겼다.
이번 3일(09-18~21) 동안 MolmoBot 저장소에는 새 claude/*.md, git commit, MolmoBot workdir의 SLURM 기록이 모두 없다. 남아 있는 유일한 활동 흔적은 MolmoBot-Pi0/outputs/<date>/<time>/serve.log(서버 런치마다 1개, 09-15 이후 258개)다. 이 카드는 그 로그를 정량 집계해 (a) 미검증 항목이 실제로 검증되었는지, (b) 운영 중 드러난 문제가 있는지를 확인한다.
type=molmobot 경로가 한 번도 실행되지 않았다. 또한 이 경로는 eval.py in-process 경로(tasks/task.py:243에서 episode마다 policy.reset() 호출)와 달리 서버가 lifecycle을 관리하므로, 동등성이 코드만으로는 보장되지 않았다.코드 변경은 하지 않았고(읽기 전용 분석), 로그 집계와 서버/정책 소스 정독으로 진행했다.
127.0.0.1(서버와 같은 pod)에서 온다. 타임라인과 260918 카드의 목적으로 미루어 scene_bench 온라인 하네스로 추정하나 로그로는 미확인. ② WebsocketPolicy.reset()이 close() 후 재접속(websocket_policy.py)이고 connection 지속시간 중앙값이 72 s라서 1 connection ≈ 1 episode로 간주했다(미확인).| 날짜 (UTC) | molmobot 런치 | connection | server-hours | pi 런치 (참고) |
|---|---|---|---|---|
| 09-18 (첫 molmobot 13:21:51) | 20 | 2,543 | 48.3 | 43 (→13:54 이후 0), 1,235 conn |
| 09-19 | 44 | 6,388 | 121.6 | 0 |
| 09-20 | 72 | 7,954 | 170.0 | 0 |
| 09-21 (→00:41) | 8 | 200 | 4.1 | 0 |
| 합계 | 144 | 17,085 | 344.1 | pi 09-15~18: 114회 / 2,669 conn |
첫 molmobot 런치(09-18 13:21 UTC = 22:21 KST)는 260918 카드 작성(10:10 KST)의 약 12시간 뒤이고, 그 33분 뒤(13:54 UTC)를 마지막으로 pi 서버 런치가 사라진다. 동시에 떠 있던 서버는 최대 14개(로그 span 기준).
체크포인트 (모두 type=molmobot, jointpos, exo_1_left + wrist_left) | 런치 | connection |
|---|---|---|
molmobot_runs/molmobot_place_oc/10000 — goal 없이 학습한 no-goal 기준선 | 138 | 15,502 |
molmobot_runs/molmobot_place_oc_goal/10000 — goal 이미지 학습 | 6 | 1,583 |
공통 설정(로그 확인): max_joint_delta=0.2, action_horizon=16, n_obs_steps=2, obs_step_delta=8, execute=8, flow_steps=10.
| 지표 | 값 |
|---|---|
| 런치 → 첫 connection 도달 | 144/144 (min / 중앙 / 평균 / max = 28 / 40 / 43.0 / 159 s, 모델 로드 + 클라이언트 대기 포함 상한) |
서버 측 inference 예외 (Error in policy server / INTERNAL_ERROR) | 0 |
| OOM / Killed / MemoryError 흔적 | 0 |
| ERROR 레벨 로그 (molmobot 런) | 149건 전부 websockets.server: opening handshake failed (EOFError: connection closed while reading HTTP request line) — 139개 런치에서 1회, 5개 런치에서 2회 |
| connection 지속시간 (닫힌 17,057건) | p25 66 / 중앙 72 / p75 78 / p95 113 / max 291 s, 합 338.3 connection-hours |
| 런치당 connection | 중앙 91.5, max 1,065; 132/144가 ≥10, 5/144가 ≤2 (수명 41~134 s의 스모크성 런) |
disabling concurrency가 molmobot 런치 144/144에서만 출력| 항목 | pi (PiPolicy) | molmobot (MolmoBotGoalPolicy) |
|---|---|---|
| 상속 | class PiPolicy(InferencePolicy, StatefulPolicy) — molmo_spaces.policy.base_policy.StatefulPolicy (pi.py:17,38) | class MolmoBotGoalPolicy(StatefulPolicy) — 로컬 molmobot_pi0.eval.policies.stateful.StatefulPolicy(InferencePolicy) (molmobot.py:17,30) |
서버 isinstance(policy, StatefulPolicy) (policy_server.py:18,92) | True | False (서로 다른 클래스) |
서버 로그 disabling concurrency | 0 / 114 런치 | 144 / 144 런치 |
| 동시성 제어 | Semaphore(max_concurrency=100) | Semaphore(1) — connection 수명 동안 점유 (생성 :93,:96, 획득 :156) |
새 connection 시 서버 동작 (:166-170) | 신규 client_id → policy.reset(), 재접속 → set_state() | 호출 없음 (두 호출 모두 Stateful 분기 안쪽) |
molmobot.py:30의 주석은 “두 베이스를 같이 쓰면 MRO 충돌”이라 로컬 클래스를 만든 이유를 적고 있다. 이는 로컬 StatefulPolicy(InferencePolicy)와 InferencePolicy를 같이 상속할 때의 충돌이며, pi.py:38이 molmo_spaces의 StatefulPolicy(BasePolicy)(InferencePolicy와 형제 클래스)를 함께 상속해 문제없이 동작하는 것과 대비된다.
Semaphore(1) 대기동시에 2개 connection이 열린 런치는 5개(molmobot 139개는 항상 최대 1개). 서버는 connection을 받아 metadata를 보낸 뒤 semaphore에서 대기하므로 앞 connection이 닫힐 때까지 추론이 시작되지 않는다.
| 런치 (UTC) | connection | 평균 대기 | 최대 대기 | >1 s 대기 | connection 시간 중 대기 비중 |
|---|---|---|---|---|---|
| 09-18 17:57:05 | 325 | 33.3 s | 152.8 s | 281 | 48.9% |
| 09-19 20:17:15 | 1,063 | 41.8 s | 219.7 s | 992 | 52.5% |
| 09-20 08:46:22 | 33 | 38.2 s | 101.6 s | 28 | 53.4% |
| 09-20 09:10:36 | 204 | 38.9 s | 144.5 s | 173 | 48.9% |
| 09-20 14:00:57 | 89 | 27.3 s | 110.0 s | 58 | 38.6% |
| 합계 | 1,714 (전체 17,085의 10.0%) | 39.0 s | 219.7 s | 1,532 | 50.8% |
Semaphore(1) 점유” 모델로 1시간 정지를 겪은 바 있다.서버가 reset()을 부르지 않으면 같은 서버 프로세스의 정책 인스턴스가 connection 사이에 상태를 공유한다. 첫 connection은 생성자(molmobot.py:49의 self.reset())로 깨끗하므로, 영향 대상은 17,085 − 144 = 16,941건(99.2%)이다.
buffer_index는 1~8 사이. execute=8이므로 다음 episode 첫 스텝에서 직전 chunk의 남은 0~7개 action이 재생된다(max_joint_delta=0.2 클램프는 적용됨)._frames의 idx<0은 버려짐), 서버 경로는 t−8 슬롯에 직전 episode 후반 프레임이 들어가 2장이 된다 → 학습/추론 입력 구성이 처음 8 step에서 달라짐.inference_model이 스텝마다 카메라 2장을 append(molmobot.py:103)하고 reset 없이는 비워지지 않는다. 서버 수명 최대 44,776 s(12.4 h), 최대 1,065 connection이지만 로그에서 OOM 흔적 0건 — 메모리 증가량은 미측정.websocket_policy.py)는 매 스텝 model_input["task"]를 채우므로 _last_prompt 이월 문제는 없음.molmobot_place_oc를 쓴 온라인 restore 결과들)가 영향을 받았는지.(1) 서빙 경로 자체는 안정적이다. 260918의 +19줄 변경은 144회 런치, 17,085 connection, 최대 12.4 h 수명에서 서버 예외·OOM 0건으로 검증되었다. MolmoBot 평가가 in-process 경로를 벗어나 외부 하네스로 확장될 수 있음이 실증되었다.
(2) 하지만 “동작함”과 “in-process와 동등함”은 별개다. 서버는 StatefulPolicy 여부로 lifecycle(reset·state 저장·동시성)을 결정하는데, MolmoBotGoalPolicy는 이름만 같은 다른 클래스를 상속해 그 계약 밖에 있다. 이 불일치는 예외를 내지 않고 로그 한 줄(disabling concurrency)로만 드러나며, 그래서 144회 동안 아무 오류 없이 통과했다.
(3) 확정된 손실은 throughput뿐이다. 2-client 런치에서 대기가 connection 시간의 50.8%(1,714 connection). 정확성 위험(상태 이월)은 코드 정독으로 도출한 가설이며 크기는 미지수다 — 특히 이 서버를 쓴 결과를 해석할 때 “영향 없음”이 검증되기 전까지는 미확정 요인으로 남겨야 한다.
① 상태 이월이 실제 rollout 지표를 바꾸는지 미측정. ② client 식별·episode 경계는 로그에 없어 “1 connection ≈ 1 episode”는 추정. ③ 대기 시간은 모델 추정치(직접 로깅 없음). ④ obs_history 메모리 증가량 미측정. ⑤ 진행 중이던 서버의 로그는 관측 시점(09-21 10:20 KST)에서 절단되어 server-hours·connection이 하한.
A. 수정 후보 (미적용·미검증): molmobot.py의 StatefulPolicy import를 molmo_spaces.policy.base_policy로 바꾸고 class MolmoBotGoalPolicy(InferencePolicy, StatefulPolicy)로 pi.py:38과 같은 형태로 맞춘다. 기대 효과: 로그의 disabling concurrency 소멸, 신규 client_id마다 reset() 호출, set_state/get_state가 서버 경로에서 처음 실행됨(→ MolmoBotPolicyState의 얕은 복사 list(self.obs_history)가 실제로 안전한지도 같이 확인).
B. 동등성 A/B (판정 기준 사전 고정): 동일 seed·동일 cell에서 (a) in-process, (b) 현재 websocket, (c) 수정 websocket. 가설: (a)≈(c), (b)는 각 서버의 2번째 episode 이후 첫 8 step action이 (a)와 다름. 1차는 “2 episode 연속 재생 → 2번째 episode 첫 8 step action 비교” 결정론적 스모크(≤100 step, 로그인 노드 1 GPU로 가능), SR 비교는 sbatch로 분리.
C. 진단 계측: serve.py에서 connection별 obs_history 길이와 첫 chunk index를 로그에 남겨 이월 여부를 직접 관측 + 대기 시간을 모델 추정 대신 직접 로깅.
D. 하네스 쪽 확인: 이 서버로 얻은 scene_bench 결과 중 molmobot_place_oc 계열을 쓴 것이 있는지 대조하고, 있다면 (c) 재측정 후 해석에 반영.