File size: 7,827 Bytes
8c38801 | 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 | """Full benchmarks of the REAP-pruned checkpoints with apex_moe.lmeval, the dense full-run recipe:
MATH-500, GPQA-Diamond, HumanEval+, MBPP+ with thinking and a 64k budget, MMLU-Pro without thinking
and a 16k budget; seeds 0, 31323, 67210 (the dense full runs' seeds); tag full-reap-official; no routes saved. Qwen3.6 (NVFP4) jobs take
one idle GPU, Qwen3.8 (FP8, TP 2) jobs any two idle GPUs (NVSwitch: any pair works), DeepSeek-V4.1-Flash
(TP 4) any four, with its full-run recipe (deep_gemm, batch 36, MMLU-Pro batch 128,
VLLM_USE_BREAKABLE_CUDAGRAPH=0); --gpus limits the queue to some GPUs; a model's jobs start once its config exists
(make_config.py). Jobs with an ok ledger row or a live process (a restarted queue) are skipped; a
failed job is retried once. Seed 0 of every model first, in order: while an earlier two-GPU job
waits for a second idle GPU, later jobs do not take the idle one. Prints every launch and exit.
cd apex-moe && setsid nohup .venv/bin/python external/reap/experiments/apex/eval_queue.py \
> data/logs/reap-official-eval-queue.log 2>&1 &
"""
import json
import os
import subprocess
import time
from pathlib import Path
ROOT = Path("/localhome/mkleineg/dgx-moe/apex-moe")
TAG = "full-reap-official"
MODELS = { # config name -> (GPUs per job, batch)
"qwen3.6-35b-a3b-nvfp4-reapofficial-keep50": (1, 76),
"qwen3.6-35b-a3b-nvfp4-reapofficial-keep25": (1, 76),
"qwen3.8-flash-next-fp8-reapofficial-keep50": (2, 80),
"qwen3.8-flash-next-fp8-reapofficial-keep25": (2, 80),
"deepseek-v4.1-flash-reapofficial-keep50": (4, 36),
"deepseek-v4.1-flash-reapofficial-keep25": (4, 36),
}
DEEPSEEK = { # the DeepSeek full runs' extra settings (configs/models/deepseek-v4.1-flash.yaml)
"sets": ["model.model_args.moe_backend=deep_gemm"],
"mmlu_batch": 128,
"env": {"VLLM_USE_BREAKABLE_CUDAGRAPH": "0"},
}
TASKS = {
"minerva": "minerva_math500",
"gpqa": "gpqa_diamond_cot_zeroshot",
"humaneval": "humaneval_plus_think",
"mbpp": "mbpp_plus_think",
"mmlu": "mmlu_pro",
}
SEEDS = (0, 31323, 67210)
def gpu_memory() -> dict[int, int]:
out = subprocess.run(
["nvidia-smi", "--query-gpu=index,memory.used", "--format=csv,noheader,nounits"],
capture_output=True, text=True, check=True,
).stdout
return {int(i): int(m) for i, m in (line.split(",") for line in out.strip().splitlines())}
def done() -> set[tuple[str, int]]:
ok = set()
for line in (ROOT / "experiments/ledger.jsonl").open():
row = json.loads(line)
if row.get("tag") == TAG and row.get("status") == "ok":
ok.add((row["run_id"].rsplit("-", 2)[0], row["seed"]))
return ok
def live() -> set[tuple[str, str, int]]:
"""(model, task, seed) of every apex_moe.lmeval process of this tag already running."""
out = set()
for proc in Path("/proc").iterdir():
try:
argv = (proc / "cmdline").read_bytes().decode().split("\0")
except (OSError, ValueError):
continue
if "apex_moe.lmeval" not in argv or TAG not in argv:
continue
model = Path(argv[argv.index("--model") + 1]).stem
task = next(k for k, v in TASKS.items() if v == argv[argv.index("--tasks") + 1])
out.add((model, task, int(argv[argv.index("--seed") + 1])))
return out
def name_of(model: str, task: str) -> str:
return f"{model}-lmeval-{task}-docs20000-{'nothink-' if task == 'mmlu' else ''}dense"
def command(model: str, task: str, seed: int) -> list[str]:
batch = MODELS[model][1]
deepseek = model.startswith("deepseek")
mmlu_batch = DEEPSEEK["mmlu_batch"] if deepseek else 140
cmd = [
".venv/bin/python", "-m", "apex_moe.lmeval", "--model", f"configs/models/{model}.yaml",
"--docs", "20000", "--seed", str(seed), "--tasks", TASKS[task], "--tag", TAG,
]
if task == "mmlu":
cmd += [
"--set", "model.model_args.enable_thinking=false",
"--set", "model.gen_kwargs.chat_template_kwargs.enable_thinking=false",
"--set", "model.gen_kwargs.max_gen_toks=16384",
"--set", "model.model_args.max_model_len=18432",
"--set", f"model.model_args.max_num_seqs={mmlu_batch}",
"--set", f"name={name_of(model, task)}",
"--note", f"official REAP pruned, full MMLU-Pro without thinking, batched {mmlu_batch}",
]
else:
cmd += [
"--set", "model.gen_kwargs.max_gen_toks=65536",
"--set", "model.model_args.max_model_len=69632",
"--set", f"model.model_args.max_num_seqs={batch}",
"--note", f"official REAP pruned, full test set, 64k budget, batched {batch}",
]
if task in ("humaneval", "mbpp"):
cmd.append("--allow-code-execution")
if deepseek:
for setting in DEEPSEEK["sets"]:
cmd += ["--set", setting]
return cmd
def main() -> None:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--gpus", default="0,1,2,3,4,5,6,7", help="GPUs the queue may use")
allowed = {int(g) for g in parser.parse_args().gpus.split(",")}
os.chdir(ROOT)
jobs = [(m, t, s) for s in SEEDS for m in MODELS for t in TASKS]
running: dict[tuple, tuple[subprocess.Popen, tuple[int, ...]]] = {}
failures: dict[tuple, int] = {}
print(f"{time.strftime('%T')} queue: {len(jobs)} jobs", flush=True)
while True:
for job, (proc, gpus) in list(running.items()):
if proc.poll() is not None:
print(f"{time.strftime('%T')} exit {proc.returncode}: {job} on GPUs {gpus}", flush=True)
if proc.returncode != 0:
failures[job] = failures.get(job, 0) + 1
del running[job]
finished = done()
elsewhere = live() - set(running)
pending = [
j for j in jobs
if (name_of(j[0], j[1]), j[2]) not in finished and j not in running and failures.get(j, 0) < 2
and j not in elsewhere
and (ROOT / f"configs/models/{j[0]}.yaml").exists()
]
waiting = [j for j in jobs if not (ROOT / f"configs/models/{j[0]}.yaml").exists()]
if not pending and not running and not waiting and not elsewhere:
break
busy = {g for _, gpus in running.values() for g in gpus}
memory = gpu_memory()
idle = [g for g, used in sorted(memory.items()) if g in allowed and g not in busy and used < 2000]
for job in pending:
width = MODELS[job[0]][0]
gpus = tuple(idle[:width]) if len(idle) >= width else None
if gpus is None:
break
idle = [g for g in idle if g not in gpus]
env = os.environ | {
"PATH": f"{ROOT}/.venv/bin:{os.environ['PATH']}",
"OMP_NUM_THREADS": "8",
"CUDA_VISIBLE_DEVICES": ",".join(map(str, gpus)),
"APEX_SAVE_ROUTES": "0",
"HF_ALLOW_CODE_EVAL": "1",
} | (DEEPSEEK["env"] if job[0].startswith("deepseek") else {})
log = ROOT / f"data/logs/reapoff-{job[0].split('-reapofficial-')[1]}-{job[0][:8]}-{job[1]}-s{job[2]}.log"
proc = subprocess.Popen(
command(*job), env=env, stdout=log.open("w"), stderr=subprocess.STDOUT,
stdin=subprocess.DEVNULL, start_new_session=True,
)
running[job] = (proc, gpus)
where = ",".join(map(str, gpus))
print(f"{time.strftime('%T')} GPUs {where}: {job} (PID {proc.pid}) -> {log.name}", flush=True)
time.sleep(20)
time.sleep(30)
print(f"{time.strftime('%T')} queue done; failed twice: {[j for j, n in failures.items() if n >= 2]}", flush=True)
if __name__ == "__main__":
main()
|