commit 284dfd731e64353c996486432811aebb5ee47ea0 Author: Eiichi Shimazu Date: Fri Nov 6 19:51:31 2026 +0900 11-06 のゲームパッドで直した成功 5 本を diag_joint_hold.py で点検できるようにし (rpc 行 send_angle / stop を log.jsonl の pad の行と組にして指令を作る・長押しの関節は見ない・送ったらすぐ返る daemon の区間は向かう途中を遅れに数えず指令から離れた分 away を見る. 11-01 の結果は変わらない), 外れのない 183926・184452・184650・184906 を corr_v4b の 7 本に足した corr_v5 で, corr2 の 1499 から続きを学習する lab_train.sh / lab_start.sh の --model corr3 を足す (設定 pi05_mecharm_trim_corr_v5_lora・上げる先 pi05-mecharm-trim-corr-lora-v3). build_correction_episodes がゲームパッドの区間を扱えることを test_pad_build.py で確かめる (依頼 97. codex 3 回) Co-Authored-By: Claude Opus 5.5 diff --git a/lab_lib.sh b/lab_lib.sh index f890316..e9a0db7 100644 --- a/lab_lib.sh +++ b/lab_lib.sh @@ -275,11 +275,14 @@ lab_cmd_addon() { # 3f. 何度流しても同じ結果 (install_addon. # corr の学習の設定 (pi05_mecharm_trim_corr_lora) は lab_train.sh の学習と同じ値で足す (add_trim_corr_config.py は # 入っている設定と --steps / --init が違うと止まる. 推論では weight_loader は使わない) # corr2 (依頼 57) は corr_v1_1499 から trim2_corr_v4 で続きを学習したもの (設定 pi05_mecharm_trim_corr_v4_lora) -LAB_MODELS="trim corr corr2" +# corr3 (依頼 97) は corr_v2_1499 から trim2_corr_v5 で続きを学習したもの (設定 pi05_mecharm_trim_corr_v5_lora) +LAB_MODELS="trim corr corr2 corr3" LAB_CORR_STEPS=1500 LAB_CORR_INIT=/workspace/ckpt/3999/params LAB_CORR2_STEPS=1500 LAB_CORR2_INIT=/workspace/ckpt/corr_v1_1499/params +LAB_CORR3_STEPS=1500 +LAB_CORR3_INIT=/workspace/ckpt/corr_v2_1499/params lab_model_def() { # lab_model_def trim|corr → MODEL_REPO MODEL_CKPT MODEL_CONFIG MODEL_DATA MODEL_DESC. 知らない名前なら 1 case "$1" in trim) @@ -300,24 +303,31 @@ lab_model_def() { # lab_model_def trim|corr → MODEL_REPO MODEL_CKPT MODEL_CONFIG=pi05_mecharm_trim_corr_v4_lora MODEL_DATA=mecharm_redblock_box_teach_v1_trim2_corr_v4b # 依頼 58: 182545 を外した 7 本 (8 本の corr_v4 は使わない) MODEL_DESC="corr の 1499 から trim2_corr_v4b で続きを学習した 1499 (依頼 57 / 58)" ;; + corr3) + MODEL_REPO=PixelstoMotors/pi05-mecharm-trim-corr-lora-v3 + MODEL_CKPT=/workspace/ckpt/corr_v3_1499 + MODEL_CONFIG=pi05_mecharm_trim_corr_v5_lora + MODEL_DATA=mecharm_redblock_box_teach_v1_trim2_corr_v5 # 依頼 97: corr_v4b の 7 本 + 11-06 のゲームパッドの 4 本 + MODEL_DESC="corr2 の 1499 から trim2_corr_v5 で続きを学習した 1499 (依頼 97)" ;; *) return 1 ;; esac } -lab_cmd_addon_model() { # lab_cmd_addon_model trim|corr|corr2 → 3f (trim は lab_cmd_addon と同じ. corr・corr2 は学習の設定と assets も足す) +lab_cmd_addon_model() { # lab_cmd_addon_model trim|corr|corr2|corr3 → 3f (trim は lab_cmd_addon と同じ. corr〜corr3 は学習の設定と assets も足す) lab_model_def "$1" || return 1 if [ "$1" = trim ]; then lab_cmd_addon; return; fi local corr_args="--steps $LAB_CORR_STEPS --init $LAB_CORR_INIT" [ "$1" = corr2 ] && corr_args="--variant v4 --steps $LAB_CORR2_STEPS --init $LAB_CORR2_INIT" + [ "$1" = corr3 ] && corr_args="--variant v5 --steps $LAB_CORR3_STEPS --init $LAB_CORR3_INIT" # assets は hf download が置いたモデルの assets/local/<データ名> を, openpi の assets/<設定>/local/ に写す # (trim の 3f が assets/pi05_mecharm_trim_lora/local/ に写すのと同じ形. 中身は trim2 と同じ正規化の値) echo "cd /workspace/openpi && python3 /workspace/r2r2r/pi05/openpi_addon/install_addon.py /workspace/openpi && python3 /workspace/r2r2r/add_trim_config.py /workspace/openpi && python3 /workspace/r2r2r/pi05/openpi_addon/add_trim_corr_config.py /workspace/openpi $corr_args && mkdir -p assets/$MODEL_CONFIG/local && cp -r $MODEL_CKPT/assets/local/$MODEL_DATA assets/$MODEL_CONFIG/local/" } -# ---- lab_train.sh で作るモデル (依頼 57. --model corr | corr2) ---- +# ---- lab_train.sh で作るモデル (依頼 57. --model corr | corr2. 依頼 97 で corr3) ---- # 作るモデルの名前は lab_start.sh の --model と同じ. 続きの元 (TRAIN_FROM) も lab_model_def のモデル -LAB_TRAIN_MODELS="corr corr2" -lab_train_def() { # lab_train_def corr|corr2 → TRAIN_* (知らない名前なら 1) +LAB_TRAIN_MODELS="corr corr2 corr3" +lab_train_def() { # lab_train_def corr|corr2|corr3 → TRAIN_* (知らない名前なら 1) case "$1" in corr) # 依頼 49: 3999 から trim2_corr_v3 で続きを学習した 1499 TRAIN_FROM=trim; TRAIN_VARIANT=v3 @@ -325,6 +335,9 @@ lab_train_def() { # lab_train_def corr|corr2 → TRAIN_* (知らない corr2) # 依頼 57: corr の 1499 から trim2_corr_v4b (依頼 58) で続きを学習する TRAIN_FROM=corr; TRAIN_VARIANT=v4 TRAIN_FROM_KIOXIA=pi05_mecharm_trim_corr_lora_v1/1499 ;; + corr3) # 依頼 97: corr2 の 1499 から trim2_corr_v5 で続きを学習する + TRAIN_FROM=corr2; TRAIN_VARIANT=v5 + TRAIN_FROM_KIOXIA=pi05_mecharm_trim_corr_lora_v2/1499 ;; *) return 1 ;; esac lab_model_def "$1" || return 1 @@ -336,8 +349,8 @@ lab_train_def() { # lab_train_def corr|corr2 → TRAIN_* (知らない lab_model_def "$1" # MODEL_* は作るモデルのものに戻す } -lab_cmd_addon_train() { # lab_cmd_addon_train corr|corr2 → lab_train.sh の 3f - # corr は lab_cmd_addon と同じ (3999 を取っているので trim の assets も写す). corr2 は 3999 を取らないので +lab_cmd_addon_train() { # lab_cmd_addon_train corr|corr2|corr3 → lab_train.sh の 3f + # corr は lab_cmd_addon と同じ (3999 を取っているので trim の assets も写す). corr2・corr3 は 3999 を取らないので # addon と trim2 の設定だけを入れる (学習の設定と正規化の値は pod_prep_trim_corr.sh が置く) if [ "$1" = corr ]; then lab_cmd_addon; return; fi echo "cd /workspace/openpi && python3 /workspace/r2r2r/pi05/openpi_addon/install_addon.py /workspace/openpi && python3 /workspace/r2r2r/add_trim_config.py /workspace/openpi" diff --git a/lab_start.sh b/lab_start.sh index bc67b77..41ec59b 100755 --- a/lab_start.sh +++ b/lab_start.sh @@ -13,8 +13,11 @@ # corr = 3999 から trim2_corr_v3 で続きを学習した 1499 (PixelstoMotors/pi05-mecharm-trim-corr-lora-v1) # corr2 = corr の 1499 から trim2_corr_v4b で続きを学習した 1499 (PixelstoMotors/pi05-mecharm-trim-corr-lora-v2. # 依頼 57. lab_train.sh --model corr2 で作る. Pod の /workspace/ckpt/corr_v2_1499) +# corr3 = corr2 の 1499 から trim2_corr_v5 で続きを学習した 1499 (PixelstoMotors/pi05-mecharm-trim-corr-lora-v3. +# 依頼 97. lab_train.sh --model corr3 で作る. Pod の /workspace/ckpt/corr_v3_1499) # 取る場所・設定・assets・サーバーの起動・つなぎ直しの確かめが選んだモデルに合う. 安全範囲 (学習データ ±10°) -# と位置合わせのお手本はどれも trim2 の raw_episodes (corr_v3・corr_v4 と合わせても範囲はほぼ同じで, trim2 の方が狭い) +# と位置合わせのお手本はどれも trim2 の raw_episodes (corr_v3・corr_v4 と合わせても範囲はほぼ同じで, trim2 の方が狭い. +# corr_v5 は 11-06 の 184650 の j2 が trim2 の上限 +31.4° を最大 11° 超える) # つなぎ直しで, 残っている Pod のサーバーが別のモデルで動いていれば, そのことを出して止まる # # 1. Pod を作る (A40×1・Runpod Pytorch 2.8.0・コンテナのディスク 200GB・22/tcp を外へ出す) @@ -62,7 +65,7 @@ while [ $# -gt 0 ]; do --dry-run) DRY_RUN=1; shift ;; --model) [ $# -ge 2 ] || { echo "[ERROR] --model には ${LAB_MODELS// / か } を付ける" >&2; exit 2; } # 値がないと shift 2 が失敗して回り続ける (codex R1) MODEL="$2"; shift 2 ;; - -h|--help) sed -n '2,39p' "$0"; exit 0 ;; + -h|--help) sed -n '2,42p' "$0"; exit 0 ;; *) echo "[ERROR] 知らない引数: $1 (./lab_start.sh --help)" >&2; exit 2 ;; esac done diff --git a/lab_train.sh b/lab_train.sh index a42bc4b..5e5efe3 100755 --- a/lab_train.sh +++ b/lab_train.sh @@ -13,8 +13,11 @@ # corr = 3999 から trim2_corr_v3 で続きを学習 → PixelstoMotors/pi05-mecharm-trim-corr-lora-v1 # corr2 = corr の 1499 から trim2_corr_v4b で続きを学習 → PixelstoMotors/pi05-mecharm-trim-corr-lora-v2 # (設定 pi05_mecharm_trim_corr_v4_lora. 3c で取るのは 3999 ではなく corr の 1499) -# --steps / --init / --exp-name 学習 (既定 1500 / 続きの元の params / trim_corr_v3 か trim_corr_v4) -# 続きの元: corr は /workspace/ckpt/3999/params, corr2 は /workspace/ckpt/corr_v1_1499/params +# corr3 = corr2 の 1499 から trim2_corr_v5 で続きを学習 → PixelstoMotors/pi05-mecharm-trim-corr-lora-v3 +# (依頼 97. 設定 pi05_mecharm_trim_corr_v5_lora. 3c で取るのは corr2 の 1499) +# --steps / --init / --exp-name 学習 (既定 1500 / 続きの元の params / trim_corr_v3・trim_corr_v4・trim_corr_v5) +# 続きの元: corr は /workspace/ckpt/3999/params, corr2 は /workspace/ckpt/corr_v1_1499/params, +# corr3 は /workspace/ckpt/corr_v2_1499/params # --poll-min 進みを見る間 (既定 5 分) # --stall-min 学習のログが何分書かれなければ「止まった」とするか (既定 30 分) # @@ -62,7 +65,7 @@ while [ $# -gt 0 ]; do --stall-min) lab_need_val 30 "$@"; STALL_MIN="$2"; shift 2 ;; --stop) MODE=stop; shift ;; --dry-run) DRY_RUN=1; shift ;; - -h|--help) sed -n '2,36p' "$0"; exit 0 ;; + -h|--help) sed -n '2,39p' "$0"; exit 0 ;; *) echo "[ERROR] 知らない引数: $1 (./lab_train.sh --help)" >&2; exit 2 ;; esac done @@ -92,17 +95,17 @@ if [ $DRY_RUN = 1 ]; then fi CKPT_ROOT="$DATA_ROOT/checkpoints" ADD_TRIM="$DATA_ROOT/lab/Log11/pod/add_trim_config.py" -use_model() { # use_model corr|corr2 → 作るモデルで決まる値 (lab_lib.sh の lab_train_def. 依頼 57) +use_model() { # use_model corr|corr2|corr3 → 作るモデルで決まる値 (lab_lib.sh の lab_train_def. 依頼 57 / 97) lab_train_def "$1" || return 1 - DATA_NAME=$TRAIN_DATA # corr: ..._trim2_corr_v3 / corr2: ..._trim2_corr_v4b (依頼 58) + DATA_NAME=$TRAIN_DATA # corr: ..._trim2_corr_v3 / corr2: ..._trim2_corr_v4b (依頼 58) / corr3: ..._trim2_corr_v5 TAR="$DATA_ROOT/datasets/$DATA_NAME/${DATA_NAME}_raw_episodes.tar" - CONFIG=$TRAIN_CONFIG # corr: pi05_mecharm_trim_corr_lora / corr2: pi05_mecharm_trim_corr_v4_lora - HF_REPO_IN=$TRAIN_REPO_IN # 続きの元 (corr: 3999 / corr2: corr の 1499. lab_start.sh と同じ) + CONFIG=$TRAIN_CONFIG # corr: pi05_mecharm_trim_corr_lora / corr2: ..._v4_lora / corr3: ..._v5_lora + HF_REPO_IN=$TRAIN_REPO_IN # 続きの元 (corr: 3999 / corr2: corr の 1499 / corr3: corr2 の 1499. lab_start.sh と同じ) HF_REPO_OUT=$TRAIN_REPO_OUT # 上げる先 (非公開). 名前は checkpoints/ のフォルダ名に合わせる CKPT_NAME=$TRAIN_CKPT_NAME # KIOXIA の checkpoints/<これ>/<ステップ>/ CKPT_IN=$TRAIN_CKPT_IN # 3c で続きの元を置く場所 CKPT_IN_KIOXIA="$CKPT_ROOT/$TRAIN_FROM_KIOXIA" # HF_REPO_IN と同じもの (由来の指紋を取る. 依頼 54) - PREP_VARIANT=$TRAIN_VARIANT # pod_prep_trim_corr.sh の 3 つ目 (v3 / v4) + PREP_VARIANT=$TRAIN_VARIANT # pod_prep_trim_corr.sh の 3 つ目 (v3 / v4 / v5) } use_model "$MODEL" POD_EXP_DIR=/workspace/openpi/checkpoints/$CONFIG/$EXP @@ -154,7 +157,7 @@ hm() { local x=$1; [ "$x" -lt 0 ] && x=0; printf '%d:%02d' $((x / 3600)) $((x % PROV_PROCESS=""; PROV_ERROR=""; PROV_CKPT_DIR=""; PROV_HF=0; PROV_DONE=0 OPENPI_JSON='[]' # 3f のあとに Pod の openpi のコミットと変更の有無を入れる iso_of() { [ -n "${1:-}" ] && [ "$1" != 0 ] && date -r "$1" '+%Y-%m-%dT%H:%M:%S%z' | sed -E 's/([0-9]{2})$/:\1/'; } -prov_inputs() { # 入力 (学習データ・続きの元 (corr は 3999・corr2 は corr の 1499)・設定を足すスクリプト) を spec の inputs の形で出す +prov_inputs() { # 入力 (学習データ・続きの元 (corr は 3999・corr2 は corr の 1499・corr3 は corr2 の 1499)・設定を足すスクリプト) を spec の inputs の形で出す local init_ck="" case "$INIT" in "$CKPT_IN"/*) init_ck="$CKPT_IN_KIOXIA" ;; esac jq -n --arg data "$DATA_NAME" --arg data_dir "$DATA_ROOT/datasets/$DATA_NAME" \ diff --git a/lab_train_fakes.sh b/lab_train_fakes.sh index 2f787e7..87a5d9f 100644 --- a/lab_train_fakes.sh +++ b/lab_train_fakes.sh @@ -36,6 +36,7 @@ echo "[DRY ] ドライラン: Pod は借りません. 書くのは $LAB_DRY_RO if [ -d /Volumes/KIOXIA/r2r2r-data ]; then for f in "/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v3/mecharm_redblock_box_teach_v1_trim2_corr_v3_raw_episodes.tar" \ "/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v4b/mecharm_redblock_box_teach_v1_trim2_corr_v4b_raw_episodes.tar" \ + "/Volumes/KIOXIA/r2r2r-data/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v5/mecharm_redblock_box_teach_v1_trim2_corr_v5_raw_episodes.tar" \ /Volumes/KIOXIA/r2r2r-data/lab/Log11/pod/add_trim_config.py "$RUNPOD_KEY_FILE" "$HF_TOKEN_FILE"; do echo "[DRY ] 本物の $(basename "$f"): $([ -s "$f" ] && echo ある || echo ない)" done @@ -46,13 +47,14 @@ LAB_ROOT="$DATA_ROOT/lab"; LAB_CURRENT="$LAB_ROOT/.lab_current" RUNPOD_KEY_FILE="$LAB_DRY_ROOT/keys/runpod_api_key.txt"; HF_TOKEN_FILE="$LAB_DRY_ROOT/keys/hf_token.txt" POD_SSH_KEY="$LAB_DRY_ROOT/keys/id_ed25519" mkdir -p "$LAB_DRY_ROOT/keys" "$LAB_DRY_ROOT/fake" "$DATA_ROOT/lab/Log11/pod" \ - "$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v3" "$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v4b" + "$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v3" "$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v4b" \ + "$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_v5" [ -s "$RUNPOD_KEY_FILE" ] || echo "DRY-RUNPOD-SECRET-KEY" > "$RUNPOD_KEY_FILE" [ -s "$HF_TOKEN_FILE" ] || echo "hf_DRYSECRETTOKEN" > "$HF_TOKEN_FILE" [ -s "$POD_SSH_KEY" ] || echo "dry-ssh-key" > "$POD_SSH_KEY" [ -s "$POD_SSH_KEY.pub" ] || echo "ssh-ed25519 AAAA dry" > "$POD_SSH_KEY.pub" [ -f "$DATA_ROOT/lab/Log11/pod/add_trim_config.py" ] || echo "# dry" > "$DATA_ROOT/lab/Log11/pod/add_trim_config.py" -for v in v3 v4b; do # --model corr は corr_v3, corr2 は corr_v4b (依頼 57 / 58) +for v in v3 v4b v5; do # --model corr は corr_v3, corr2 は corr_v4b (依頼 57 / 58), corr3 は corr_v5 (依頼 97) TARF="$DATA_ROOT/datasets/mecharm_redblock_box_teach_v1_trim2_corr_$v/mecharm_redblock_box_teach_v1_trim2_corr_${v}_raw_episodes.tar" [ -f "$TARF" ] || echo "dry tar $v" > "$TARF" done diff --git a/pi05/openpi_addon/add_trim_corr_config.py b/pi05/openpi_addon/add_trim_corr_config.py index d928407..2dd76a0 100644 --- a/pi05/openpi_addon/add_trim_corr_config.py +++ b/pi05/openpi_addon/add_trim_corr_config.py @@ -29,6 +29,10 @@ pi05_mecharm_trim_corr_v4_lora を足す (名前が違うので v3 の設定と python3 add_trim_corr_config.py /workspace/openpi --variant v4 --steps 1500 --init /workspace/ckpt/corr_v1_1499/params 依頼 58: v4 のデータを ..._trim2_corr_v4b (corr_v4 から 10-31 の 182545 を外した 7 本) に替えた. 設定の名前は pi05_mecharm_trim_corr_v4_lora のまま. 8 本の ..._trim2_corr_v4 の設定が入っている config.py には足さずに止まる +依頼 97: --variant v5 で, corr_v5 (corr_v4b の 7 本 + 11-06 のゲームパッドで直した 4 本) と合わせた ..._trim2_corr_v5 の設定 +pi05_mecharm_trim_corr_v5_lora を足す (v3・v4 と並べて入る). 学習率の予定・ほかの値は v3 と同じ. +続きの元 (--init) は corr_v2_1499 (/workspace/ckpt/corr_v2_1499/params) + python3 add_trim_corr_config.py /workspace/openpi --variant v5 --steps 1500 --init /workspace/ckpt/corr_v2_1499/params """ import argparse import re @@ -41,6 +45,7 @@ VARIANTS = { "old_tags": ("teach_v1_trim2_corr_v1", "teach_v1_trim2_corr_v2")}, # 依頼 45 / 46 で入れた版 "v4": {"name": "pi05_mecharm_trim_corr_v4_lora", "data_tag": "teach_v1_trim2_corr_v4b", "old_tags": ("teach_v1_trim2_corr_v4",)}, # 依頼 57 / 58 (8 本の corr_v4 → 182545 を外した 7 本の corr_v4b) + "v5": {"name": "pi05_mecharm_trim_corr_v5_lora", "data_tag": "teach_v1_trim2_corr_v5", "old_tags": ()}, # 依頼 97 } diff --git a/pi05/openpi_addon/pod_prep_trim_corr.sh b/pi05/openpi_addon/pod_prep_trim_corr.sh index 7296957..575f190 100644 --- a/pi05/openpi_addon/pod_prep_trim_corr.sh +++ b/pi05/openpi_addon/pod_prep_trim_corr.sh @@ -6,13 +6,17 @@ # /workspace/data/mecharm_redblock_box_teach_v1_trim2_corr_v3_raw_episodes.tar # /workspace/r2r2r/pi05/ (この依頼の版. add_trim_corr_config.py と convert_to_lerobot.py を使う) # -# bash /workspace/r2r2r/pi05/openpi_addon/pod_prep_trim_corr.sh [v3|v4] +# bash /workspace/r2r2r/pi05/openpi_addon/pod_prep_trim_corr.sh [v3|v4|v5] # 例: bash ... 1500 /workspace/ckpt/3999/params # 依頼 57: 3 つ目に v4 を付けると trim2 + corr_v4 (..._trim2_corr_v4・設定 pi05_mecharm_trim_corr_v4_lora) の準備. # 例: bash ... 1500 /workspace/ckpt/corr_v1_1499/params v4 # 続きの元は corr_v1_1499 (lab_train.sh --model corr2 の 3c が取る). 3999 は取らないので, 正規化の値は # 1499 の assets にある値 (3999 の trim2 の値と sha256 が同じ. 依頼 52 で確かめた) を, 同じ sha256 で確かめて置く # 依頼 58: v4 のデータは ..._trim2_corr_v4b (8 本の corr_v4 から 182545 を外した 7 本. 合わせて 26 本). 設定の名前は同じ +# 依頼 97: v5 は trim2 + corr_v5 (..._trim2_corr_v5・設定 pi05_mecharm_trim_corr_v5_lora. 合わせて 30 本). +# 続きの元は corr_v2_1499 (lab_train.sh --model corr3 の 3c が取る). 正規化の値は 1499 の assets にある値 +# (trim2 の値と sha256 が同じ. 依頼 97 で KIOXIA の写しを確かめた) を, 同じ sha256 で確かめて置く +# 例: bash ... 1500 /workspace/ckpt/corr_v2_1499/params v5 # v3 (既定) は今までと同じ # # すること (何度流しても同じ結果): @@ -41,13 +45,17 @@ case "$VARIANT" in CONFIG=pi05_mecharm_trim_corr_v4_lora NORM_SRC=/workspace/ckpt/corr_v1_1499/assets/local/mecharm_redblock_box_teach_v1_trim2_corr_v3/norm_stats.json EXP=trim_corr_v4; N_MAC=26 ;; - *) echo "[ERROR] 3 つ目は v3 か v4: $VARIANT" >&2; exit 2 ;; + v5) NAME=mecharm_redblock_box_teach_v1_trim2_corr_v5 + CONFIG=pi05_mecharm_trim_corr_v5_lora + NORM_SRC=/workspace/ckpt/corr_v2_1499/assets/local/mecharm_redblock_box_teach_v1_trim2_corr_v4b/norm_stats.json + EXP=trim_corr_v5; N_MAC=30 ;; + *) echo "[ERROR] 3 つ目は v3 か v4 か v5: $VARIANT" >&2; exit 2 ;; esac TAR=/workspace/data/${NAME}_raw_episodes.tar DATA=/workspace/data/$NAME OPENPI=/workspace/openpi ADDON=/workspace/r2r2r/pi05/openpi_addon -NORM_SHA256=80346837eb12ffa6e683416f0fa41a196519fa8459d1f0b666b06cd621c7f61b # Mac の写しの sha256 (v3 も v4 も同じ trim2 の値) +NORM_SHA256=80346837eb12ffa6e683416f0fa41a196519fa8459d1f0b666b06cd621c7f61b # Mac の写しの sha256 (v3・v4・v5 とも同じ trim2 の値) NORM_DST=assets/$CONFIG/local/$NAME/norm_stats.json # $OPENPI からの相対 [ -f "$TAR" ] || { echo "[ERROR] tar がない: $TAR" >&2; exit 1; } diff --git a/pi05/test_merge_and_config.py b/pi05/test_merge_and_config.py index 4239e75..eb4d17d 100644 --- a/pi05/test_merge_and_config.py +++ b/pi05/test_merge_and_config.py @@ -15,6 +15,8 @@ pod_prep_trim_corr.sh の v4 / KIOXIA の corr_v4 が決めた 8 本で, 前の 5 本は corr_v3 と同じ - 依頼 58: v4 のデータは ..._trim2_corr_v4b (corr_v4 から 182545 を外した 7 本) / 8 本の corr_v4 の設定が入っていたら止まる / KIOXIA の corr_v4b は決めた 7 本で, 中身は corr_v4 と同じ. 8 本の corr_v4 は残っている + - 依頼 97: --variant v5 (pi05_mecharm_trim_corr_v5_lora・..._trim2_corr_v5・続きの元 corr_v2_1499) が v3・v4 と並べて入る / + pod_prep_trim_corr.sh の v5 / KIOXIA の corr_v5 は corr_v4b の 7 本 (中身も同じ) と 11-06 の 4 本 """ import ast import json @@ -297,6 +299,40 @@ class TestConfigV4(unittest.TestCase): self.assertEqual(cfg.read_text(), before) +class TestConfigV5(unittest.TestCase): + """依頼 97: --variant v5 は別の名前の設定として v3・v4 と並べて入り, データと続きの元だけが違う.""" + INIT5 = "/workspace/ckpt/corr_v2_1499/params" + INIT4 = "/workspace/ckpt/corr_v1_1499/params" + + def test_v5_with_v3_v4(self): + for order in (("v5",), ("v3", "v4", "v5"), ("v5", "v4")): + with tempfile.TemporaryDirectory() as td, mock.patch("sys.stdout"): + cfg = fake_config(Path(td)) + inits = {"v3": "/workspace/ckpt/3999/params", "v4": self.INIT4, "v5": self.INIT5} + for v in order: + self.assertEqual(atc.main([td, "--variant", v, "--steps", "1500", "--init", inits[v]]), 0) + c = configs(cfg) + self.assertIn("pi05_mecharm_trim_corr_v5_lora", c) + v5 = c["pi05_mecharm_trim_corr_v5_lora"] + self.assertIn("'local/mecharm_redblock_box_teach_v1_trim2_corr_v5'", v5["data"]) + self.assertIn(self.INIT5, v5["weight_loader"]) + self.assertEqual(v5["num_train_steps"], "1500") + lr = {k.arg: ast.literal_eval(k.value) for k in ast.parse(v5["lr_schedule"]).body[0].value.keywords} + self.assertEqual(lr, {"warmup_steps": 100, "peak_lr": 2.5e-5, "decay_steps": 1500, "decay_lr": 5e-6}) + if "v4" in order: # v4 は今までのまま (corr_v4b・corr_v1_1499). データ・続きの元のほかは同じ値 + v4 = c["pi05_mecharm_trim_corr_v4_lora"] + self.assertIn("'local/mecharm_redblock_box_teach_v1_trim2_corr_v4b'", v4["data"]) + self.assertIn(self.INIT4, v4["weight_loader"]) + for k in set(v4) - {"name", "data", "weight_loader"}: + self.assertEqual(v5[k], v4[k], k) + text = cfg.read_text() + self.assertEqual(atc.main([td, "--variant", "v5", "--steps", "1500", "--init", self.INIT5]), 0) + self.assertEqual(cfg.read_text(), text) # 二重に入れない + with self.assertRaises(SystemExit): # 違う続きの元では止まる + atc.main([td, "--variant", "v5", "--steps", "1500", "--init", self.INIT4]) + self.assertEqual(cfg.read_text(), text) + + class TestPodPrep(unittest.TestCase): """依頼 48: pod_prep_trim_corr.sh は正規化の値を計算し直さず, 3999 の学習の trim2 の値を置く.""" SH = _HERE / "openpi_addon" / "pod_prep_trim_corr.sh" @@ -344,6 +380,21 @@ class TestPodPrep(unittest.TestCase): m = re.search(r"^NORM_SHA256=([0-9a-f]{64})", self.SH.read_text(), re.M) self.assertEqual(hashlib.sha256(mac.read_bytes()).hexdigest(), m.group(1)) + def test_v5_uses_corr2_1499_norm(self): + """依頼 97: v5 は corr_v5 の設定で, 正規化の値は続きの元 (corr2 の 1499) の assets から同じ sha256 で確かめて置く.""" + code = "\n".join(self.lines()) + for x in ("NAME=mecharm_redblock_box_teach_v1_trim2_corr_v5\n", "N_MAC=30 ;;", "CONFIG=pi05_mecharm_trim_corr_v5_lora", + "NORM_SRC=/workspace/ckpt/corr_v2_1499/assets/local/mecharm_redblock_box_teach_v1_trim2_corr_v4b/norm_stats.json", + "EXP=trim_corr_v5;"): + self.assertIn(x, code) + mac = Path("/Volumes/KIOXIA/r2r2r-data/checkpoints/pi05_mecharm_trim_corr_lora_v2/1499/assets/local/" + "mecharm_redblock_box_teach_v1_trim2_corr_v4b/norm_stats.json") + if mac.exists(): + import hashlib + import re + m = re.search(r"^NORM_SHA256=([0-9a-f]{64})", self.SH.read_text(), re.M) + self.assertEqual(hashlib.sha256(mac.read_bytes()).hexdigest(), m.group(1)) + def test_unknown_variant_stops_before_anything(self): r = subprocess.run(["bash", str(self.SH), "1500", "base", "v9"], capture_output=True, text=True) self.assertEqual(r.returncode, 2) @@ -413,5 +464,36 @@ class TestCorrV4bData(unittest.TestCase): self.assertEqual(sorted(Path(n).parent.name for n in names if n.endswith("/episode.npz")), eps) +@unittest.skipUnless((DS / "mecharm_redblock_box_corr_v5").is_dir(), "KIOXIA の corr_v5 がない") +class TestCorrV5Data(unittest.TestCase): + """依頼 97: corr_v5 は corr_v4b の 7 本 (中身も同じ) と, 11-06 のゲームパッドで直した成功のうち外れのない 4 本. + corr_v4b と合わせたもの (v4b) は残す.""" + OLD = TestCorrV4bData.RUNS + NEW = ["pi05_20261106_183926", "pi05_20261106_184452", "pi05_20261106_184650", "pi05_20261106_184906"] + + def test_runs_and_old_same(self): + raw = DS / "mecharm_redblock_box_corr_v5" / "raw_episodes" + self.assertEqual(sorted(p.parent.name for p in raw.glob("[!.]*/episode.npz")), sorted(self.OLD + self.NEW)) + for r in self.OLD: + a = (DS / "mecharm_redblock_box_corr_v4b" / "raw_episodes" / r / "episode.npz").read_bytes() + self.assertEqual(a, (raw / r / "episode.npz").read_bytes(), r) + for r in self.NEW: + m = json.loads((raw / r / "meta.json").read_text()) + self.assertEqual(m["gap_fill"]["mode"], "speed20") + self.assertEqual(m["trim_hold"], {"keep_model": 0, "keep_correct": 1, "keep_grip": 2}) + self.assertGreater(m["correct_steps"], 0) + self.assertNotIn("pi05_20261106_185554", [p.parent.name for p in raw.glob("*/episode.npz")]) + self.assertEqual(len(list((DS / "mecharm_redblock_box_corr_v4b" / "raw_episodes").glob("[!.]*/episode.npz"))), 7) + + def test_merged_and_tar(self): + ds = DS / "mecharm_redblock_box_teach_v1_trim2_corr_v5" + eps = sorted(p.parent.name for p in (ds / "raw_episodes").glob("[!.]*/episode.npz")) + self.assertEqual(len(eps), 30) + tar = ds / "mecharm_redblock_box_teach_v1_trim2_corr_v5_raw_episodes.tar" + names = subprocess.run(["tar", "-tf", str(tar)], capture_output=True, text=True, check=True).stdout.split() + self.assertFalse([n for n in names if Path(n).name.startswith("._")]) + self.assertEqual(sorted(Path(n).parent.name for n in names if n.endswith("/episode.npz")), eps) + + if __name__ == "__main__": unittest.main() diff --git a/test_lab_start.sh b/test_lab_start.sh index be6f152..c481953 100755 --- a/test_lab_start.sh +++ b/test_lab_start.sh @@ -398,13 +398,27 @@ check "corr2 で動いている Pod に --model corr2 → 3b〜4 を飛ばして rm -rf "$T" check "フォルダからモデルの名前 (corr2)" '[ "$(. "$HERE/lab_lib.sh"; lab_model_of_dir /workspace/ckpt/corr_v2_1499)" = corr2 ]' +echo "== 34c. --model corr3 (依頼 97) で新しく作る → corr_v5 で学習したモデルを取り, v5 の設定・assets を足して起動" +setup; run --model corr3 +check "終了コード 0" '[ $RC = 0 ]' +check "corr3 のモデルを /workspace/ckpt/corr_v3_1499 に取る (ほかのモデルは取らない)" 'has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-corr-lora-v3 --local-dir /workspace/ckpt/corr_v3_1499" && ! has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-lora-v1 " && ! has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-corr-lora-v2 "' +check "3f で学習と同じ v5 の設定 (続きの元 corr_v2_1499) を足し, モデルの assets を写す" 'has ssh.log "add_trim_corr_config.py /workspace/openpi --variant v5 --steps 1500 --init /workspace/ckpt/corr_v2_1499/params" && has ssh.log "mkdir -p assets/pi05_mecharm_trim_corr_v5_lora/local && cp -r /workspace/ckpt/corr_v3_1499/assets/local/mecharm_redblock_box_teach_v1_trim2_corr_v5 assets/pi05_mecharm_trim_corr_v5_lora/local/"' +check "corr3 の設定とフォルダでサーバーを起動" 'has ssh.log "--policy.config=pi05_mecharm_trim_corr_v5_lora --policy.dir=/workspace/ckpt/corr_v3_1499 2>&1"' +check "クライアントに --model corr3 を渡す・安全範囲と位置合わせは trim2 のまま" 'has py.log "--model corr3 (PixelstoMotors/pi05-mecharm-trim-corr-lora-v3)" && has py.log "datasets/mecharm_redblock_box_teach_v1_trim2/raw_episodes "' +check "記録に model=corr3" '[ "$(jq -r .model "$T/data/lab/LogT/pod/lab_pod.json")" = corr3 ]' +rm -rf "$T" +setup; state $ID_OLD; pod 200 "$RUNNING"; probe 1 1 1 1 1; serve_dir /workspace/ckpt/corr_v2_1499; run --model corr3 +check "corr2 のサーバーが動いている Pod に --model corr3 → 止まり, --model corr2 を案内" '[ $RC = 1 ] && has out.txt "別のモデル (--model corr2)で動いています" && ! has ssh.log "tmux new" && ! has ssh.log "pkill"' +rm -rf "$T" +check "フォルダからモデルの名前 (corr3)" '[ "$(. "$HERE/lab_lib.sh"; lab_model_of_dir /workspace/ckpt/corr_v3_1499)" = corr3 ]' + echo "== 35. --model に知らない名前 → 何もせずに止まる" setup; run --model foo -check "終了コード 2・使える名前を出す・API を呼ばない" '[ $RC = 2 ] && has out.txt "--model は trim か corr か corr2" && [ ! -s "$T/calls.log" ]' +check "終了コード 2・使える名前を出す・API を呼ばない" '[ $RC = 2 ] && has out.txt "--model は trim か corr か corr2 か corr3" && [ ! -s "$T/calls.log" ]' rm -rf "$T" setup (cd "$T" && PATH="$T/bin:$PATH" perl -e 'alarm 10; exec @ARGV' ./lab_start.sh --log LogT --dry-run --model < /dev/null > "$T/out.txt" 2>&1); RC=$? -check "--model だけで値がない → 回り続けずに終了コード 2 (codex R1)" '[ $RC = 2 ] && has out.txt "--model には trim か corr か corr2 を付ける"' +check "--model だけで値がない → 回り続けずに終了コード 2 (codex R1)" '[ $RC = 2 ] && has out.txt "--model には trim か corr か corr2 か corr3 を付ける"' rm -rf "$T" for a in "--gpu" "--episode" "--log" "--gpu --dry-run" "--episode --log LogT" "--log --dry-run"; do setup diff --git a/test_lab_train.sh b/test_lab_train.sh index fafe2cf..4bf9c55 100755 --- a/test_lab_train.sh +++ b/test_lab_train.sh @@ -213,6 +213,28 @@ TD="$T/data/lab/LogT/train" check "--stop (--model なし): 記録の model=corr2 の設定・exp でログと一覧を取る" '[ $(n_call DELETE) = 1 ] && [ -f "$TD/train_trim_corr_v4.log" ] && has ssh.log "cd /workspace/openpi/checkpoints/pi05_mecharm_trim_corr_v4_lora/trim_corr_v4" && [ "$(jq -r .config.data_name "$TD/train_provenance.json")" = mecharm_redblock_box_teach_v1_trim2_corr_v4b ]' rm -rf "$T" +echo "== 12c. --model corr3 (依頼 97): corr2 の 1499 から trim2_corr_v5 で続きを学習する" +run success --model corr3 +CK3="$T/data/checkpoints/pi05_mecharm_trim_corr_lora_v3" +check "終了コード 0・画面に --model corr3 と続きの元 → 上げる先" '[ $RC = 0 ] && has out.txt "--model corr3 (PixelstoMotors/pi05-mecharm-trim-corr-lora-v2 → PixelstoMotors/pi05-mecharm-trim-corr-lora-v3)"' +check "3c は corr2 の 1499 を /workspace/ckpt/corr_v2_1499 に取る (3999・corr の 1499 は取らない)" 'has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-corr-lora-v2 --local-dir /workspace/ckpt/corr_v2_1499" && ! has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-lora-v1 " && ! has ssh.log "hf download PixelstoMotors/pi05-mecharm-trim-corr-lora-v1 "' +check "3f は 3999 の assets を写さない" 'has ssh.log "add_trim_config.py /workspace/openpi" && ! has ssh.log "cp -r /workspace/ckpt/3999/"' +check "corr_v5 の tar を送り, pod_prep_trim_corr.sh 1500 /workspace/ckpt/corr_v2_1499/params v5" 'has scp.log "mecharm_redblock_box_teach_v1_trim2_corr_v5_raw_episodes.tar root@" && ! has scp.log "corr_v4b_raw_episodes.tar" && ! has scp.log "corr_v3_raw_episodes.tar" && has ssh.log "pod_prep_trim_corr.sh 1500 /workspace/ckpt/corr_v2_1499/params v5"' +check "学習は pi05_mecharm_trim_corr_v5_lora --exp-name=trim_corr_v5" 'has ssh.log "uv run scripts/train.py pi05_mecharm_trim_corr_v5_lora --exp-name=trim_corr_v5 --overwrite > /workspace/logs/train_trim_corr_v5.log"' +check "Hugging Face の pi05-mecharm-trim-corr-lora-v3 へ上げ, KIOXIA の checkpoints/pi05_mecharm_trim_corr_lora_v3/1499 に置く" 'has ssh.log "hf_upload_ckpt.py --dir /workspace/openpi/checkpoints/pi05_mecharm_trim_corr_v5_lora/trim_corr_v5/1499 --repo PixelstoMotors/pi05-mecharm-trim-corr-lora-v3" && [ -f "$CK3/1499/_CHECKPOINT_METADATA" ] && [ ! -e "$T/data/checkpoints/pi05_mecharm_trim_corr_lora_v2/1499/assets" ]' +check "記録 lab_pod.json に model・設定・exp・init" '[ "$(jq -r "[.model,.config,.exp,.init] | join(\" \")" "$TD/lab_pod.json")" = "corr3 pi05_mecharm_trim_corr_v5_lora trim_corr_v5 /workspace/ckpt/corr_v2_1499/params" ]' +P3="$TD/train_provenance.json" +check "由来: 入力は corr_v5 と corr2 の 1499 (KIOXIA の原本・指紋・Hugging Face の元)" '[ "$(jq -r ".inputs[0].id" "$P3")" = mecharm_redblock_box_teach_v1_trim2_corr_v5 ] && [ "$(jq -r ".inputs[1] | [.kind,.id,.path,.hf_repo,.pod_path] | join(\" \")" "$P3")" = "checkpoint pi05_mecharm_trim_corr_lora_v2/1499 checkpoints/pi05_mecharm_trim_corr_lora_v2/1499 PixelstoMotors/pi05-mecharm-trim-corr-lora-v2 /workspace/ckpt/corr_v2_1499/params" ] && [ "$(jq -r ".inputs[1].fingerprint" "$P3")" = "$(python3 "$HERE/provenance.py" fingerprint "$T/data/checkpoints/pi05_mecharm_trim_corr_lora_v2/1499")" ]' +check "由来: 設定・出力・チェックポイント側と Hugging Face にも同じもの" '[ "$(jq -r ".config | [.name,.exp_name,.init_params,.data_name] | join(\" \")" "$P3")" = "pi05_mecharm_trim_corr_v5_lora trim_corr_v5 /workspace/ckpt/corr_v2_1499/params mecharm_redblock_box_teach_v1_trim2_corr_v5" ] && [ "$(jq -r ".outputs[0] | [.path,.hf_repo] | join(\" \")" "$P3")" = "checkpoints/pi05_mecharm_trim_corr_lora_v3/1499 PixelstoMotors/pi05-mecharm-trim-corr-lora-v3" ] && cmp -s "$P3" "$CK3/1499/train_provenance.json" && has calls.log "hf upload PixelstoMotors/pi05-mecharm-trim-corr-lora-v3 train_provenance.json"' +rm -rf "$T" +T=$(mktemp -d); mkdir -p "$T/data/lab/LogT/train" "$T/fake" +jq -n '{id:"dryrunpod0001", kind:"train", model:"corr3", config:"pi05_mecharm_trim_corr_v5_lora", gpu:"NVIDIA A40", costPerHr:0.44, created_epoch:1793449178, created_at:"2026-10-31 21:19:38", exp:"trim_corr_v5", train_started_epoch:1793449300}' > "$T/data/lab/LogT/train/lab_pod.json" +echo "NVIDIA A40" > "$T/fake/created" +(cd "$HERE" && LAB_DRY_ROOT="$T" ./lab_train.sh --log LogT --dry-run --stop < /dev/null > "$T/out.txt" 2>&1); RC=$? +TD="$T/data/lab/LogT/train" +check "--stop (--model なし): 記録の model=corr3 の設定・exp でログと一覧を取る" '[ $(n_call DELETE) = 1 ] && [ -f "$TD/train_trim_corr_v5.log" ] && has ssh.log "cd /workspace/openpi/checkpoints/pi05_mecharm_trim_corr_v5_lora/trim_corr_v5" && [ "$(jq -r .config.data_name "$TD/train_provenance.json")" = mecharm_redblock_box_teach_v1_trim2_corr_v5 ]' +rm -rf "$T" + echo "== 13. 見守る途中で止められても Pod を残さない (TERM. Ctrl-C・HUP も同じ扱い)" T=$(mktemp -d) (cd "$HERE" && LAB_DRY_ROOT="$T" LAB_FAKE_SCENARIO=timeout LAB_DRY_POLL_SEC=1 ./lab_train.sh --log LogT --dry-run --limit-hours 1 < /dev/null > "$T/out.txt" 2>&1) &