File size: 7,520 Bytes
3b599d6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | #!/bin/bash
#SBATCH --partition=songmei
#SBATCH --nodelist=feanor
#SBATCH --gres=gpu:1
#SBATCH --cpus-per-task=8
#SBATCH --mem=64G
#SBATCH --time=48:00:00
#SBATCH --job-name=w12_s2up
#SBATCH --output=/scratch/users/gatmiry/llm-reasoning-logic-puzzles/sudoku-code/wavecurriculum_run/logs/slurm_%x_%j.out
#SBATCH --error=/scratch/users/gatmiry/llm-reasoning-logic-puzzles/sudoku-code/wavecurriculum_run/logs/slurm_%x_%j.err
# Multi-stage continuation. Starts from the stage-1 run's checkpoint and walks
# stage 2, 3, 4, ... Each stage keeps the SAME sampling structure as stage 1:
# every (puzzle, instance) pair of that stage is enumerated and walked 5 times,
# one instance of a given puzzle per batch. On promotion the pair list is
# rebuilt for the new stage, since each stage has its own instances.
#
# A stage is only left when all three hold:
# 1. every one of its (puzzle, instance) pairs has been seen 5 times
# 2. mass* >= SUDOKU_PROMOTE_ACC (support inside the candidate set)
# 3. spread* >= SUDOKU_PROMOTE_SPREAD (uniform over the candidate set)
# with SUDOKU_MAX_STAGE_STEPS as a cap so an unreachable gate cannot stall the
# whole run.
#
# Runs on a SECOND GPU. It must never touch the stage-1 job's files: no
# rm -rf of /tmp/sudoku_wave_runs, and the stage-1 checkpoint is copied out
# before being restored.
set -u
hostname
nvidia-smi -L
echo "[$(date)] w12_s2plus"
SCRATCH_ROOT=/scratch/users/gatmiry/llm-reasoning-logic-puzzles
RUN_DIR=${SCRATCH_ROOT}/sudoku-code/wavecurriculum_run
ENV_LOCAL=/tmp/logicpuzzles
CAND_DIR=/tmp/sudoku_s12
INST_DIR=/tmp/sudoku_superposition
STAGE1_DIR=/tmp/sudoku_wave_runs/w12_s1_super # the running job -- READ ONLY
LOCAL_LOG=/tmp/sudoku_wave_runs/w12_s2plus
SEED_CKPT=/tmp/sudoku_wave_runs/w12_s2plus_seed
LOGIN_STAGE=gandalf.berkeley.edu:/tmp/sudoku_hf_s2plus
mkdir -p "${RUN_DIR}/logs" "${LOCAL_LOG}" "${SEED_CKPT}"
echo "[$(date)] /tmp:"
df -h /tmp | tail -1
SCP_OPTS="-o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"
[ -f "${HOME}/.ssh/id_ed25519_berkeley" ] && SCP_OPTS="${SCP_OPTS} -i ${HOME}/.ssh/id_ed25519_berkeley"
if ${ENV_LOCAL}/bin/python -u -c "import jax; assert jax.default_backend()=='gpu' or 'cuda' in str(jax.devices()[0]).lower()" 2>/dev/null; then
echo "[$(date)] reusing ${ENV_LOCAL}"
else
echo "ERROR: ${ENV_LOCAL} missing; the stage-1 job should have created it" >&2
exit 1
fi
export PY=${ENV_LOCAL}/bin/python
export LD_LIBRARY_PATH=\
${ENV_LOCAL}/lib/python3.9/site-packages/nvidia/cudnn/lib:\
${ENV_LOCAL}/lib/python3.9/site-packages/nvidia/cublas/lib:\
${ENV_LOCAL}/lib/python3.9/site-packages/nvidia/cuda_runtime/lib:\
${ENV_LOCAL}/lib/python3.9/site-packages/nvidia/cuda_nvrtc/lib:\
${ENV_LOCAL}/lib/python3.9/site-packages/nvidia/nccl/lib:\
${LD_LIBRARY_PATH:-}
${PY} -u -c "import jax; print(jax.__version__, jax.devices(), jax.default_backend())"
for f in train_assignments.npy train_starts.npy train_counts.npy \
test_assignments.npy test_starts.npy test_counts.npy; do
[ -s "${INST_DIR}/${f}" ] || { echo "missing ${INST_DIR}/${f}" >&2; exit 1; }
done
for f in train_cand_masks.npy test_cand_masks.npy; do
[ -s "${CAND_DIR}/${f}" ] || { echo "missing ${CAND_DIR}/${f}" >&2; exit 1; }
done
# ---- Copy the stage-1 checkpoint out before restoring ----
# The stage-1 job rolls its checkpoints (keep=2) while running, so restore from
# a private copy rather than reading a directory that is being rewritten.
latest=$(ls -d ${STAGE1_DIR}/checkpoint_* 2>/dev/null | sort -t_ -k2 -n | tail -1)
if [ -z "${latest}" ]; then
echo "ERROR: no checkpoint found in ${STAGE1_DIR}" >&2
ls -la "${STAGE1_DIR}" >&2 || true
exit 1
fi
echo "[$(date)] seeding from ${latest}"
cp -r "${latest}" "${SEED_CKPT}/" 2>/dev/null || true
ls -la "${SEED_CKPT}"
# ---- Stage 2 onward, same instance schedule as stage 1 ----
# ckpt_loc is a CLI flag, not an env var; SUDOKU_RESUME only turns restore on.
export SUDOKU_RESUME=1
export SUDOKU_START_STAGE=2
export SUDOKU_MAX_STAGE=12
export SUDOKU_LATENT_SLOTS=12
export SUDOKU_RECURRENT=1
export SUDOKU_BACKTRACK=0
export SUDOKU_CAND_SLOT_MODE=depth
export SUDOKU_PASSES_PER_STAGE=1
export SUDOKU_AUX_WEIGHT=0.0
export SUDOKU_LEVEL_BALANCED=0
export SUDOKU_DATA_CURRICULUM=none
# Same structure as stage 1: every (puzzle, instance) pair of the CURRENT stage
# seen 5 times. 200k puzzles keeps one stage near 2 h so several stages land
# overnight; stage 2 has ~5.87 instances/puzzle = 1.17M pairs = 92k steps.
export SUDOKU_INSTANCE_EPOCHS=5
export SUDOKU_INSTANCE_PUZZLES="${SUDOKU_INSTANCE_PUZZLES:-200000}"
# Quality gates, both required on top of the 5-pass data gate.
export SUDOKU_PROMOTE_ACC=0.85
export SUDOKU_PROMOTE_SPREAD=0.85
export SUDOKU_PROMOTE_LOC_WAVE=0.0
export SUDOKU_PLATEAU_STEPS=0
export SUDOKU_PATIENCE=0
export SUDOKU_MIN_STAGE_STEPS=8000
# Cap per stage: above the ~92k steps that 5 passes need at stage 2, so the
# data gate always gets to finish, but bounded so one stage cannot eat the run.
export SUDOKU_MAX_STAGE_STEPS="${SUDOKU_MAX_STAGE_STEPS:-130000}"
# Resume starts the loop at the restored step (~250k+), so leave plenty of room.
export SUDOKU_MAX_STEPS="${SUDOKU_MAX_STEPS:-1400000}"
export SUDOKU_EVAL_EVERY=2000
export SUDOKU_SAVE_EVERY=10000
export SUDOKU_CKPT_KEEP=2
export SUDOKU_LR=0.0002
export SUDOKU_DROPOUT=0.2
export SUDOKU_WD=0.005
export SUDOKU_TRAIN_PATH="${SCRATCH_ROOT}/sudoku-code/datasets/train_sudoku_puzzles.npy"
export SUDOKU_TEST_PATH="${SCRATCH_ROOT}/sudoku-code/datasets/test_sudoku_puzzles.npy"
export SUDOKU_TRAIN_CAND="${CAND_DIR}/train_cand_masks.npy"
export SUDOKU_TEST_CAND="${CAND_DIR}/test_cand_masks.npy"
export SUDOKU_INSTANCE_DIR="${INST_DIR}"
# Two jobs share the node's GPUs, so take a smaller slice of this one.
export XLA_PYTHON_CLIENT_MEM_FRACTION=0.80
HF_TOKEN_FILE="${HF_TOKEN_FILE:-/scratch/users/gatmiry/.hf_token}"
if [ -z "${HF_TOKEN:-}" ] && [ -s "${HF_TOKEN_FILE}" ]; then
HF_TOKEN="$(cat "${HF_TOKEN_FILE}")"
export HF_TOKEN
fi
export HUGGING_FACE_HUB_TOKEN="${HF_TOKEN:-}"
HF_PKGS="${HF_PKGS:-/scratch/users/gatmiry/hf_pkgs}"
TRAIN_LOG="${RUN_DIR}/logs/w12_s2plus.log"
SYNC_LOG="${RUN_DIR}/logs/hf_sync_w12_s2plus.log"
cd "${RUN_DIR}"
PYTHONPATH="${HF_PKGS}${PYTHONPATH:+:${PYTHONPATH}}" ${PY} -u "${RUN_DIR}/hf_sync.py" \
--workdir "${LOCAL_LOG}" \
--log "${TRAIN_LOG}" \
--scratch-log "${TRAIN_LOG}" \
--repo Avra98/Sudoku_superposition \
--prefix runs/w12_s2plus \
--login-stage "${LOGIN_STAGE}" \
--token-file "${HF_TOKEN_FILE}" \
--interval 60 \
> "${SYNC_LOG}" 2>&1 &
SYNC_PID=$!
echo "[$(date)] starting w12_s2plus"
echo " resume from ${SEED_CKPT}, curriculum starts at stage 2"
echo " ${SUDOKU_INSTANCE_PUZZLES} puzzles, every instance of each stage seen 5x"
echo " gates: mass*>=${SUDOKU_PROMOTE_ACC} spread*>=${SUDOKU_PROMOTE_SPREAD}"
echo " hf=Avra98/Sudoku_superposition/runs/w12_s2plus"
CUDA_VISIBLE_DEVICES=0 ${PY} -u -m train.main \
--workdir="${LOCAL_LOG}" --exp_name="w12_s2plus" \
--ckpt_loc="${SEED_CKPT}" \
> "${TRAIN_LOG}" 2>&1
EC=$?
kill ${SYNC_PID} 2>/dev/null || true
wait ${SYNC_PID} 2>/dev/null || true
PYTHONPATH="${HF_PKGS}${PYTHONPATH:+:${PYTHONPATH}}" ${PY} -u "${RUN_DIR}/hf_sync.py" --once \
--workdir "${LOCAL_LOG}" \
--log "${TRAIN_LOG}" \
--scratch-log "${TRAIN_LOG}" \
--repo Avra98/Sudoku_superposition \
--prefix runs/w12_s2plus \
--login-stage "${LOGIN_STAGE}" \
--token-file "${HF_TOKEN_FILE}" \
>> "${SYNC_LOG}" 2>&1 || true
echo "[$(date)] w12_s2plus exit ${EC}"
exit ${EC}
|