EVIE-4.5B / code /compress /run.sh
xiaoxiaoshadiao's picture
EVIE-4.5B: Prefix-MRL weights, ARD training, eval, HAC
6e8abde verified
Raw History Blame Contribute Delete
7.15 kB
#!/usr/bin/env bash
# HAC on EVIE-4.5B: shipped SKU is d64 × K32 (HEAD_DIM / BUDGET in common.py).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$SCRIPT_DIR/../.." && pwd)"
EVIE_ROOT="${EVIE_ROOT:-$REPO}"
# shellcheck source=/dev/null
source "$REPO/code/shared/lib.sh"
evie_resolve_python
evie_pythonpath
evie_workdirs
PY="$PYTHON"
export PATH="$(dirname "$PY"):$PATH"
unset PYTHONHOME
export PYTHONPATH="$SCRIPT_DIR:$PYTHONPATH"
export TOKENIZERS_PARALLELISM=false
export HF_HUB_OFFLINE="${HF_HUB_OFFLINE:-0}"
export PYTORCH_CUDA_ALLOC_CONF="${PYTORCH_CUDA_ALLOC_CONF:-expandable_segments:True}"
export OMP_NUM_THREADS="${OMP_NUM_THREADS:-8}"
export NCCL_IB_DISABLE=1
export EVAL_DDP_TIMEOUT_S="${EVAL_DDP_TIMEOUT_S:-21600}"
export EVAL_FINALIZE_TIMEOUT_S="${EVAL_FINALIZE_TIMEOUT_S:-21600}"
export TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC="${TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC:-480}"
export TORCH_NCCL_ENABLE_MONITORING="${TORCH_NCCL_ENABLE_MONITORING:-1}"
MODEL_DIR="${MODEL_DIR:-${EVIE_4_5B_DIR:-}}"
[[ -n "$MODEL_DIR" && -f "$MODEL_DIR/model.safetensors" ]] || {
echo "[fatal] set MODEL_DIR or EVIE_4_5B_DIR to an EVIE-4.5B checkpoint"; exit 2
}
read -r HEAD_DIM BUDGET WEIGHT < <("$PY" -c "from common import HEAD_DIM, BUDGET, WEIGHT; print(HEAD_DIM, BUDGET, WEIGHT)")
RUN_NAME="${RUN_NAME:-evie-compress}"
DATASETS="${DATASETS:-}"
MAX_DOCS="${MAX_DOCS:-0}"
MAX_QUERIES="${MAX_QUERIES:-0}"
EXPECTED_TASKS="${EXPECTED_TASKS:-138}"
RUN_DIR="${RUN_DIR:-$RUNS_DIR/$RUN_NAME}"
evie_forbid_venv_path "$RUN_DIR" "RUN_DIR"
DUMP_DIR="$RUN_DIR/dump"
CLUSTER_DIR="$RUN_DIR/cluster"
EVAL_DIR="$RUN_DIR/eval"
EVAL_BATCH="${EVAL_BATCH:-8}"
EVAL_WORKERS="${EVAL_WORKERS:-8}"
CLUSTER_WORKERS="${CLUSTER_WORKERS:-128}"
SKIP_DUMP="${SKIP_DUMP:-0}"
SKIP_RAW="${SKIP_RAW:-0}"
SKIP_CLUSTER="${SKIP_CLUSTER:-0}"
SKIP_EVAL="${SKIP_EVAL:-0}"
NNODES="${NNODES:-1}"
NODE_RANK="${NODE_RANK:-${RANK:-0}}"
MASTER_ADDR="${MASTER_ADDR:-127.0.0.1}"
MASTER_PORT="${MASTER_PORT:-29711}"
NPROC_PER_NODE="${NPROC_PER_NODE:-$("$PY" -c 'import torch; print(torch.cuda.device_count())')}"
mkdir -p "$LOG_DIR" "$RUN_DIR"
LOG_NODE="${NODE_RANK}"
LOG_FILE="${LOG_FILE:-$LOG_DIR/${RUN_NAME}_node${LOG_NODE}_$(date +%Y%m%d_%H%M%S).log}"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "[log] $LOG_FILE"
echo "[compress] run=$RUN_NAME soup=$(basename "$MODEL_DIR") d=$HEAD_DIM k=$BUDGET w=$WEIGHT"
echo "[compress] topology=${NNODES}x${NPROC_PER_NODE} dump=$DUMP_DIR"
cd "$SCRIPT_DIR"
run_ddp() {
local script="$1"; shift
local port="$1"; shift
echo "[ddp] $script port=$port $*"
"$PY" -m torch.distributed.run \
--nnodes="$NNODES" \
--nproc_per_node="$NPROC_PER_NODE" \
--node_rank="$NODE_RANK" \
--master_addr="$MASTER_ADDR" \
--master_port="$port" \
"$script" "$@"
}
dump_args=(
--eval-root "$EVAL_ROOT"
--dump-dir "$DUMP_DIR"
--embed-batch "$EVAL_BATCH"
--num-workers "$EVAL_WORKERS"
--max-queries "$MAX_QUERIES"
--max-docs "$MAX_DOCS"
)
[[ -n "$DATASETS" ]] && dump_args+=(--datasets "$DATASETS")
if [[ "$SKIP_DUMP" != "1" ]]; then
run_ddp dump.py "$MASTER_PORT" "${dump_args[@]}"
"$PY" - "$DUMP_DIR/DONE.json" "$EXPECTED_TASKS" "$HEAD_DIM" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
want = int(sys.argv[2])
head = int(sys.argv[3])
print("[dump] DONE", d.get("status"), d.get("completed_tasks"), "/", d.get("expected_tasks"), "unique_corpora", d.get("unique_corpora"))
if d.get("status") != "complete" or int(d.get("completed_tasks") or 0) != int(d.get("expected_tasks") or -1):
sys.exit(2)
if int(d.get("expected_tasks") or 0) != want:
print("[fatal] expected_tasks mismatch", d.get("expected_tasks"), "want", want, file=sys.stderr)
sys.exit(2)
if int(d.get("head_dim") or 0) != head:
print("[fatal] dump head_dim", d.get("head_dim"), "want", head, file=sys.stderr)
sys.exit(2)
PY
else
echo "[compress] SKIP_DUMP=1"
fi
CLUSTER_PID=""
cluster_cleanup() {
if [[ -n "${CLUSTER_PID:-}" ]] && kill -0 "$CLUSTER_PID" 2>/dev/null; then
echo "[compress] stopping background cluster pid=$CLUSTER_PID"
kill "$CLUSTER_PID" 2>/dev/null || true
wait "$CLUSTER_PID" 2>/dev/null || true
fi
}
trap cluster_cleanup EXIT
n_dump_corpora="$("$PY" -c "from pathlib import Path; print(len(list(Path(r'$DUMP_DIR').joinpath('docs').glob('*.pt'))))")"
WTAG="$("$PY" -c "from common import w_tag; print(w_tag())")"
if [[ "$SKIP_CLUSTER" != "1" ]]; then
echo "[compress] cluster K=$BUDGET workers=$CLUSTER_WORKERS"
"$PY" cluster.py --dump-dir "$DUMP_DIR" --cluster-root "$CLUSTER_DIR" --workers "$CLUSTER_WORKERS" &
CLUSTER_PID=$!
else
echo "[compress] SKIP_CLUSTER=1"
fi
if [[ "$SKIP_RAW" != "1" ]]; then
run_ddp eval_index.py "$((MASTER_PORT + 1))" \
--dump-dir "$DUMP_DIR" \
--output-dir "$EVAL_DIR/raw" \
--mode raw \
--run-name "$RUN_NAME" \
--resume
else
echo "[compress] SKIP_RAW=1"
fi
eval_summary_complete() {
"$PY" - "$1" <<'PY'
import json, sys
from pathlib import Path
p = Path(sys.argv[1])
if not p.is_file():
sys.exit(1)
d = json.load(p.open())
if d.get("status") == "complete" and int(d.get("completed_tasks") or 0) == int(d.get("expected_tasks") or -1) and d.get("expected_tasks"):
sys.exit(0)
sys.exit(1)
PY
}
if [[ "$SKIP_EVAL" != "1" ]]; then
if [[ "$SKIP_CLUSTER" != "1" ]]; then
done="$CLUSTER_DIR/$WTAG/DONE.json"
echo "[compress] waiting for $done"
while [[ ! -f "$done" ]]; do
if [[ -n "${CLUSTER_PID:-}" ]] && ! kill -0 "$CLUSTER_PID" 2>/dev/null; then
rc=0
wait "$CLUSTER_PID" || rc=$?
CLUSTER_PID=""
if [[ ! -f "$done" ]]; then
echo "[fatal] cluster exited rc=$rc before $done" >&2
exit 2
fi
break
fi
if [[ -z "${CLUSTER_PID:-}" && ! -f "$done" ]]; then
echo "[fatal] no cluster process and missing $done" >&2
exit 2
fi
sleep 5
done
if [[ -n "${CLUSTER_PID:-}" ]]; then
wait "$CLUSTER_PID"
CLUSTER_PID=""
fi
"$PY" - "$done" "$n_dump_corpora" <<'PY'
import json, sys
d = json.load(open(sys.argv[1]))
want, got = int(sys.argv[2]), int(d.get("n_corpora") or 0)
if got != want:
print(f"[fatal] {sys.argv[1]} n_corpora={got} want={want}", file=sys.stderr)
sys.exit(2)
print(f"[compress] cluster ready n_corpora={got}", flush=True)
PY
fi
if eval_summary_complete "$EVAL_DIR/k${BUDGET}/summary.json"; then
echo "[compress] skip eval already complete"
else
echo "[compress] eval independent K=$BUDGET w=$WEIGHT"
run_ddp eval_index.py "$((MASTER_PORT + 2))" \
--dump-dir "$DUMP_DIR" \
--cluster-root "$CLUSTER_DIR" \
--output-dir "$EVAL_DIR/k${BUDGET}" \
--mode k \
--w "$WEIGHT" \
--budget "$BUDGET" \
--run-name "$RUN_NAME" \
--resume
fi
else
echo "[compress] SKIP_EVAL=1"
if [[ -n "${CLUSTER_PID:-}" ]]; then
wait "$CLUSTER_PID"
CLUSTER_PID=""
fi
fi
if [[ -n "${CLUSTER_PID:-}" ]]; then
wait "$CLUSTER_PID"
CLUSTER_PID=""
fi
trap - EXIT
"$PY" ladder.py --eval-root "$EVAL_DIR"
echo "== compress done: $EVAL_DIR/ladder.json =="
echo "[log] $LOG_FILE"