#!/bin/bash # Launch one LOOM run with torchrun (single node or multi-node). # # The architecture overrides below are the LOOM recipe used in the paper; the model size, # schedule and data come from the environment. The presets in scripts/loom_329m.sh and # scripts/loom_1p7b.sh set those for the two paper scales. # # H=9 DATA_PATH=data/fineweb-edu-1024 bash scripts/train.sh # H=3 DATA_PATH=... TOTAL_STEPS=20 GLOBAL_BATCH_SIZE=16 MICRO_BATCH_SAMPLES=8 bash scripts/train.sh # # Multi-node: run the same command on every node with NNODES, NODE_RANK, MASTER_ADDR and # MASTER_PORT set (WORLD_SIZE / RANK as injected by most schedulers are also accepted). set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT" # ---- what to run ------------------------------------------------------------ H="${H:?set H (number of loops): 1, 3, 6, 9 or 12}" ARCH_SIZE="${ARCH_SIZE:-T_moe_L15_E32}" ARCH_N_LAYERS="${ARCH_N_LAYERS:-15}" ARCH_NET="${ARCH_NET:-looped_transformer}" DATA_PATH="${DATA_PATH:?set DATA_PATH to a packed DocumentDataset directory}" # Where weights go. Default: checkpoints// under the repo. CHECKPOINT_PATH="${CHECKPOINT_PATH:-}" GLOBAL_BATCH_SIZE="${GLOBAL_BATCH_SIZE:-1024}" MICRO_BATCH_SAMPLES="${MICRO_BATCH_SAMPLES:-4}" LR="${LR:-6e-5}" TOTAL_STEPS="${TOTAL_STEPS:-20000}" LR_WARMUP_RATIO="${LR_WARMUP_RATIO:-0.1}" LR_DECAY_RATIO="${LR_DECAY_RATIO:-0.1}" LR_MIN_RATIO="${LR_MIN_RATIO:-0.1}" VAL_PATH="${VAL_PATH:-}" # eval on this pack's epoch_0 instead of DATA_PATH's holdout CKPT_EVERY="${CKPT_EVERY:-500}" # live checkpoint (overwritten) -> resume granularity export SNAPSHOT_EVERY_STEPS="${SNAPSHOT_EVERY_STEPS:-2000}" # immutable full copies (19 GB at 1.7B) export SNAPSHOT_KEEP_LAST="${SNAPSHOT_KEEP_LAST:-1}" # prune older snapshots; 0 keeps all EVAL_INTERVAL="${EVAL_INTERVAL:-500}" BP_K="${BP_K:-3}" SEED="${SEED:-0}" # ---- topology --------------------------------------------------------------- # WORLD_SIZE / RANK are read as node count / node rank when NNODES / NODE_RANK are unset. NPROC_PER_NODE="${NPROC_PER_NODE:-$(python -c 'import torch;print(torch.cuda.device_count())')}" NNODES="${NNODES:-${WORLD_SIZE:-1}}" NODE_RANK="${NODE_RANK:-${RANK:-0}}" MASTER_ADDR="${MASTER_ADDR:-127.0.0.1}" MASTER_PORT="${MASTER_PORT:-29500}" WORLD="$((NNODES * NPROC_PER_NODE))" if (( GLOBAL_BATCH_SIZE % WORLD != 0 )); then echo "ERROR: global_batch_size ${GLOBAL_BATCH_SIZE} not divisible by world size ${WORLD}" >&2 exit 1 fi SAMPLES_PER_RANK=$((GLOBAL_BATCH_SIZE / WORLD)) if (( SAMPLES_PER_RANK % MICRO_BATCH_SAMPLES != 0 )); then echo "ERROR: samples/rank ${SAMPLES_PER_RANK} not divisible by micro ${MICRO_BATCH_SAMPLES}" >&2 exit 1 fi # ---- runtime env ------------------------------------------------------------ export DIST_BACKEND="${DIST_BACKEND:-nccl}" export MOE_BACKEND="${MOE_BACKEND:-npu_fused}" # packed expert weights + grouped GEMM (also the CUDA path) export MOE_ROUTING="${MOE_ROUTING:-python}" # token permute/unpermute in PyTorch export PREFIXLM_ATTN_BACKEND="${PREFIXLM_ATTN_BACKEND:-fa2}" export PREFIXLM_FUSION_ROPE="${PREFIXLM_FUSION_ROPE:-0}" export TORCH_COMPILE_DISABLE="${TORCH_COMPILE_DISABLE:-1}" export DATALOADER_NUM_WORKERS="${DATALOADER_NUM_WORKERS:-1}" export MODULE_DIAG_FORCE_OFF="${MODULE_DIAG_FORCE_OFF:-0}" export MODULE_DIAG_INTERVAL="${MODULE_DIAG_INTERVAL:-50}" export MODULE_DIAG_ACT="${MODULE_DIAG_ACT:-1}" export MODULE_DIAG_RANK="${MODULE_DIAG_RANK:-1}" export MODULE_DIAG_GRAD="${MODULE_DIAG_GRAD:-0}" export MODULE_DIAG_LIVE_PLOT="${MODULE_DIAG_LIVE_PLOT:-0}" export EXPERT_FREQ_EVERY="${EXPERT_FREQ_EVERY:-1}" export LAMBDA_LOG_EVERY="${LAMBDA_LOG_EVERY:-10}" export NUM_LOOPS="$H" export H_LIST_OVERRIDE="$H" export OMP_NUM_THREADS="${OMP_NUM_THREADS:-1}" export MKL_NUM_THREADS="${MKL_NUM_THREADS:-1}" export NCCL_DEBUG="${NCCL_DEBUG:-WARN}" export PYTHONPATH="${ROOT}:${PYTHONPATH:-}" # ---- run name / checkpoint dir --------------------------------------------- RUN_TAG="${RUN_TAG:-loom_L${ARCH_N_LAYERS}_H${H}}" RUN_TIMESTAMP="${RUN_TIMESTAMP:-$(date +%Y%m%d_%H%M%S)}" FULL_RUN_NAME="${FULL_RUN_NAME:-${RUN_TAG}_s${TOTAL_STEPS}_${RUN_TIMESTAMP}}" # ---- LOOM recipe ------------------------------------------------------------- # residual scaling arch.cycle_residual_scale, arch.cycle_scale_lambda # embedding inject arch.embed_inject_* # per-loop routers arch.moe.router_per_loop, arch.moe.router_num_loops # Looping Residual arch.attn_res=true arch.attn_res_scope=dual_axis, arch.dual_axis_* # MoE output norm arch.ffn_branch_rms # segmented backprop arch.bp_segment_len (backward + optimizer step every BP_K loops) LAM="${CYCLE_SCALE_LAMBDA:-0.5}" BETA="${DUAL_AXIS_BETA_INIT:-0.5}" # Ablation switches; defaults are the LOOM values. CYCLE_RESIDUAL_SCALE="${CYCLE_RESIDUAL_SCALE:-true}" # false: loop residual γ=1 (inject schedule unaffected) EMBED_INJECT_MODE="${EMBED_INJECT_MODE:-loop_start_mix_soft}" # none: no embedding re-injection at loop start FFN_BRANCH_RMS="${FFN_BRANCH_RMS:-affine}" # none: no RMSNorm on the MoE output read -r -d '' ARCH_OVERRIDES <&2; exit 1; } VAL_ARGS="data.val_path=${VAL_PATH}" fi TRAIN_OVERRIDES="${TRAIN_OVERRIDES} skip_loss_delta=0.18 skip_loss_rel=0.06 skip_loss_ratio=0.09 skip_loss_hard=1.5 skip_loss_ema=0.9 skip_delta_warmup_steps=0" TRAIN_OVERRIDES="${TRAIN_OVERRIDES} skip_abort_on_spike=${SKIP_ABORT_ON_SPIKE:-true} skip_abort_consecutive=${SKIP_ABORT_CONSECUTIVE:-0}" CKPT_ARGS=() if [[ -n "${CHECKPOINT_PATH}" ]]; then CKPT_ARGS+=("checkpoint_path='${CHECKPOINT_PATH}'") fi RESUME_ARGS=() if [[ -n "${RESUME_FROM:-}" && "${RESUME_FROM}" != "none" ]]; then RESUME_ARGS+=("resume_from='${RESUME_FROM}'") fi cat </ (under cwd)} resume : ${RESUME_FROM:-none} (set RESUME_FROM= to continue) master : ${MASTER_ADDR}:${MASTER_PORT} =========================================== INFO exec torchrun \ --master_addr="${MASTER_ADDR}" \ --master_port="${MASTER_PORT}" \ --nproc_per_node="${NPROC_PER_NODE}" \ --nnodes="${NNODES}" \ --node_rank="${NODE_RANK}" \ pretrain.py \ "arch/net@arch=${ARCH_NET}" \ "arch/size@arch=${ARCH_SIZE}" \ arch.num_loops="${H}" \ arch.n_layers="${ARCH_N_LAYERS}" \ lm_mode=causal \ global_batch_size="${GLOBAL_BATCH_SIZE}" \ micro_batch_samples="${MICRO_BATCH_SAMPLES}" \ lr="${LR}" \ total_steps="${TOTAL_STEPS}" \ downstream_eval_interval=0 \ optimizer=adamw beta1=0.9 beta2=0.95 weight_decay=0.1 ema=null \ seed="${SEED}" \ run_name="${FULL_RUN_NAME}" \ data.path="${DATA_PATH}" \ data.format=document \ ${VAL_ARGS} \ ${ARCH_OVERRIDES} \ ${TRAIN_OVERRIDES} \ "${CKPT_ARGS[@]}" \ "${RESUME_ARGS[@]}"