File size: 10,879 Bytes
c5dae6b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/usr/bin/env bash
# =============================================================================
# ext64k_b5.sh -- YaRN extension 32k -> 64k on b5, deadline-aware.
#
# PHASE 1  3-step probe: does 64k fit at cp=4 on 143 GB, and how fast is a step?
# PHASE 2  train as many steps as fit before HARD_STOP, WSD tail sized so the
#          FINAL checkpoint is DECAYED and comparable to the 32k results
# PHASE 3  eval 4 lengths IN PARALLEL on the 4 GPUs (wall clock = slowest job)
# PHASE 4  upload ckpt + sidecar + logs
#
# WHY b5: documents are 65,536-131,072 tokens, so the MINIMUM equals the 64k
#   window and every training sample is one contiguous document. b4 (32-64k)
#   would straddle in roughly half its samples. Same reasoning that made b4 the
#   right choice at 32k.
#
# PARENT: b4 full-epoch step 2227 -- the best 32k model (70.0/58.0/43.0 at
#   8k/16k/32k). CP_INIT_FROM loads WEIGHTS ONLY, so its cp=2 shard layout is
#   irrelevant to this cp=4 run, and no sidecar is needed (none is read).
#
# YaRN INVARIANT: SCALE * ORIG_MAXPOS must equal seq_len EXACTLY and ORIG_MAXPOS
#   must be the length the parent was actually trained at. 2 * 32768 = 65536.
#
# LR: CP_MAX_LR / CP_MIN_LR DO NOT EXIST -- bluscriptCP.cpp:131-132 hardcodes
#   6e-4 / 6e-5 and the env block never reads them. Real schedule is
#   6e-4 * CP_REWARMUP_PEAK(0.3) = 1.8e-4 peak, 6e-5 floor -- the same values
#   every previous run used, so results stay comparable.
#
# DEADLINE: HARD_STOP is a UTC epoch. Step count is derived from the MEASURED
#   probe rate, not an estimate, so the run lands inside the window.
# =============================================================================
set -uo pipefail
cd "$(dirname "$0")"
ROOT="$(cd ../.. && pwd)"
export LD_LIBRARY_PATH="$ROOT/Tensor-Implementations/lib:$ROOT/Profiler/lib:${LD_LIBRARY_PATH:-}"
export OMPI_ALLOW_RUN_AS_ROOT=1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1

PY=/root/envv/bin/python3
HF=/root/envv/bin/hf
EXE=./build/bluscriptCP_exec
CK=checkpoints_bluscriptcp/rank_0
LOG=ext64k_logs; mkdir -p "$LOG"
M="$LOG/master.log"
REPO=unparallelled/BluScriptCP
say(){ echo "[$(date -u +%H:%M:%S)] $*" | tee -a "$M" >&2; }
die(){ say "FATAL: $*"; exit 1; }

T=65536; NP=4; GPUS=0,1,2,3
ORIG=32768; SCALE=2                  # 2 * 32768 == 65536
DATA=lendata/b5_65536_131072
PARENT="$CK/b4epoch32k_step2227.ckpt"
HAY="$PWD/lendata/haystack/b2val_haystack.bin"
WARM=100; TAIL=${TAIL:-2}; FREQ=50; KEEP=2
GB=524288
# 23:30 IST = 18:00 UTC today
HARD_STOP=${HARD_STOP:-$(date -u -d "$(date -u +%Y-%m-%d) 18:00:00" +%s)}
RESERVE_MIN=${RESERVE_MIN:-50}       # eval (28) + upload (20) + slack

$PY -c "import tiktoken" 2>/dev/null || die "tiktoken missing"
[ -x "$EXE" ]    || die "$EXE not built"
[ -f "$PARENT" ] || die "parent missing: $PARENT"
[ -f "$HAY" ]    || die "haystack missing: $HAY"
[ -d "$DATA" ]   || die "$DATA missing"
[ $((SCALE*ORIG)) -eq $T ] || die "YaRN invariant: $SCALE * $ORIG != $T"
ntr=$(ls "$DATA"/*train*.bin 2>/dev/null | wc -l)
nva=$(ls "$DATA"/*val*.bin 2>/dev/null | wc -l)
[ "$ntr" -ge 1 ] && [ "$nva" -ge 1 ] || die "need train+val shards in $DATA (have $ntr/$nva)"
have=$(( $(du -cb "$DATA"/*train*.bin | tail -1 | cut -f1) / 2 ))

say "=== 32k -> 64k YaRN extension on b5 (4x H200, cp=$NP) ==="
say "parent: b4 full epoch step 2227 (best 32k model)"
say "YaRN SCALE=$SCALE ORIG=$ORIG -> $((SCALE*ORIG)) == CP_T=$T  OK"
say "b5: $ntr train shards = $(echo "scale=3; $have/1000000000" | bc) B tokens available"
say "hard stop $(date -u -d @$HARD_STOP +%H:%M) UTC = $(date -u -d @$((HARD_STOP+19800)) +%H:%M) IST, reserving ${RESERVE_MIN}m"

COMMON="CP_SIZE=$NP CP_ATTN_MODE=ring CP_ATTN_FUSION=split CP_T=$T \
YARN_SCALE=$SCALE YARN_ORIG_MAXPOS=$ORIG \
CP_ZERO=1 CP_ZERO_V2=1 CP_ZERO_SYMMETRIC=1 CP_BF16=1 CP_OPTIMIZER=muon \
CP_WARMUP=$WARM CP_REWARMUP=$WARM CP_REWARMUP_PEAK=0.3"
ARCH="CP_N_EMBD=1536 CP_N_LAYER=36 CP_N_HEAD=12 CP_N_KVHEAD=4 CP_FFN=4096 CP_WEIGHT_TYING=0"

# ---- PHASE 1: fit + speed --------------------------------------------------
if [ ! -f "$LOG/probe.ok" ]; then
  say "PHASE 1: 3-step probe (64k at cp=4 projects to 108.8 GB of 143 GB)"
  env $ARCH $COMMON CP_STABLE=0 CP_CKPT=0 \
      CP_INIT_FROM="$PWD/$PARENT" CP_DATA_ROOT="$PWD/$DATA" \
      CP_B=1 CP_GLOBAL_BATCH=65536 CP_MAX_STEPS=3 \
      CUDA_VISIBLE_DEVICES=$GPUS mpirun --allow-run-as-root -np $NP "$EXE" \
      > "$LOG/probe.log" 2>&1
  if grep -qaiE 'out of memory|bad_alloc' "$LOG/probe.log"; then
    say "PROBE OOM -- 64k does not fit at cp=$NP even on 143 GB cards."
    grep -aoE 'cudaMallocAsync\(size=[0-9]+\) failed' "$LOG/probe.log" | head -2 | sed 's/^/    /' >&2
    exit 1
  fi
  grep -aE '^step +[0-9]+ \|' "$LOG/probe.log" | sed 's/^/  /' >&2
  say "PROBE OK: peak $(grep -aoE 'mem: [0-9]+MB' "$LOG/probe.log" | tail -1)"
  touch "$LOG/probe.ok"
fi

# ---- derive the step count from the MEASURED rate --------------------------
# The probe used a tiny global batch, so its dt is NOT the real per-step cost.
# Scale it: real grad_accum is GB/T vs the probe's 65536/T.
SPS=$($PY - "$LOG/probe.log" $GB $T <<'PYEOF'
import re,sys,statistics
t=open(sys.argv[1],errors='ignore').read()
d=[float(x) for x in re.findall(r'dt: ([0-9.]+)ms', t)]
probe_accum=65536//int(sys.argv[3]) or 1
real_accum=int(sys.argv[2])//int(sys.argv[3])
per=statistics.median(d[1:]) if len(d)>2 else d[-1]
print(f"{per/1000.0*real_accum/probe_accum:.3f}")
PYEOF
)
say "measured step cost at real batch: ${SPS} s/step"
if [ -n "${STEPS_OVERRIDE:-}" ]; then
  say "STEPS_OVERRIDE=$STEPS_OVERRIDE -- the probe ran grad_accum=1 so its dt x8"
  say "  overstated the real step cost 5.8x (74.0 vs a measured 12.85 s/step)."
fi
STEPS=$($PY - "$SPS" "$HARD_STOP" "$RESERVE_MIN" "$have" "$GB" "$WARM" "$TAIL" <<'PYEOF'
import sys,time,math
sps=float(sys.argv[1]); stop=int(sys.argv[2]); res=int(sys.argv[3])
have=int(sys.argv[4]); gb=int(sys.argv[5]); warm=int(sys.argv[6]); tail=int(sys.argv[7])
budget=stop-time.time()-res*60
n=int(budget/sps)
n=min(n, have//gb)                       # never wrap the data
n=max(n, warm+tail+10)                   # schedule must be legal
print(n)
PYEOF
)
STEPS=${STEPS_OVERRIDE:-$STEPS}
STABLE=$(( STEPS - WARM - TAIL ))
[ "$STABLE" -lt 1 ] && STABLE=1
say "PHASE 2: $STEPS steps = $(echo "scale=3; $STEPS*$GB/1000000000" | bc) B tokens = $(echo "scale=0; $STEPS*$GB*100/866000000" | bc)% of a b5 epoch"
say "  WSD: warmup $WARM, stable $STABLE, decay tail $TAIL -> FINAL checkpoint IS decayed"

if [ -f "$LOG/ext.ckpt" ] && [ -f "$(cat "$LOG/ext.ckpt")" ]; then
  say "already trained -> $(cat "$LOG/ext.ckpt")"
else
  env $ARCH $COMMON CP_STABLE=$STABLE \
      CP_CKPT=1 CP_CKPT_FREQ=$FREQ CP_CKPT_KEEP=$KEEP CP_CKPT_NEW_RUN=1 \
      CP_INIT_FROM="$PWD/$PARENT" CP_DATA_ROOT="$PWD/$DATA" \
      CP_B=1 CP_GLOBAL_BATCH=$GB CP_MAX_STEPS=$STEPS \
      CUDA_VISIBLE_DEVICES=$GPUS mpirun --allow-run-as-root -np $NP "$EXE" \
      > "$LOG/ext.log" 2>&1
  grep -qaiE 'out of memory|bad_alloc' "$LOG/ext.log" && die "OOM in the full run"
  RN=$(grep -aoE 'CP_Training_log[0-9]+' "$LOG/ext.log" | head -1 | grep -oE '[0-9]+')
  [ -n "$RN" ] || die "no run number"
  CKF=$(ls -t $CK/blumodelcp_run${RN}_step_*.ckpt 2>/dev/null | head -1)
  [ -n "$CKF" ] || die "run $RN wrote NO checkpoint"
  n=$(ls checkpoints_bluscriptcp/rank_*/"$(basename "$CKF")" 2>/dev/null | wc -l)
  [ "$n" -ge "$NP" ] || die "only $n/$NP rank shards for $(basename "$CKF")"
  echo "$CKF" > "$LOG/ext.ckpt"; echo "$RN" > "$LOG/runnum"
  say "ext64k -> run $RN, $(basename "$CKF"), loss $(grep -aE '^step ' "$LOG/ext.log" | tail -1 | grep -oE 'loss: [0-9.]+')"
  say "  peak mem $(grep -aoE 'mem: [0-9]+MB' "$LOG/ext.log" | tail -1)"
  say "  final lr $(grep -aE '^step ' "$LOG/ext.log" | tail -1 | grep -oE 'lr [0-9.e-]+')  (should be ~6e-05 = decayed)"
fi

# ---- PHASE 3: eval, 4 lengths in PARALLEL on 4 GPUs ------------------------
EXT=$(basename "$(cat "$LOG/ext.ckpt")")
say "PHASE 3: eval ext64k -- 4 lengths, one GPU each"
# 65512 + MAX_NEW 24 = 65536 exactly; 65528 would pad to 65792 and abort.
for LEN in 8192 16360 32744 65512; do
  ( GEN_DATA_ROOT=$DATA HAY="$HAY" PY=$PY OUT=ext64k_len_$LEN TASKS="niah_single" \
    CKPTS="ext64k" N=100 PROMPT_LEN=$LEN MAX_NEW=24 T=$T \
    DEPTHS="0.0,0.25,0.5,0.75,1.0" YARN_ORIG=$ORIG YARN=$SCALE \
    GPUS=$(( (LEN==8192)?0:(LEN==16360)?1:(LEN==32744)?2:3 )) JOBS_PER_GPU=1 \
    BF16=1 GREEDY=1 CKPT_EXTRA="ext64k=$EXT" ./run_longeval.sh \
    >> "$LOG/eval_$LEN.log" 2>&1 ) &
done
wait
for LEN in 8192 16360 32744 65512; do
  [ -s "ext64k_len_$LEN/summary.csv" ] && say "  len $LEN -> $(sed -n 2p ext64k_len_$LEN/summary.csv)" \
                                       || say "  len $LEN -> NO RESULT"
done

# ---- PHASE 4: upload -------------------------------------------------------
say "PHASE 4: upload"
{
  echo "# 32k -> 64k YaRN extension on b5 -- $(date -u +%Y-%m-%d)"
  echo
  echo "Parent: b4 full-epoch step 2227 (best 32k model: 70.0/58.0/43.0 at 8k/16k/32k)."
  echo "Data:   b5_65536_131072 -- min doc 65,536 == the window, so every sample is"
  echo "        ONE contiguous document."
  echo "YaRN:   SCALE=2 ORIG_MAXPOS=32768 -> 65536 exactly."
  echo "Train:  $STEPS steps x $GB = $(echo "scale=3; $STEPS*$GB/1000000000" | bc) B tokens"
  echo "        = $(echo "scale=0; $STEPS*$GB*100/866000000" | bc)% of b5's 0.866 B train split (no wrap)."
  echo "        WSD warmup $WARM / stable $STABLE / decay tail $TAIL -- final ckpt DECAYED."
  echo "        LR peak 1.8e-4, floor 6e-5 (CP_MAX_LR is a no-op; see B4 results doc)."
  echo "        4x H200, cp=4, B=1 x grad_accum $((GB/T))."
  echo "Eval:   niah_single, N=100, greedy, shared haystack b2_8192_16384 val."
  echo
  echo "## Results"; echo
  echo "| context | niah_single |"; echo "|---|---|"
  for LEN in 8192 16360 32744 65512; do
    v=$(sed -n 2p "ext64k_len_$LEN/summary.csv" 2>/dev/null | cut -d, -f2)
    printf "| %s | %s |\n" "$LEN" "${v:-n/a}"
  done
  echo
  echo "For comparison, the 32k parent at the same lengths: 70.0 / 58.0 / 43.0 / n/a"
  echo "(it cannot run at 64k -- its RoPE cache is sized 32,768)."
  echo
  echo "NOTE: this is a PARTIAL b5 epoch, sized to a wall-clock deadline. It is a"
  echo "first 64k data point, not a converged extension."
} > "$LOG/RESULTS.md"
up(){ [ -e "$1" ] || return 0
  $HF upload "$REPO" "$1" "$2" >>"$LOG/upload.log" 2>&1 && say "  ok $2" || say "  FAIL $2"; }
up "$LOG/RESULTS.md" docs/EXT64K_B5_RESULTS_$(date -u +%Y-%m-%d).md
for LEN in 8192 16360 32744 65512; do up "ext64k_len_$LEN" "logs/ext64k_len_$LEN/"; done
up "$LOG" logs/ext64k/
up ext64k_b5.sh scripts/ext64k_b5.sh
RN=$(cat "$LOG/runnum" 2>/dev/null)
for r in 0 1 2 3; do
  for e in ckpt zero_g1; do
    up "checkpoints_bluscriptcp/rank_$r/blumodelcp_run${RN}_step_${STEPS}.$e" \
       "checkpoints/ext64k_b5_rank${r}_step_${STEPS}.$e"
  done
done
say "=== EXT64K DONE ==="