guanghulab/server/training-agent/start-training.sh

106 lines
4.2 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════
# 训练启动脚本占位 · start-training.sh
# ═══════════════════════════════════════════════════════════
# 签发: 铸渊 · ICE-GL-ZY001 · 国作登字-2026-A-00037559
#
# 在 GPU 训练机上执行。本脚本是真实训练器的最小骨架占位,
# 它只做三件事:
# 1. 切阶段为 training往仓库 README 上报「训练已启动」
# 2. 调用 train.py如果存在— 真实的 SFT 由 train.py 实现
# 3. 训练每 N 步在训练侧 print "ZY_PROGRESS step=… loss=…"
# 由 watcher.py 解析后转发给 progress-reporter.sh
#
# 真实 train.py + watcher.py 由后续 PR 落地Qwen2.5-7B + Accelerate + DeepSpeed
# 本脚本提供:
# - 标准的 tmux session 起停约定zy-train
# - .env 加载
# - bootstrap → training → done 状态切换
#
# 用法:
# bash start-training.sh # 前台跑(调试)
# bash start-training.sh --tmux # 后台 tmux 跑(生产)
# bash start-training.sh --stop # 停止训练
# ═══════════════════════════════════════════════════════════
set -uo pipefail
ROOT="${ZY_TRAIN_ROOT:-/opt/guanghu/training}"
ENV_FILE="$ROOT/.env"
SESSION="zy-train"
if [[ ! -f "$ENV_FILE" ]]; then
echo "❌ 找不到 $ENV_FILE,请先跑 setup.sh" >&2
exit 2
fi
# shellcheck disable=SC1090
set -a; source "$ENV_FILE"; set +a
REPORTER="$ROOT/progress-reporter.sh"
# ── --stop ──
if [[ "${1:-}" == "--stop" ]]; then
if tmux has-session -t "$SESSION" 2>/dev/null; then
tmux kill-session -t "$SESSION"
echo "preprocessing" > "$ROOT/.phase"
"$REPORTER" "preprocessing" "训练已停止" "" "Training stopped by operator on $(hostname)"
echo "✅ 训练已停止"
else
echo "⚠️ 没有运行中的 tmux session $SESSION"
fi
exit 0
fi
# ── --tmux ──
if [[ "${1:-}" == "--tmux" ]]; then
if tmux has-session -t "$SESSION" 2>/dev/null; then
echo "⚠️ tmux session $SESSION 已存在 · 先 --stop 再启动"
exit 1
fi
tmux new-session -d -s "$SESSION" "bash $ROOT/start-training.sh 2>&1 | tee -a $ROOT/training.log"
echo "✅ tmux session $SESSION 已启动 · 日志: $ROOT/training.log"
echo " 附加: tmux attach -t $SESSION"
exit 0
fi
# ── 前台执行 ──
echo "training" > "$ROOT/.phase"
"$REPORTER" "training" "训练启动 · 进入主循环" "" "start-training.sh launched on $(hostname)"
# 真实训练入口
TRAIN_PY="$ROOT/train.py"
DATA_DIR="${ZY_TRAIN_DATA:-/data/guanghu}"
SFT_PATH="${ZY_DATA_PATH:-$DATA_DIR/processed/sft.jsonl}"
MODEL_PATH="${ZY_MODEL_DIR:-$DATA_DIR/models/Qwen2.5-7B}"
# 前置校验 — 缺哪样就立刻上报错误并退出
if [[ ! -f "$TRAIN_PY" ]]; then
"$REPORTER" "error" "train.py 缺失" "" "$TRAIN_PY not found — bootstrap 未跑或脚本未同步"
echo "$TRAIN_PY 不存在" >&2
exit 2
fi
if [[ ! -d "$MODEL_PATH" ]]; then
"$REPORTER" "error" "模型缺失" "" "Qwen2.5-7B 未在 $MODEL_PATH — 重跑 bootstrap"
echo "❌ 模型目录不存在: $MODEL_PATH" >&2
exit 3
fi
if [[ ! -f "$SFT_PATH" ]]; then
"$REPORTER" "error" "训练数据缺失" "" "$SFT_PATH not found — preprocess 未跑"
echo "❌ 训练数据不存在: $SFT_PATH" >&2
exit 4
fi
# 自动探测 GPU 数 (fallback 4)
NUM_GPUS=$(nvidia-smi --list-gpus 2>/dev/null | wc -l)
NUM_GPUS=${NUM_GPUS:-4}
[[ "$NUM_GPUS" -lt 1 ]] && NUM_GPUS=1
echo "[start-training] 使用 ${NUM_GPUS} 卡 启动 deepspeed"
"$REPORTER" "training" "DeepSpeed 启动 (${NUM_GPUS}×GPU)" "" "deepspeed --num_gpus=${NUM_GPUS} train.py"
# shellcheck disable=SC1091
source "$ROOT/venv/bin/activate"
cd "$ROOT"
# stdbuf 让 python 输出立即可见,管道到 watcher 解析后转发给 progress-reporter
exec stdbuf -oL -eL deepspeed --num_gpus="${NUM_GPUS}" "$TRAIN_PY" 2>&1 \
| "$ROOT/watch-training-output.sh"