#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT_DIR" PYTHON_BIN="${PYTHON_BIN:-/mnt/s3files/s3-us-west2-default/zoubin/cz/envs/self_forcing/bin/python}" GPU_IDS="${GPU_IDS:-0,1,2,3,4,5,6,7}" WAIT_FOR_GPUS="${WAIT_FOR_GPUS:-1}" GPU_MEMORY_THRESHOLD_MIB="${GPU_MEMORY_THRESHOLD_MIB:-2048}" POLL_SECONDS="${POLL_SECONDS:-30}" RUN_SMOKE_TEST="${RUN_SMOKE_TEST:-1}" START_TRAINING="${START_TRAINING:-0}" DATASET_ROOT="${DATASET_ROOT:-/mnt/local_nvme/zoubin/cz/self_forcing_predictor_v4_1000_seed0}" SMOKE_ROOT="${SMOKE_ROOT:-/mnt/local_nvme/zoubin/cz/self_forcing_predictor_v4_smoke_seed0}" NVME_TRAIN_ROOT="${NVME_TRAIN_ROOT:-/mnt/local_nvme/zoubin/cz/self_forcing_predictor_v4_training_1000_seed0}" RUN_DIR="${RUN_DIR:-$ROOT_DIR/checkpoints/predictor_v4_1000_seed0}" mkdir -p "$RUN_DIR" exec 9>"$RUN_DIR/end_to_end.lock" if ! flock -n 9; then echo "错误:已有 Predictor-v4 end-to-end supervisor 正在运行。" >&2 exit 1 fi echo "$$" >"$RUN_DIR/end_to_end.pid" trap 'rm -f "$RUN_DIR/end_to_end.pid"' EXIT IFS=',' read -r -a GPU_ARRAY <<< "$GPU_IDS" if (( ${#GPU_ARRAY[@]} != 8 )); then echo "错误:正式构建与训练需要 8 张 GPU,当前 GPU_IDS=$GPU_IDS。" >&2 exit 1 fi if [[ "$WAIT_FOR_GPUS" != "0" && "$WAIT_FOR_GPUS" != "1" ]]; then echo "错误:WAIT_FOR_GPUS 必须为 0 或 1。" >&2 exit 1 fi if [[ "$START_TRAINING" != "0" && "$START_TRAINING" != "1" ]]; then echo "错误:START_TRAINING 必须为 0 或 1。" >&2 exit 1 fi gpus_are_free() { local used mapfile -t used < <( nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits ) if (( ${#used[@]} < 8 )); then return 1 fi local gpu_id for gpu_id in "${GPU_ARRAY[@]}"; do if (( used[gpu_id] > GPU_MEMORY_THRESHOLD_MIB )); then return 1 fi done } if [[ "$WAIT_FOR_GPUS" == "1" ]]; then while ! gpus_are_free; do echo "[$(date -u +%FT%TZ)] GPU 尚忙,${POLL_SECONDS}s 后重试。" >&2 sleep "$POLL_SECONDS" done elif ! gpus_are_free; then echo "错误:GPU 显存占用超过 ${GPU_MEMORY_THRESHOLD_MIB} MiB。" >&2 exit 1 fi if [[ "$RUN_SMOKE_TEST" == "1" ]]; then echo "[$(date -u +%FT%TZ)] 开始单 case GPU 冒烟测试。" "$PYTHON_BIN" scripts/prepare_predictor_v4_prompts.py \ --output_root "$SMOKE_ROOT" \ --num_prompts 1 \ --sampling_seed 0 \ --inference_seed 0 CUDA_VISIBLE_DEVICES="${GPU_ARRAY[0]}" \ "$PYTHON_BIN" scripts/build_predictor_v4_dataset.py \ --dataset_root "$SMOKE_ROOT" \ --worker_id 0 \ --num_workers 1 \ --case_ids 0 \ --seed 0 \ --blocks 0 1 28 29 \ --validate_kv_rebuild "$PYTHON_BIN" scripts/merge_predictor_v4_manifests.py \ --dataset_root "$SMOKE_ROOT" \ --num_workers 1 "$PYTHON_BIN" scripts/validate_predictor_v4_dataset.py \ --dataset_root "$SMOKE_ROOT" \ --tensor_records 0 \ --require_kv_metrics 7 echo "[$(date -u +%FT%TZ)] 单 case GPU 冒烟测试通过。" fi echo "[$(date -u +%FT%TZ)] 开始 1000 prompts / 8 GPU 离线数据构建。" GPU_IDS="$GPU_IDS" \ DATASET_ROOT="$DATASET_ROOT" \ PREPARE_PROMPTS=1 \ VALIDATE_KV_REBUILD=0 \ bash scripts/launch_predictor_v4_build.sh if [[ "$START_TRAINING" == "0" ]]; then echo "[$(date -u +%FT%TZ)] 数据构建完成;START_TRAINING=0,不启动训练。" exit 0 fi echo "[$(date -u +%FT%TZ)] 数据构建完成,开始 8 GPU Predictor-v4 训练。" NPROC_PER_NODE=8 \ LOG_DIR="$NVME_TRAIN_ROOT" \ bash scripts/run_predictor_v4_training.sh echo "[$(date -u +%FT%TZ)] 训练完成,开始把 NVMe 产物同步回项目目录。" DATASET_SOURCE="$DATASET_ROOT" \ TRAIN_SOURCE="$NVME_TRAIN_ROOT" \ bash scripts/sync_predictor_v4_artifacts.sh echo "[$(date -u +%FT%TZ)] Predictor-v4 数据构建与训练全部完成。"