File size: 8,526 Bytes
76469ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env bash
# =============================================================================
# lenbucket_experiment.sh -- does TRAINING DOCUMENT LENGTH change 16k retrieval?
#
# THE QUESTION
#   The 2026-09-03 result left retrieval at 27% at the full 16,384 window. One
#   standing hypothesis for the ceiling is the training corpus: flux documents
#   have median 826 tokens, p90 2,721, and only 0.27% reach 16k -- so almost no
#   training example ever required attending across the window. This tests it by
#   holding everything else fixed and changing only document length.
#
# THREE ARMS, one variable
#   armA_c  flux plain text     median 826, p90 2,721 tok   ALREADY TRAINED (run 28)
#   L1      b1_4096_8192        docs in [4096, 8192)        trained here
#   L2      b2_8192_16384       docs in [8192, 16384)       trained here
#   All three: 400 steps, global batch 524,288, from run7' (run 6 step 750),
#   YARN_ORIG_MAXPOS=4096 matched, Muon+ZeRO-1, bf16. Only the data differs.
#
# WHY armA_c IS RE-EVALUATED HERE rather than reusing its published numbers:
#   those were measured with the flux val shard as NIAH filler, and flux is not
#   on this box (nor in the HF model repo). A different haystack is a different
#   test, so all three arms are re-scored against ONE haystack instead.
#
# HAYSTACK CHOICE: b3_16384_32768 val shard -- documents of 16-32k tokens, held
#   out from every arm above. b1's or b2's own val shard would be in-distribution
#   for exactly one arm and would flatter it.
#
# MEMORY: the H200 runs used CP_B=4 and 108 GB/GPU. These are 80 GB H100s, so
#   CP_B=2 with grad_accum 16 holds the global batch at 524,288 while roughly
#   halving activation memory. If step 0 OOMs, the run retries at CP_B=1/accum 32
#   -- same global batch, same optimizer trajectory, just slower.
# =============================================================================
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=${PY:-/root/Adhi/BluTrain/envv/bin/python}
EXE=./build/bluscriptCP_exec
CK=checkpoints_bluscriptcp/rank_0
LOG=lenbucket_logs; mkdir -p "$LOG"
M="$LOG/master.log"

# stderr, never stdout: train_one()'s stdout is its return value.
say(){ echo "[$(date -u +%H:%M:%S)] $*" | tee -a "$M" >&2; }
die(){ say "FATAL: $*"; exit 1; }

T=16384; NP=4; GPUS=0,1,2,3; ORIG=4096
ARCH="CP_N_EMBD=1536 CP_N_LAYER=36 CP_N_HEAD=12 CP_N_KVHEAD=4 CP_FFN=4096 CP_WEIGHT_TYING=0"
COMMON="CP_SIZE=$NP CP_ATTN_MODE=ring CP_ATTN_FUSION=split CP_T=$T \
YARN_SCALE=4 YARN_ORIG_MAXPOS=$ORIG \
CP_ZERO=1 CP_ZERO_V2=1 CP_ZERO_SYMMETRIC=1 CP_BF16=1 CP_OPTIMIZER=muon \
CP_MAX_LR=1e-3 CP_MIN_LR=1e-4 CP_WARMUP=1 \
CP_CKPT=1 CP_CKPT_KEEP=1 CP_CKPT_NEW_RUN=1"

PARENT="$CK/blumodelcp_run6_step_750.ckpt"      # run7'
HAY_ABS="$PWD/lendata/haystack/b3val_haystack.bin"
LENS="1024 2048 4096 8192 16360"
N=${N:-100}
TASKS="niah_single val_backward"

[ -x "$EXE" ]     || die "$EXE not built"
[ -f "$PARENT" ]  || die "parent run7' missing: $PARENT"
[ -f "$HAY_ABS" ] || die "haystack missing: $HAY_ABS"

say "=== length-bucket experiment ==="
say "free disk $(df -BG --output=avail /root | tail -1 | tr -dc '0-9')G"

# ---------------------------------------------------------------------------
train_one(){            # $1 = arm label (l1/l2)   $2 = data dir
  local A="$1"
  local DD="$2"
  local lf="$LOG/${A}.log"
  if [ -f "$LOG/${A}.ckpt" ] && [ -f "$(cat "$LOG/${A}.ckpt")" ]; then
    say "$A already trained -> $(cat "$LOG/${A}.ckpt")"; return 0
  fi
  [ -d "$DD" ] || { say "$A: data dir $DD missing -- SKIP"; return 1; }
  local ntr; ntr=$(ls "$DD"/*train*.bin 2>/dev/null | wc -l)
  local nva; nva=$(ls "$DD"/*val*.bin   2>/dev/null | wc -l)
  say "$A: $ntr train shards, $nva val shards in $DD"
  [ "$ntr" -ge 1 ] && [ "$nva" -ge 1 ] || { say "$A: need >=1 train and >=1 val shard"; return 1; }

  # CP_B x grad_accum must hold global batch at 524,288 to match armA_c exactly.
  local B ACC
  for cfg in "2 16" "1 32"; do
    B=${cfg% *}; ACC=${cfg#* }
    say "$A: attempting CP_B=$B (grad_accum=$ACC, global 524288)"
    env $ARCH $COMMON CP_INIT_FROM="$PWD/$PARENT" CP_DATA_ROOT="$PWD/$DD" \
        CP_B=$B CP_GLOBAL_BATCH=524288 CP_MAX_STEPS=400 \
        CP_REWARMUP=100 CP_REWARMUP_PEAK=0.3 CP_CKPT_FREQ=200 \
        CUDA_VISIBLE_DEVICES=$GPUS mpirun --allow-run-as-root -np $NP "$EXE" \
        > "$lf" 2>&1
    if grep -qaiE 'out of memory|CUDA error: out of memory|bad_alloc' "$lf"; then
      say "$A: OOM at CP_B=$B -- retrying smaller"; continue
    fi
    break
  done

  local RN; RN=$(grep -aoE 'CP_Training_log[0-9]+' "$lf" | head -1 | grep -oE '[0-9]+')
  [ -n "$RN" ] || { say "$A: no run number in $lf -- FAILED"; return 1; }
  local CKF; CKF=$(ls -t $CK/blumodelcp_run${RN}_step_*.ckpt 2>/dev/null | head -1)
  [ -n "$CKF" ] || { say "$A: run $RN wrote NO checkpoint -- FAILED"; return 1; }
  # all four ZeRO-1 shards or the load is silently partial
  local bn n; bn=$(basename "$CKF")
  n=$(ls checkpoints_bluscriptcp/rank_*/"$bn" 2>/dev/null | wc -l)
  [ "$n" -ge 4 ] || { say "$A: only $n/4 rank shards for $bn -- FAILED"; return 1; }
  echo "$CKF" > "$LOG/${A}.ckpt"
  say "$A -> run $RN, $bn, B=$B, final loss $(grep -aE '^step ' "$lf" | tail -1 | grep -oE 'loss: [0-9.]+')"
  say "$A  peak mem $(grep -aoE 'mem: [0-9]+MB' "$lf" | tail -1)"
  return 0
}

train_one l1 lendata/b1_4096_8192 || say "L1 incomplete -- continuing"
train_one l2 lendata/b2_8192_16384 || say "L2 incomplete -- continuing"

# ---------------------------------------------------------------------------
# evaluate all three arms against ONE haystack
# ---------------------------------------------------------------------------
EXTRA=""
[ -f "$CK/blumodelcp_run28_step_400.ckpt" ] && EXTRA="armA_c=blumodelcp_run28_step_400.ckpt"
for A in l1 l2; do
  f="$LOG/${A}.ckpt"; [ -f "$f" ] || continue
  p=$(cat "$f"); [ -f "$p" ] || continue
  EXTRA="$EXTRA ${A}=$(basename "$p")"
done
[ -n "$EXTRA" ] || die "no checkpoints to evaluate"
MODELS=$(echo $EXTRA | tr ' ' '\n' | cut -d= -f1 | tr '\n' ' ')
say "eval models: $MODELS"
say "haystack: $HAY_ABS ($(stat -Lc%s "$HAY_ABS") B)"

for LEN in $LENS; do
  say "eval PROMPT_LEN=$LEN N=$N"
  # GEN_DATA_ROOT: generation never reads training data, but bluscriptCP builds
  # the DataLoader before reaching the CP_GENERATE branch, and this box has no
  # Data_Loader/Data (no flux). Any dir with a *train*.bin and a *val*.bin works.
  GEN_DATA_ROOT=lendata/b1_4096_8192 \
  HAY="$HAY_ABS" PY=$PY OUT=lenb_len_$LEN TASKS="$TASKS" CKPTS="$MODELS" N=$N \
  PROMPT_LEN=$LEN MAX_NEW=24 T=$T DEPTHS="0.0,0.25,0.5,0.75,1.0" \
  YARN_ORIG=$ORIG GPUS=0,1,2,3 JOBS_PER_GPU=2 BF16=1 GREEDY=1 \
  CKPT_EXTRA="$EXTRA" ./run_longeval.sh >> "$LOG/eval_$LEN.log" 2>&1 \
    || say "  WARN: eval at $LEN returned nonzero"
  [ -f "lenb_len_$LEN/summary.csv" ] && say "  -> $(sed -n 2p lenb_len_$LEN/summary.csv)"
done
say "eval done"

# ---------------------------------------------------------------------------
{
  echo "# Training document length vs 16k retrieval -- $(date -u +%Y-%m-%d)"
  echo
  echo "All arms: 400 steps, global batch 524,288, from run7' (run 6 step 750),"
  echo "YARN_ORIG_MAXPOS=4096 matched, Muon+ZeRO-1 bf16, 4xH100."
  echo "Only the training data differs. NIAH scored generatively (substring match),"
  echo "greedy, N=$N per cell, one shared haystack held out from every arm."
  echo
  echo "| arm | training docs |"
  echo "|---|---|"
  echo "| armA_c | flux plain text, median 826 / p90 2,721 tok |"
  echo "| l1 | b1_4096_8192, docs in [4096, 8192) |"
  echo "| l2 | b2_8192_16384, docs in [8192, 16384) |"
  echo
  for LEN in $LENS; do
    echo "## PROMPT_LEN=$LEN"; echo '```'
    cat "lenb_len_$LEN/summary.csv" 2>/dev/null || echo "(missing)"
    echo '```'; echo
  done
  echo "## Training losses"; echo '```'
  for A in l1 l2; do
    [ -f "$LOG/${A}.log" ] && \
      echo "$A: $(grep -aE '^step ' "$LOG/${A}.log" | tail -1 | grep -oE 'loss: [0-9.]+')"
  done
  echo '```'
  echo
  echo "NOTE: losses are NOT comparable across arms -- each is measured on its own"
  echo "data distribution. Longer documents are a different prediction problem, so"
  echo "a higher loss on b2 than on flux says nothing about model quality. Only the"
  echo "retrieval numbers compare."
} > "$LOG/RESULTS.md"
say "wrote $LOG/RESULTS.md"
say "=== LENBUCKET DONE ==="