Download source/examples/train/nnode/dflash2_infinity_parser2_flash_online_2node.sh from khazic/spec-b300: direct link, hf CLI and curl.
- Browser
- Download file 10.1 kB
-
https://huggingface.co/khazic/spec-b300/resolve/main/source/examples/train/nnode/dflash2_infinity_parser2_flash_online_2node.sh
- Command line
-
hf download hf://khazic/spec-b300/source/examples/train/nnode/dflash2_infinity_parser2_flash_online_2node.sh
-
curl -L -o dflash2_infinity_parser2_flash_online_2node.sh https://huggingface.co/khazic/spec-b300/resolve/main/source/examples/train/nnode/dflash2_infinity_parser2_flash_online_2node.sh
10.1 kB
| # Infinity-Parser2.1-Flash 在线 DFlash2 训练。 | |
| # 平台两个节点各执行一次:每节点前 2 卡推理、后 6 卡训练,共 12 个 DDP rank。 | |
| set -Eeuo pipefail | |
| # ============ 路径与平台分布式配置 ============ | |
| WS="${ROOT:-/inspire/sfs/project/inf-multimodal/public/wumengke}" | |
| REPO="${REPO:-$WS/speculators}" | |
| ENV_REPO="${ENV_REPO:-$WS/speculators}" | |
| MODEL="${MODEL:-/inspire/sfs/project/inf-multimodal/public/data_mllm/publish_models/Infinity-Parser2.1-Flash-2608}" | |
| DATA_ROOT="${DATA_ROOT:-$WS/datasets/infinity_parsers2_v2_1_max32768_vocab32k}" | |
| DATA_DIR="${DATA_DIR:-$DATA_ROOT/dflash_data/full}" | |
| # DFlash2 selector 使用完整的 248320-token 词表;数据目录已改为全词表映射。 | |
| OUTPUT_DIR="${OUTPUT_DIR:-${RUN_DIR:-$WS/model_weights/dflash2_parser2_1_flash_2node}}" | |
| NNODES="${PET_NNODES:?需要 PET_NNODES=2}" | |
| NODE_RANK="${PET_NODE_RANK:?需要 PET_NODE_RANK=0 或 1}" | |
| [[ "$NNODES" == 2 && "${PET_NPROC_PER_NODE:-}" == 8 ]] || { | |
| echo "需要 2 节点、每节点 8 卡(2 推理 + 6 训练)" >&2; exit 1; | |
| } | |
| [[ "$NODE_RANK" == 0 || "$NODE_RANK" == 1 ]] || { | |
| echo "PET_NODE_RANK 必须为 0 或 1" >&2; exit 1; | |
| } | |
| DIST_MASTER_ADDR="${MASTER_ADDR:-${PET_MASTER_ADDR:?需要 MASTER_ADDR 或 PET_MASTER_ADDR}}" | |
| DIST_MASTER_PORT="${MASTER_PORT:-${PET_MASTER_PORT:?需要 MASTER_PORT 或 PET_MASTER_PORT}}" | |
| # 保留平台 NCCL/GLOO 网络设置,与现有两节点配方保持一致。 | |
| export NCCL_CROSS_NIC="${NCCL_CROSS_NIC:-0}" | |
| if [[ -z "${GLOO_SOCKET_IFNAME:-}" && -n "${NCCL_SOCKET_IFNAME:-}" ]]; then | |
| export GLOO_SOCKET_IFNAME="$NCCL_SOCKET_IFNAME" | |
| fi | |
| RUN_NAME="${RUN_NAME:-dflash2-parser2_1-2node}" | |
| SAVE_DIR="${CHECKPOINT_DIR:-$OUTPUT_DIR/$RUN_NAME/checkpoints}" | |
| LOG_DIR="${LOG_DIR:-$OUTPUT_DIR/$RUN_NAME}" | |
| VLLM_LOG="$LOG_DIR/vllm_node${NODE_RANK}.log" | |
| TRAIN_LOG="$LOG_DIR/train_node${NODE_RANK}.log" | |
| IFS=',' read -r -a GPU_LIST <<< "${CUDA_VISIBLE_DEVICES:-0,1,2,3,4,5,6,7}" | |
| [[ ${#GPU_LIST[@]} == 8 ]] || { echo "每节点需要 8 张可见 GPU" >&2; exit 1; } | |
| VLLM_GPUS=$(IFS=,; printf '%s' "${GPU_LIST[*]:0:2}") | |
| TRAIN_GPUS=$(IFS=,; printf '%s' "${GPU_LIST[*]:2:6}") | |
| NUM_TRAIN_GPUS=6 | |
| # DFlash2 的卷积、selector 和 CE/DPACE 配方沿用两节点参考脚本。 | |
| NUM_LAYERS="${NUM_LAYERS:-5}" | |
| BLOCK_SIZE="${BLOCK_SIZE:-16}" | |
| MAX_ANCHORS="${MAX_ANCHORS:-1024}" | |
| DECAY_GAMMA=7 | |
| CONV_KERNEL_SIZE="${CONV_KERNEL_SIZE:-2}" | |
| CONV_GROUP_SIZE="${CONV_GROUP_SIZE:-16}" | |
| SELECTOR_RANK="${SELECTOR_RANK:-256}" | |
| SELECTOR_TOP_K="${SELECTOR_TOP_K:-16}" | |
| SELECTOR_LOSS_ALPHA="${SELECTOR_LOSS_ALPHA:-0.1}" | |
| EPOCHS="${EPOCHS:-3}" | |
| LR="${LR:-1e-4}" | |
| MUON_LR=2e-4 | |
| # Parser2 使用 16K packing、2048 非因果滑窗及自己的辅助层/MRoPE 配置。 | |
| PACK_SEQ_LEN=16384 | |
| TARGET_LAYER_IDS=(2 7 12 17 22) | |
| # 数据加载、HTTP 连接和请求重试使用 speculators 默认值。 | |
| # API 进程数由 launch_vllm.py 按可用 CPU 自动选择。 | |
| VLLM_MM_PROCESSOR_CACHE_GB="${VLLM_MM_PROCESSOR_CACHE_GB:-0}" | |
| MEDIA_ROOT="/inspire/sfs/project/inf-multimodal/public" | |
| VLLM_PORT="${VLLM_PORT:-8200}" | |
| VLLM_ENDPOINT="http://127.0.0.1:${VLLM_PORT}/v1" | |
| SPEC_PYTHON="${SPEC_PYTHON:-$ENV_REPO/speculators_venv/bin/python}" | |
| TORCHRUN="${TORCHRUN:-$ENV_REPO/speculators_venv/bin/torchrun}" | |
| VLLM_PYTHON="${VLLM_PYTHON:-$ENV_REPO/vllm_venv/bin/python}" | |
| LAUNCH_VLLM="${LAUNCH_VLLM:-$REPO/scripts/launch_vllm.py}" | |
| TRAIN_SCRIPT="${TRAIN_SCRIPT:-$REPO/scripts/train.py}" | |
| export PYTHONPATH="$REPO/src:$REPO/hs_connectors/src${PYTHONPATH:+:$PYTHONPATH}" | |
| export PYTHONUNBUFFERED=1 | |
| export NO_PROXY="${NO_PROXY:+$NO_PROXY,}127.0.0.1,localhost" | |
| export no_proxy="${no_proxy:+$no_proxy,}127.0.0.1,localhost" | |
| export HF_ENDPOINT="${HF_ENDPOINT:-https://hf-mirror.com}" | |
| export HF_HOME="${HF_HOME:-$WS/.cache/huggingface}" | |
| export HF_DATASETS_CACHE="${HF_DATASETS_CACHE:-$WS/datasets/.cache}" | |
| export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$WS/.cache}" | |
| export TORCH_HOME="${TORCH_HOME:-$WS/.cache/torch}" | |
| # 清掉 .bashrc 的共享 Triton 路径,由 PyTorch 自动按 GPU 选择 Triton 缓存。 | |
| # 节点之间只隔离缓存根目录;TRITON_HOME 保证直接调用 Triton 时也不写入 $HOME。 | |
| unset TRITON_CACHE_DIR | |
| export TORCHINDUCTOR_CACHE_DIR="${TORCHINDUCTOR_CACHE_DIR:-$WS/.cache/torchinductor}/$RUN_NAME/node${NODE_RANK}" | |
| export TRITON_HOME="$TORCHINDUCTOR_CACHE_DIR" | |
| export VLLM_CACHE_ROOT="${VLLM_CACHE_ROOT:-$WS/.cache/vllm}" | |
| export WANDB_PROJECT="${WANDB_PROJECT:-infinity-parser2-flash}" | |
| export WANDB_MODE="${WANDB_MODE:-online}" | |
| if [[ "$WANDB_MODE" == online && -z "${WANDB_API_KEY:-}" ]]; then | |
| WANDB_KEY_FILE="${WANDB_KEY_FILE:-$WS/.secrets/wandb_key}" | |
| [[ -s "$WANDB_KEY_FILE" ]] || { echo "缺少 W&B key:$WANDB_KEY_FILE" >&2; exit 1; } | |
| export WANDB_API_KEY="$(tr -d '[:space:]' < "$WANDB_KEY_FILE")" | |
| fi | |
| # ============ 准备数据与输出目录 ============ | |
| for path in "$MODEL/config.json" "$DATA_DIR/state.json" "$DATA_DIR/dataset_info.json"; do | |
| [[ -f "$path" ]] || { echo "缺少文件:$path" >&2; exit 1; } | |
| done | |
| mkdir -p "$SAVE_DIR" "$LOG_DIR" | |
| exec 9>"$SAVE_DIR/training.lock.node${NODE_RANK}" | |
| flock -n 9 || { echo "本节点已有任务使用 $SAVE_DIR" >&2; exit 1; } | |
| HS_PATH="$(mktemp -d "/tmp/dflash2_parser2_node${NODE_RANK}.XXXXXX")" | |
| VLLM_PID="" | |
| TRAIN_PID="" | |
| terminate_group() { | |
| local pid="$1" | |
| [[ -n "$pid" ]] || return 0 | |
| kill -TERM -- "-$pid" 2>/dev/null || true | |
| for _ in {1..30}; do | |
| kill -0 -- "-$pid" 2>/dev/null || break | |
| sleep 1 | |
| done | |
| kill -KILL -- "-$pid" 2>/dev/null || true | |
| wait "$pid" 2>/dev/null || true | |
| } | |
| cleanup() { | |
| local status=$? | |
| trap - EXIT INT TERM HUP | |
| terminate_group "$TRAIN_PID" | |
| terminate_group "$VLLM_PID" | |
| rm -r -- "$HS_PATH" # 只删除本次 mktemp 创建的 hidden-state 目录。 | |
| exit "$status" | |
| } | |
| trap cleanup EXIT | |
| trap 'exit 130' INT | |
| trap 'exit 143' TERM HUP | |
| "$SPEC_PYTHON" - "$VLLM_PORT" <<'PY' | |
| import socket | |
| import sys | |
| with socket.socket() as sock: | |
| sock.settimeout(1) | |
| if sock.connect_ex(("127.0.0.1", int(sys.argv[1]))) == 0: | |
| raise SystemExit(f"Port {sys.argv[1]} is already in use") | |
| PY | |
| # ============ 每节点独立的 vLLM 服务(TP=1 / DP=2) ============ | |
| echo "Node $NODE_RANK: vLLM GPUs=$VLLM_GPUS, training GPUs=$TRAIN_GPUS" | |
| echo "Model: $MODEL" | |
| echo "Data: $DATA_DIR" | |
| echo "Draft vocab: full verifier vocabulary (248320 tokens)" | |
| echo "Checkpoints: $SAVE_DIR" | |
| echo "vLLM log: $VLLM_LOG" | |
| echo "Training log: $TRAIN_LOG" | |
| setsid env \ | |
| -u RANK \ | |
| -u WORLD_SIZE \ | |
| -u LOCAL_RANK \ | |
| -u LOCAL_WORLD_SIZE \ | |
| -u MASTER_ADDR \ | |
| -u MASTER_PORT \ | |
| CUDA_VISIBLE_DEVICES="$VLLM_GPUS" \ | |
| "$VLLM_PYTHON" "$LAUNCH_VLLM" "$MODEL" \ | |
| --target-layer-ids "${TARGET_LAYER_IDS[@]}" \ | |
| --hidden-states-backend file \ | |
| --hidden-states-path "$HS_PATH" \ | |
| -- \ | |
| --tensor-parallel-size 1 \ | |
| --data-parallel-size 2 \ | |
| --data-parallel-backend mp \ | |
| --nnodes 1 \ | |
| --node-rank 0 \ | |
| --master-addr 127.0.0.1 \ | |
| --data-parallel-address 127.0.0.1 \ | |
| --gpu-memory-utilization 0.9 \ | |
| --max-model-len 65536 \ | |
| --mm-processor-cache-gb "$VLLM_MM_PROCESSOR_CACHE_GB" \ | |
| --served-model-name "$MODEL" \ | |
| --allowed-local-media-path "$MEDIA_ROOT" \ | |
| --limit-mm-per-prompt '{"image":16}' \ | |
| --host 127.0.0.1 \ | |
| --port "$VLLM_PORT" \ | |
| >>"$VLLM_LOG" 2>&1 & | |
| VLLM_PID=$! | |
| echo "Waiting for local vLLM..." | |
| deadline=$((SECONDS + 1800)) | |
| until curl \ | |
| --noproxy '*' \ | |
| -fsS \ | |
| --connect-timeout 2 \ | |
| --max-time 5 \ | |
| "http://127.0.0.1:${VLLM_PORT}/health" >/dev/null 2>&1; do | |
| if ! kill -0 "$VLLM_PID" 2>/dev/null; then | |
| tail -n 100 "$VLLM_LOG" >&2 | |
| echo "本机 vLLM 在就绪前退出" >&2 | |
| exit 1 | |
| fi | |
| if (( SECONDS >= deadline )); then | |
| echo "等待 vLLM 超过 1800 秒,见 $VLLM_LOG" >&2 | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| # ============ 两节点 DDP 训练(global world size = 12) ============ | |
| setsid env \ | |
| -u RANK \ | |
| -u WORLD_SIZE \ | |
| -u LOCAL_RANK \ | |
| -u LOCAL_WORLD_SIZE \ | |
| CUDA_VISIBLE_DEVICES="$TRAIN_GPUS" \ | |
| "$TORCHRUN" \ | |
| --nnodes "$NNODES" \ | |
| --node_rank "$NODE_RANK" \ | |
| --nproc_per_node "$NUM_TRAIN_GPUS" \ | |
| --master_addr "$DIST_MASTER_ADDR" \ | |
| --master_port "$DIST_MASTER_PORT" \ | |
| --rdzv_backend static \ | |
| --rdzv_conf timeout=3600 \ | |
| "$TRAIN_SCRIPT" \ | |
| --verifier-name-or-path "$MODEL" \ | |
| --data-path "$DATA_DIR" \ | |
| --save-path "$SAVE_DIR" \ | |
| --speculator-type dflash2 \ | |
| --draft-arch qwen3 \ | |
| --draft-hidden-act silu \ | |
| --num-layers "$NUM_LAYERS" \ | |
| --mask-token-id 248077 \ | |
| --block-size "$BLOCK_SIZE" \ | |
| --max-anchors "$MAX_ANCHORS" \ | |
| --target-layer-ids "${TARGET_LAYER_IDS[@]}" \ | |
| --draft-mrope-full-head-hack \ | |
| --sliding-window 2048 \ | |
| --sliding-window-non-causal \ | |
| --draft-attn-impl simple_flex_attention \ | |
| --loss-fn ce \ | |
| --per-position-loss-weight dpace \ | |
| --dflash-decay-gamma "$DECAY_GAMMA" \ | |
| --conv-kernel-size "$CONV_KERNEL_SIZE" \ | |
| --conv-group-size "$CONV_GROUP_SIZE" \ | |
| --selector-rank "$SELECTOR_RANK" \ | |
| --selector-top-k "$SELECTOR_TOP_K" \ | |
| --selector-loss-alpha "$SELECTOR_LOSS_ALPHA" \ | |
| --optimizer muon \ | |
| --muon-lr "$MUON_LR" \ | |
| --lr "$LR" \ | |
| --scheduler-type cosine \ | |
| --scheduler-warmup-ratio 0.01 \ | |
| --epochs "$EPOCHS" \ | |
| --checkpoint-freq 0.1 \ | |
| --total-seq-len "$PACK_SEQ_LEN" \ | |
| --train-data-ratio 0.99 \ | |
| --noise-std 0 \ | |
| --hidden-states-dtype bfloat16 \ | |
| --hidden-states-backend file \ | |
| --hidden-states-path "$HS_PATH" \ | |
| --vllm-endpoint "$VLLM_ENDPOINT" \ | |
| --on-missing generate \ | |
| --on-generate delete \ | |
| --seed 42 \ | |
| --logger wandb \ | |
| --log-dir "$LOG_DIR" \ | |
| --run-name "$RUN_NAME" \ | |
| >>"$TRAIN_LOG" 2>&1 & | |
| TRAIN_PID=$! | |
| status=0 | |
| wait -n -p finished_pid "$TRAIN_PID" "$VLLM_PID" || status=$? | |
| if [[ "$finished_pid" == "$VLLM_PID" ]]; then | |
| tail -n 100 "$VLLM_LOG" >&2 | |
| echo "训练期间本机 vLLM 退出" >&2 | |
| exit 1 | |
| fi | |
| if (( status != 0 )); then | |
| tail -n 100 "$TRAIN_LOG" >&2 | |
| exit "$status" | |
| fi | |
| echo "Done. Checkpoints saved to $SAVE_DIR" | |