diff --git a/.gitignore b/.gitignore index 6838b06..4646f80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,13 @@ *.git *.vscode *.log +# Editable install metadata for the kernels/ submodule (scmp_kernels package) +*.egg-info/ +kernels/build/ pretrained_models/stabilityai results wandb # Large eval-output dirs (kept local only) results_full_short results_simpler_demo +robotdata diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..53a6890 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "kernels"] + path = kernels + url = https://github.com/CrucibleComputingGroup/scmp_kernels.git + branch = main diff --git a/EXPERIMENT_PLAN.md b/EXPERIMENT_PLAN.md new file mode 100644 index 0000000..b576252 --- /dev/null +++ b/EXPERIMENT_PLAN.md @@ -0,0 +1,262 @@ +# SCMP World Model (IRASim) — Experiment Plan & Runbook + +Everything needed to reproduce / continue the SC quantization study on a fresh +machine. Written 2026-07-24. Code lives on `AE-W/scmp_worldmodel`, branch +`reorg/sc-kernel-submodule` (HEAD `e578d11`), kernels submodule pinned `fd0982e`. + +-------------------------------------------------------------------------------- +## 0. What this is + +Task: run the IRASim video-DiT world model with **every matmul simulated in +stochastic computing (SC)**, and measure the quality/precision tradeoff against +FP and integer-quantization baselines. Model = IRASim-XL/2 (28-block video DiT, +hidden 1152, alternating spatial/temporal attention, frame-level adaLN action +conditioning), one checkpoint per dataset (bridge / RT-1 / Language-Table). + +-------------------------------------------------------------------------------- +## 1. Environment setup (new machine) + +```bash +# clone with the kernels submodule +git clone --recurse-submodules https://github.com/AE-W/scmp_worldmodel.git +cd scmp_worldmodel +git checkout reorg/sc-kernel-submodule + +# conda env (py3.10, cu121) +conda create -n scmp python=3.10 -y && conda activate scmp +pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 +pip install timm "diffusers[torch]==0.24.0" einops transformers scikit-image \ + pandas imageio imageio-ffmpeg omegaconf "huggingface_hub==0.25.2" \ + opencv-python-headless rotary_embedding_torch einops_exts accelerate decord \ + wandb tensorboard scipy matplotlib +pip install -e ./kernels # scmp_kernels (Triton, needs CUDA GPU) +pip install -e ./pytorch-fid # for FID (or: pip install pytorch-fid) +``` + +Requires: CUDA GPU (A100-80G used; ~15-20 GB per eval task, batch=1). + +### Data (bridge, from ByteDance IRASim release) + +The eval subset (per dataset) needs: `evaluation_latent_videos/test_sample_latent_videos/*.pt`, +`evaluation_videos/test_sample_videos/*.mp4`, `annotation/test/*.json`, +`checkpoints/frame_ada/0300000.pt`, `evaluation_cache/test_fid_cache.npz`. + +```bash +BASE=https://lf-robot-opensource.bytetos.com/obj/lab-robot-public/opensource_IRASim_v1 +mkdir -p robotdata/opensource_robotdata && cd robotdata/opensource_robotdata +# checkpoints tar is UNCOMPRESSED tar w/ HTTP range -> can parallel-fetch one file +# eval tar is gzip (stream + extract subset). annotation is in the TRAIN tar. +curl -sS "$BASE/bridge_checkpoints_data.tar.gz" | tar -x --wildcards '*checkpoints/frame_ada/*' +curl -sS "$BASE/bridge_evaluation_data.tar.gz" | tar -xz --wildcards \ + '*test_sample_latent_videos*' '*test_sample_videos*' '*evaluation_cache*' +curl -sS "$BASE/bridge_train_data.tar.gz" | tar -xz --wildcards '*annotation/test*' +# FID/FVD detector models (NOT in the tars — standard weights): +mkdir -p evaluation_model +curl -sL "https://github.com/mseitzer/pytorch-fid/releases/download/fid_weights/pt_inception-2015-12-05-6726825d.pth" \ + -o evaluation_model/pt_inception-2015-12-05-6726825d.pth +curl -sL "https://www.dropbox.com/s/ge9e5ujwgetktms/i3d_torchscript.pt?dl=1" \ + -o evaluation_model/i3d_torchscript.pt +``` + +Then set once per shell (adjust paths): +```bash +export BRIDGE_ROOT=$PWD/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=$PWD/results/local_n_eval +export PYTHONPATH=. +``` + +-------------------------------------------------------------------------------- +## 2. The SC recipe (the "deployed" config) + +Full-coverage SC: **100% of diffusion steps × all 28 blocks × all 6 matmul +types** (qkv / qk / av / proj / mlp_fc1 / mlp_fc2). Quality recovered by four +optimizations, all env-gated (measured deltas, DPM10 n=8, full SC): + +| optimization | env | delta | +|---|---|---| +| per-row quantization | `SC_LINEAR_GRANULARITY=per_row` | 14.16 → 20.21 dB | +| uSystolic stream halving | `SC_HALVE=1` | → 23.93 dB | +| SmoothQuant (α=0.5) | `SC_SMOOTH_SCALES=` | → 24.43 dB | +| sensitivity top-17 skip | `--skip ""` | keeps it (per mandate) | + +**skip set** (10.1% of 168 operators, from leave-one-in sensitivity, n=300): +``` +mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25 +``` +(NOTE: the value actually deployed on the full-test SC line was the "provisional +top-17", which adds qkv=27 and swaps two fc2 blocks — see +results/final_sc_recipe.json for the byte-exact string in use.) + +SmoothQuant scales are pre-calibrated at `results/smoothquant_scales.pt` +(α=0.5, 112 linears). Regenerate with: +```bash +python evaluate/calibrate_smoothquant.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --keys_file results/diverse_300.json --num_samples 8 --alpha 0.5 \ + --out results/smoothquant_scales.pt +``` + +### SC spec (group convention, HPCA) +`sc_prec ≡ 8` always. "int7/int6" is the ISO-equivalent INT width for a cycle +budget, NOT a lowered grid. Level values ARE halved cycle counts. +"int series = uniform, avg series = mixed-precision". Full table in +`configs/sc_spec.yaml`: + +| config | type | levels / stoc_len | budget | avg cycles | iso-int | +|---|---|---|---|---|---| +| sc_int8 | uniform | 128 | — | 128 | int8 | +| sc_int7 | uniform | 64 | — | 64 | int7 | +| sc_int6 | uniform | 32 | — | 32 | int6 | +| sc_avg192 | MP | [128,96,64] | 0.75×128 | 96 | int8 | +| sc_avg96 | MP | [64,48,32] | 0.75×64 | 48 | int7 | + +Scrambling: bitrev, 64 masks (kernel default, `SC_OWEN_MODE=bitrev`, +`SC_SCRAMBLE_MASKS=64` — no env needed). Symmetric + bipolar. + +-------------------------------------------------------------------------------- +## 3. Experiment matrix & status (bridge) + +Legend: ✅ done · 🟢 running · ⏳ todo + +### Baselines (11 cells) +- ✅ FP16 full (2946): **PSNR 25.30 / SSIM 0.834 / L2 0.1945 / FID 4.99 / FVD* + (FVD needs official recompute)** +- ✅ W8A8_symm (naive int8) full (2946): 300-clip snapshot **24.81 / 0.815 / FID 21.59** + (full aggregate to be recomputed) +- ⏳ W8A8_asymm, W7A7_{symm,asymm}, W6A6_{symm,asymm}, W5A5_{symm,asymm}, + W4A4_{symm,asymm} — 9 cells not run. These are cheap (plain int quant, fast). + +### SC Uniform (n=300 diverse; ladder, same sample set) +- ✅ sc_int8 (128): **PSNR 23.27 / SSIM 0.793 / L2 0.259** +- ✅ sc_int7 (64): **22.73 / 0.766 / 0.257** +- ✅ sc_int6 (32): **21.25 / 0.684 / 0.320** + +### SC Mixed precision (n=300 diverse) +- ✅ calibrated fractions: avg192 = [0.239,0.523,0.239]@[128,96,64]; + avg96 = [0.243,0.514,0.243]@[64,48,32] +- 🟢 sc_avg192, sc_avg96 evaluation running (`scripts/run_mp_ladder.sh`) + +### SC full-test deployed recipe (2946, PNDM50) +- ✅ **PSNR 24.43 / SSIM 0.807 / L2 0.2082 / FID 10.85** — SC FID is HALF of + naive int8's 21.59 at the same bit width (quantization cost, not SC noise) + +### Other datasets +- ⏳ Language-Table: data ready, needs eval config (288×512, 2-D action) + + action adapter (per dataset_2D.py). MUST re-run the 4-piece sensitivity + (diverse sampling → LOI sweep → skip verify → SmoothQuant recalib) — weights + are independently trained, sensitivity does NOT transfer. +- ⏳ RT-1: data incomplete (disk was full). Same 4-piece re-run rule applies. + +-------------------------------------------------------------------------------- +## 4. How to run each experiment (exact commands) + +### 4a. One SC config, n samples (the primitive) +```bash +# uniform (e.g. sc_int7, stream length 64): +CUDA_VISIBLE_DEVICES=0 SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 \ + SC_PREC=8 SC_UNIFORM_STOC_LEN=64 \ + SC_SMOOTH_SCALES=results/smoothquant_scales.pt \ + python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --skip "mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25" \ + --tag sc_int7 --keys_file results/diverse_300.json --num_samples 300 \ + --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM + +# mixed precision (e.g. sc_avg192) — pass compact JSON via EXPORT (never `env VAR=`, +# it word-splits the JSON!): +export SC_MP_CONFIG='{"stoc_len_levels":[128,96,64],"level_fractions":[0.2387,0.5226,0.2387]}' +CUDA_VISIBLE_DEVICES=0 SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 \ + SC_PREC=8 SC_SMOOTH_SCALES=results/smoothquant_scales.pt \ + python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --skip "..." --tag sc_avg192 --keys_file results/diverse_300.json \ + --num_samples 300 --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM +``` +Key eval flags: `--inference_steps 50 --scheduler PNDM` = paper protocol (slow, +~13 min/sample with SC). `--inference_steps 10 --scheduler DPM` = fast probe +(~2 min/sample) for calibration/sanity only. `--naive_int8` = plain int8 +(no SC) baseline. `--keys_file results/diverse_300.json` selects the 300 +diverse samples (episode-dedup + farthest-point sampling; see +evaluate/select_diverse_samples.py). Per-sample metrics resume automatically. + +### 4b. Full 5-config ladder (GPU auto-grab, resume) +```bash +# uniform int8/int7/int6 (edit EXCLUDE gpus inside if needed): +setsid nohup scripts/run_sc_ladder.sh > sc_ladder.log 2>&1 < /dev/null & disown +# MP avg192/avg96 (+ any uniform backfill) — uses explicit export: +setsid nohup scripts/run_mp_ladder.sh > mp_ladder.log 2>&1 < /dev/null & disown +``` +Both slice each config into 12 shards, auto-grab GPUs 2-6 (free>20 GB, util<45%), +skip contended ones, and resume from per-sample metric files. + +### 4c. FID / FVD +```bash +# FID (standard pytorch-fid, reliable): +PYTHONPATH=.:pytorch-fid/src CUDA_VISIBLE_DEVICES=0 \ + python evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval//videos --out results/fidfvd_.json +# ⚠️ FVD: our streaming impl is NOT yet cross-checked against official +# StyleGAN-V (rescale bug fixed but unverified). For paper numbers, use +# stylegan-v/src/scripts/calc_metrics_for_dataset.py. DO NOT report our FVD +# until cross-checked. +``` + +### 4d. MP fraction calibration (per config, per dataset) +```bash +CUDA_VISIBLE_DEVICES=0 python evaluate/calibrate_mp_fractions.py \ + --config_name sc_avg192 --out results/mp_fractions_sc_avg192.json +# Lagrangian budget allocation over measured per-row error curves. +# Repeat for sc_avg96. (int8/int7/int6 are uniform — no calibration.) +``` + +### 4e. Sensitivity re-run (REQUIRED per new dataset/checkpoint) +```bash +# 1) diverse 300 samples on THIS dataset's latents: +python evaluate/select_diverse_samples.py --n 300 --out results/diverse_.json +# 2) leave-one-in sweep (fast, ~all-FP): 169 configs × 300, GPU auto-grab: +setsid nohup python evaluate/gpu_scheduler_loi.py > loi.log 2>&1 < /dev/null & disown +# -> rank operators, take top-17 (10%) as skip set +# 3) verify skip set beats no-skip on new baseline (probe, n=8) +# 4) recalibrate SmoothQuant on this dataset (activation stats differ) +``` + +-------------------------------------------------------------------------------- +## 5. Backups & housekeeping + +- Metrics/json/code: auto-backed-up hourly to HF private dataset + `BDXXN/scmp-worldmodel-progress` (`evaluate/hf_backup.py`, cron :23). +- Videos: `evaluate/hf_backup_videos.py` (cron every 10 min) uploads new mp4s, + verifies them on HF, then prunes local copies (keeps newest 30/dir; never + touches a line whose FID/FVD isn't computed yet). Keeps disk flat. +- Kernel daily check: `scripts/check_kernel_update.sh` (cron 8:17) fetches + scmp_kernels; log at ~/scmp_kernel_update.log. +- Disk on the current machine is shared & chronically full — guard writes. + +-------------------------------------------------------------------------------- +## 6. Immediate TODO (priority order) + +1. Finish MP ladder (avg192/avg96 n=300) → complete the 5-config table. +2. Official StyleGAN-V FVD recompute for FP / SC / naive int8 (our FVD suspect). +3. Aggregate naive_int8 FULL (2946) FID/FVD for a fair 3-row headline table. +4. Fill the 9 missing integer baselines (W8A8_asymm … W4A4, symm+asymm) — cheap. +5. Language-Table: eval config + 2-D action adapter → 4-piece sensitivity → run. +6. RT-1: free disk, stream data, → 4-piece sensitivity → run. +7. QwT (optional) — kernel-side placeholder still. + +-------------------------------------------------------------------------------- +## 7. Key files + +| file | purpose | +|---|---| +| `configs/sc_spec.yaml` | authoritative SC spec + HPCA config table | +| `models/sc_integration/sc_linear.py` | per_row / halve / SmoothQuant / MP dispatch | +| `evaluate/eval_local_n_samples.py` | the eval primitive (--keys_file, --skip, resume) | +| `evaluate/calibrate_mp_fractions.py` | MP fraction solver (Lagrangian) | +| `evaluate/calibrate_smoothquant.py` | SmoothQuant scale calibration | +| `evaluate/select_diverse_samples.py` | diverse-300 selection (episode-dedup + FPS) | +| `evaluate/gpu_scheduler_loi.py` | leave-one-in sensitivity sweep scheduler | +| `evaluate/compute_fid_fvd_stream.py` | streaming FID (FVD pending official) | +| `scripts/run_sc_ladder.sh` / `run_mp_ladder.sh` | 5-config ladder runners | +| `results/final_sc_recipe.json` | byte-exact deployed SC recipe | +| `results/diverse_300.json` | the 300 diverse sample keys | +| `results/mp_fractions_*.json` | calibrated MP fractions | diff --git a/MP_INVESTIGATION_LOG.md b/MP_INVESTIGATION_LOG.md new file mode 100644 index 0000000..29beb6b --- /dev/null +++ b/MP_INVESTIGATION_LOG.md @@ -0,0 +1,91 @@ +# MP vs Uniform 调查日志(bridge / IRASim-XL/2) + +记录这条线的全部设计决策、bug、实验与结论,供后续接手与论文写作。 +时间跨度 2026-07-30 ~ 07-31。所有实验:bridge,PNDM-50,per_row + halve + +SmoothQuant + top-17 skip(与部署配方一致,另有注明除外),配对比较 +(同一批 diverse key,逐视频作差)。 + +--- + +## 0. 问题 + +同算力预算下,行级混合精度(MP:按行分配流长)能否打赢 uniform(所有行同流长)? +理论直觉:uniform 是 MP 可行域中的退化点,"最优 MP ≥ uniform" 应成立。 + +## 1. 基线事实(先于本轮调查) + +- 全量 2946:7.58 位 MP [128,96,64] vs uniform-96 → **−0.027 dB**(胜率 49.5%) +- 6.58 位 → **+0.003 dB**(49.8%)。逐视频五五开 = 无区分度。 +- 参考(scmp_llm 表):LLM 上 MP 全位宽赢,6.0 位赢 55%。 + +## 2. 实验时间线与结果 + +| # | 假设/干预 | 实验 | 结果 | 判定 | +|---|---|---|---|---| +| E1 | 级集太窄(3档/2x跨度) | 手挑 w5/n5/w7 + 穷举搜索 k=3..8(17点网格,拉格朗日打分),n=10×18配置 | 全部 ≤ +0.05,最优反而是原始 3 档 | 级集不是瓶颈 | +| E2 | k(档数)不够 | k 扫到 17:代理误差 k≥7 饱和(每档 <0.2%),k≥14 出现空档 | 端到端 k4..k8 混在噪声里 | k 不是瓶颈 | +| E3 | n=10 噪声 | 赢家 n5+smoothed(+0.148, 7/10)复核 n=100 | **+0.006(52/100)** | E1 的"赢"是抽样噪声 | +| E4 | 校准/部署失配 bug①(见 §3) | 修复后一致网格重搜(sqk4..8),n=10 | 级集几乎不变,端到端仍负 | 失配存在但非主因 | +| E5 | 排序信号失配 bug②(见 §3) | 排序改用 (x/s).amax(mfix),n=10 | avg192 从 +0.015 → **−0.574**;越准越差 | 方向性反证:绝对误差排序对 PSNR 有害 | +| E6 | 排序方向反了 | SC_MP_INVERT 反转,n=10×3 | −0.32 ~ −0.73 | 反向也不对 | +| E7 | SmoothQuant 吃掉了 MP 空间 | 两边关 SQ(nosq),n=10×6 | 差距不变(5/6 更糟) | 假设不成立 | +| E8 | 目标错(绝对RMSE) | 移植 scmp_llm 相对L2/delta_sigma2;实测逐行梯度权重(rowsens,68.8万对) | Spearman(metric, w_eps)=+0.17;**w_pix=+0.02** | 运行时信号对 PSNR 敏感度零信息 | +| E9 | 用实测权重+跨层预算流动 | w_pix 加权拉格朗日 → 112 模块各自 fractions+方向(19 反向,模块均值 27~128),n=10 | **−0.211(4/10)** | 一阶模型在 50 步采样+短流非线性下失效 | +| E10 | 悬崖区才有异质性(≤6位) | sigma2 搜索 budget 32/24,n=10 | 6.0位 +0.015(门未过:SSIM/L2 护栏挂);5.58位 **−1.122** | 零排序信息下,悬崖区乱分配严格更差 | +| E11 | 时间步轴(scmp_diffusion 维度) | 50/50 硬切调度 late/early vs UNI96,n=10 | late −0.10(5/7中途) vs early −0.66 → **方向差 0.56 dB** | **唯一有真方向信号的轴**,在跑校准 | +| E12 | LLM 交叉验证 | Qwen3-4B wikitext:uniform@32 vs MP[64,32,16](6.0位档) | 在跑 | 验证工具链+定位模型属性差异 | + +**根因测量**(独立于以上干预): +- 行间相对边际收益(L48→L96)变异系数 **5%**,P90/P10=1.13 —— 几乎无异质性。 +- 模块间异质性比模块内更小(方差比 0.36×)—— 跨层分配也无空间。 +- corr(行绝对误差, 相对收益) = **−0.24** —— 绝对误差目标的方向系统性偏错。 + +## 3. Bug 清单(症状 → 根因 → 修复) + +| # | 症状 | 根因 | 修复 | +|---|---|---|---| +| B1 | 7 个多档配置静默 0 样本,Slurm 报 COMPLETED | fractions 逐档 round(4) 残差累加,和偏离 1.0±1e-4,MPConfig 在 import 时抛错,作业退出码 0 | 残差吸收进最大档;生成端同修(search_mp_levels.py) | +| B2 | 代理收益 6.6% 传不到端到端 | 校准/搜索测误差**不带** smooth_scales,部署带 —— fractions 在错误误差景观上解出(原始 calibrate_mp_fractions.py 即如此,旧机器结果同病) | measure 补 smooth_scales(--smooth_scales) | +| B3 | 排序"修准"反而更差 | 运行时排 raw amax,kernel 实际量化 x/s(s 同 linear 内跨通道 4.9×~30.6×)→ 排序被系统性打乱;但修准后(E5)暴露更深层问题:matmul误差排序 ≠ PSNR 排序 | 排序改 (x/s).amax;进一步引出 E8 | +| B4 | delta_sigma2 搜索全塌到最低档(err=0) | 基线取"第0列=最长流",但网格文件升序存(第0列=L16),delta 恒 0 | 变换移到子集选列后(列已降序);跨集比较改用 sigma2(delta 基线跨集不可比) | +| B5 | _assign 收到升序 costs 时早退分支全放最高档(超预算非法解),产出"神谕=可实现=100%"假象 | _assign 约定 costs 降序,调用方传了升序 | 调用侧统一降序(工具函数文档已注明约定) | +| B6 | (更早)MP/uniform 对比曾用不同样本集 | naive_int8_300 未传 --keys_file(排序前300 vs diverse_300,只重合20个,难度差1.04dB) | 全部对比改同源配对;已在主线修正 | + +**教训**:B1 类"退出码 0 的失败"要靠产物计数抓,不能只看 sacct; +B2/B3 类"校准与部署不一致"要逐参数 diff 两条调用链; +B4/B5 类约定错误说明共享工具函数必须把列序约定写进签名或断言。 + +## 4. 设计决策(现行架构) + +``` +第1层 提案 代理搜索(sigma2 选集合 + 拉格朗日解 fractions) +第2层 选择 候选 ∪ {uniform} 同批 key 配对跑真指标 + 规则: ΔPSNR>margin 且 ΔSSIM≥−0.005 且 ΔL2≤+0.005 +第3层 回退 无人过门 → 部署 uniform(退化解) + ⇒ “部署解 ≥ uniform” 按构造成立(工具: evaluate/select_mp_or_uniform.py) +第4层 精调 仅效应≫噪声处(悬崖区/时间步轴)可做端到端直接搜索 +``` + +配套运行时能力(models/sc_integration/sc_linear.py): +- `SC_MP_CONFIG` 全局 fractions;`SC_MP_PER_MODULE` 每 (op,block) fractions+invert +- `SC_MP_INVERT` 全局反向;`SC_STEP_SCHEDULE` 每扩散步流长表 + (pipeline 循环发布步号 → sc_controller.get_current_step) + +## 5. 当前结论(截至 07-31 深夜) + +1. **行级 MP 在本模型/配方上无法打赢 uniform**,机制齐全: + 可观测排序信号对 PSNR 敏感度零信息(ρ=0.02),行间边际收益无异质性(CV 5%)。 + 平滑区无利可图;悬崖区乱分配严格更差。选择门在全预算段回退退化解。 +2. **时间步轴是唯一有方向信号的轴**(0.56 dB 方向差,无需排序信息), + 校准中(stepprobe:逐步砸16直测 W_t → min Σ W_t·σ(L_t)²)。 +3. LLM 上 MP 有效与此不矛盾:token 异质性+amax 信号在 LLM 真实存在 + (Qwen 复现在跑,预期确认)。 +4. 正面主结果另有其人:SC 低位宽鲁棒性(int6 +0.81dB;5位 INT_symm 崩溃 + 而 SC 稳 17.9;4位 INT_symm 发散 L2=414)。 + +## 6. 未决线程 + +- [ ] stepprobe → 校准时间步调度 → n=10 门检 →(若过)n=100 → 全量 +- [ ] qwenval 结果落表(uniform@32 vs MP@31.2, wikitext PPL) +- [ ] avg80(6.32位)全量仍 hold(42784478),待 MP 定稿后决定放行/取消 +- [ ] 论文 MP 节改写:门+回退叙事 + 本日志 §2/§5 的证据表 diff --git a/README.md b/README.md index f5adc07..4e021ee 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,49 @@ Scalable robot learning in the real world is limited by the cost and safety issu ## Installation -To set up the environment, run the following command: +The stochastic-computing (SC) Triton kernels live in the shared +[`scmp_kernels`](https://github.com/CrucibleComputingGroup/scmp_kernels) repo, +vendored here as a git submodule at `kernels/`. Clone with submodules: + ```bash -bash scripts/install.sh +git clone --recurse-submodules https://github.com/CrucibleComputingGroup/scmp_worldmodel.git +cd scmp_worldmodel +bash scripts/install.sh # installs deps + `pip install -e ./kernels` ``` +If you cloned without `--recurse-submodules`: + +```bash +git submodule update --init --recursive +pip install -e ./kernels +``` + +To pull the latest SC kernels later (every SC application shares this repo, so +fixes/upgrades land everywhere): + +```bash +git submodule update --remote kernels +# then commit the bumped submodule pointer +``` + +## Stochastic Computing (SC) backend + +The `models/sc_integration/` package swaps selected matmuls in the diffusion +transformer for bipolar int8 SC, computed by the shared `scmp_kernels.sc_matmul` +kernel: + +| op | granularity | replaces | +|----|-------------|----------| +| `sc_qk_matmul` | `per_head` | Q·Kᵀ attention scores | +| `sc_av_matmul` | `per_head` | softmax·V | +| `sc_linear_forward` / `SCMlp` | `per_tensor` | `nn.Linear` projections (qkv / proj / fc1 / fc2) | + +Which ops run on SC is driven by the `attention_mode` string in the config +(presets in `models/sc_integration/sc_controller.py`), e.g. `sc_int8` +(QK only) through `sc_int8_full` (all matmuls). Eval configs live under +`configs/evaluation/bridge/frame_ada_sc*.yaml`. Per-block opt-outs are +available via `set_skip_blocks()` / `clear_skip_blocks()`. + ## Dataset To download the complete dataset, run: diff --git a/RUNNING_ON_SLURM.md b/RUNNING_ON_SLURM.md new file mode 100644 index 0000000..51777b4 --- /dev/null +++ b/RUNNING_ON_SLURM.md @@ -0,0 +1,249 @@ +# Running the world-model (IRASim) SC experiments on a Slurm cluster + +Companion to `EXPERIMENT_PLAN.md`. That file describes *what* the experiments +are; this one describes *how* to actually get them through a shared, +contended GPU queue without wasting weeks. Written against PSC Bridges-2 +(ROBO partition, 6 nodes x 8 H100-80GB), but the mechanics transfer. + +-------------------------------------------------------------------------------- +## 0. TL;DR + +```bash +# one-time +git clone --recurse-submodules && cd scmp_worldmodel +git checkout reorg/sc-kernel-submodule # kernels submodule pinned fd0982e +bash scripts/mkenv.sh # conda env, torch cu121, -e ./kernels +ln -s /path/to/data/robotdata robotdata # dataset_dir is relative to CWD + +# every experiment is one array job of SHORT shards +sbatch -a 0-329 --export=ALL,CFG=sc_avg192,NSHARD=330 jobs/mp_full.sh +``` + +The single most important operational fact: **short jobs get scheduled, long +jobs do not.** Everything below follows from that. + +-------------------------------------------------------------------------------- +## 1. Shard for backfill, not for throughput + +A contended queue schedules by priority, but *backfill* runs any job that fits +in the gap before the next high-priority reservation. A 4-hour job almost never +fits; a 1-hour job usually does. + +Measured on this cluster: an unsharded 4-hour array sat `PENDING` for **10 +hours with zero progress**. Re-cut into 1-hour shards, **5 shards were running +within 2 hours** and 36 finished in ~70 minutes of wall-clock. + +Sizing rule: + +``` +samples_per_shard = (time_limit - model_load) / seconds_per_sample +``` + +with `model_load ~= 3.5 min` (10.87 GB checkpoint off Lustre) and a 1:15 limit: + +| config | s/sample (H100) | samples/shard | shards for 2946 | +|---|---:|---:|---:| +| naive INT (any width) | 15 | 200 | 15 | +| SC uniform L=256 | 662 | 6 | 490 | +| SC uniform L=192 | 324 | 13 | 240 | +| SC-MP avg192 (96 cyc) | 356 | 12 | 250 | +| SC-MP avg96 (48 cyc) | 315 | 13 | 230 | + +**Do not derive `s/sample` from the cycle budget.** SC has a large fixed +per-matmul overhead: avg96 (48 avg cycles) is only 12% faster than avg192 +(96 avg cycles), not 2x. Sizing avg96 shards on the 2x assumption timed out +81 of 165 shards. Measure one shard first, then size the array. + +Per-sample resume is built in, so a timed-out shard loses only the sample in +flight — but it still burns a GPU slot, so get the sizing right. + +-------------------------------------------------------------------------------- +## 2. Ask for the smallest allocation that works + +- **CPUs**: `eval_local_n_samples.py` has no DataLoader — it `torch.load`s + latents directly. The `num_workers: 11` in the eval YAML is dead config for + this script. Request **4 cores**, not 12. On a node with 8 free CPUs and a + free GPU, a 12-core request cannot land and a 4-core one can. +- **GPUs**: always `--gres=gpu:h100:1`. Whole-node requests queue for days. +- **Time**: use `scontrol update JobId= TimeLimit=` to shrink a + *pending* job without losing its queue position. Shrinking `sc_verify` from + 2h to 40min moved its estimated start from 07-28 to 07-27. + +-------------------------------------------------------------------------------- +## 3. Two-phase: n=300 first, then the rest + +`results/diverse_300.json` is a 300-sample subset (episode-dedup + farthest- +point). Run it first: it is 1/10 the cost and gives a config-vs-config +comparison good enough to decide whether the full run is worth it. + +Then run the complement (`results/rest_2646.json`) as a separate array so the +two phases never recompute the same key. + +**diverse_300 is systematically harder than the full set** — full-2946 PSNR +runs **+1.0 to +1.3 dB above** the diverse_300 subset, and that offset +reproduced across 12 configs. So: + +- comparing configs on diverse_300: fine, the offset cancels +- quoting a diverse_300 number next to a 2946 number: **wrong** + +-------------------------------------------------------------------------------- +## 4. Sample-set and metric hazards + +**Always pass `--keys_file`.** Without it the script takes the first N keys in +sorted order, which is a *different and easier* subset. A previously reported +`naive_int8_300` baseline was run this way; it shares only 20 of 300 samples +with `diverse_300` and reads 1.04 dB better. Any comparison against it was +cross-sample-set. + +**FID has a severe small-sample bias.** Same videos, only n changes: + +| n | frames | FID | +|---:|---:|---:| +| 2946 | 47136 | 7.29 | +| 300 | 4800 | 21.46 | + +That is a +14 shift with zero quality difference. Never put an n=300 FID next +to an n=2946 FID. FVD moves the same way (97.1 -> 143.0). + +**FVD**: use the official StyleGAN-V script for anything reported. The in-repo +streaming implementation is reproducible and rank-consistent but reads +2.2-4.8 low. `compute_fvd` sets `discard_short_videos=True`, so any clip that +failed to decode is dropped *silently* — verify every clip has exactly 16 +frames before trusting the number. + +-------------------------------------------------------------------------------- +## 5. Mixed precision: pass the config correctly + +`SC_MP_CONFIG` is read at **module import time** in +`models/sc_integration/sc_linear.py`, so it must be in the environment before +python starts. Use `export`, never `env VAR=...`: + +```bash +# CORRECT +export SC_MP_CONFIG='{"stoc_len_levels":[128,96,64],"level_fractions":[0.2387,0.5226,0.2387]}' +python evaluate/eval_local_n_samples.py ... + +# WRONG — the shell word-splits the JSON and the run silently uses no MP +env SC_MP_CONFIG={"stoc_len_levels":[128,96,64],...} python ... +``` + +Guard it in the job script so a malformed value fails loudly: + +```bash +case "$SC_MP_CONFIG" in + '{"stoc_len_levels":['*) : ;; + *) echo "!!! SC_MP_CONFIG malformed"; exit 1 ;; +esac +``` + +`SC_MP_PER_MODULE=` (optional) switches from one global +fraction triple to per-(operator, block) fractions taken from +`per_module_fractions`. Unset, behaviour is unchanged. + +### Bit-width naming + +Level values are **halved** cycle counts; nominal stream length `L = 2 x +avg_cycles`; effective bits `= log2(L)`. + +| config | avg cycles | L | bits | type | +|---|---:|---:|---:|---| +| sc_int8 | 128 | 256 | 8.00 | uniform | +| sc_avg192 | 96 | 192 | 7.58 | MP | +| sc_int7 | 64 | 128 | 7.00 | uniform | +| sc_avg96 | 48 | 96 | 6.58 | MP | +| sc_avg80 | 40 | 80 | 6.32 | MP | +| sc_int6 | 32 | 64 | 6.00 | uniform | + +MP tiers are `0.75 x` the reference uniform L, so the sequence is +192 / 96 / 48 — **there is no `avg64`**. + +`SC_UNIFORM_STOC_LEN` accepts **any** positive integer (no power-of-two +constraint), so uniform SC at 7.58 or 6.58 bits is directly runnable and is +the correct same-budget control for the MP tiers. Comparing an MP tier against +the *next uniform tier up* compares across budgets and is not an MP ablation. + +A calibration whose target equals the minimum of its level set degenerates to +uniform — `sc_int6` with levels `[64,48,32]` and budget 32 solves to +`[0, 0, 1]`. Choose levels that bracket the target. + +-------------------------------------------------------------------------------- +## 6. Environment traps + +- **Editable installs break when the repo moves.** `pip install -e ./kernels` + records an absolute path. After relocating the repo, re-run both editable + installs or every job dies with `ModuleNotFoundError: scmp_kernels`. Put an + import check at the top of each job so this costs 5 seconds, not 3 minutes: + ```bash + python -c "import scmp_kernels; from models.sc_integration import reconfigure" \ + || { echo "env broken"; exit 1; } + ``` +- **`nvcc` is not required.** `scmp_kernels` is pure Triton; a CUDA module is + never needed, only the torch wheel's bundled runtime. +- **Detector weights**: `evaluation_model/` belongs at the `dataset_dir` root, + not under `bridge/`. Pre-seed the I3D torchscript into + `$DNNLIB_CACHE_DIR/downloads/_i3d_torchscript.pt` so GPU jobs + never reach for the network. +- **The SDXL VAE is not in the repo or the dataset tars.** Fetch + `stabilityai/stable-diffusion-xl-base-1.0` `vae/` separately or + `AutoencoderKL.from_pretrained` fails at startup. +- **Some sources are text files with CRLF.** Patch them in binary mode or a + one-line edit shows up as a whole-file diff. + +-------------------------------------------------------------------------------- +## 7. Pre-flight without a GPU + +Everything below runs on a login node and catches most failures before a job +ever queues: + +```bash +# every path the eval will touch +PYTHONPATH=. python - <<'PY' +import os +from omegaconf import OmegaConf +from util import update_paths +a = OmegaConf.merge(OmegaConf.load("configs/base/data.yaml"), + OmegaConf.load("configs/base/diffusion.yaml"), + OmegaConf.load("configs/evaluation/bridge/frame_ada_sc_full.yaml")) +update_paths(a) +for n in ("evaluate_checkpoint","scheduler_path","test_annotation_path", + "fid_model_path","fvd_model_path","fid_cache_path", + "true_sample_latent_videos_dir","true_sample_videos_dir"): + p = getattr(a, n); print(("OK " if os.path.exists(p) else "MISS"), n, p) +PY + +# every key you intend to evaluate actually has a GT latent and mp4 +``` + +-------------------------------------------------------------------------------- +## 8. Keeping results + +Long campaigns outlive any single session. Run the backup as its own +CPU-partition job (1 core, 48 h) rather than a login-node background process, +which gets reaped: + +```bash +sbatch jobs/hf_sweeper.sh # loops: upload -> verify on HF -> prune local +``` + +It re-lists the remote after uploading and deletes only confirmed-present +files, keeps the newest 30 mp4s per directory, and never prunes a tag whose +FID/FVD has not been computed. Set `SCMP_HF_TOKEN_FILE`, `SCMP_ROOT` and +`SCMP_RESULTS`; the defaults point at the original author's machine. + +Note `hf_backup.py` ignores `*.pt` wholesale, which is how a calibration file +once went missing. Small, GPU-expensive artifacts are uploaded explicitly. + +-------------------------------------------------------------------------------- +## 9. Cost reference (H100, PNDM-50, 2946 samples) + +| run | GPU-hours | +|---|---:| +| one integer-quantization cell | 12 | +| SC uniform L=192 or an MP tier | 250-300 | +| SC uniform L=256 (deployed recipe) | 540 | +| FID + official FVD for one line | ~0.2 | + +Calibration (`calibrate_mp_fractions.py`, `calibrate_smoothquant.py`) is 2 +samples x 10 steps — under 2 minutes. Calibrate before committing to a 250 +GPU-hour evaluation, and check the calibrated fractions are non-degenerate +first. diff --git a/RUN_MP_QUEUE.sh b/RUN_MP_QUEUE.sh new file mode 100755 index 0000000..55ce419 --- /dev/null +++ b/RUN_MP_QUEUE.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# 换机器跑 MP 四栏表 + 三条备选方案的自包含脚本。 +# 前置: conda env scmp 已建 (见 RUNNING_ON_SLURM.md §0), 仓库已 clone, +# robotdata 软链已建, results/ 下已有: +# mp_error_grid_sq2.npz block_gamma.npz smoothquant_scales.pt +# diverse_10.json diverse_100.json final_sc_recipe.json +# 以及 mp_fractions_sc_{g758,g658,g632,g600}.json (Gamma块级配置) +# step_sched_Wt.json (时间步W_t调度) +# —— 这些小产物(~5MB)已直接提交进本仓库 results/, git pull 即得,无需另拷。 +# 数据集 robotdata(133GB, bridge eval 子集): 若本机没有, 见 RUNNING_ON_SLURM.md §0.3 +# 下载, 或从已有机器 rsync。HF token 放 ~/hf_token.txt 用于回传。 +# +# 用法: 每个函数是一个独立作业, 挑没跑完的投。SC ~350s/样本, n=10 单档 ~1h。 +set -e +cd "$(dirname "$0")" +export PYTHONPATH=. BRIDGE_ROOT=$PWD/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=$PWD/results/local_n_eval +SKIP=$(python -c "import json;print(json.load(open('results/final_sc_recipe.json'))['skip'])") +COMMON="SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 SC_PREC=8 SC_SMOOTH_SCALES=$PWD/results/smoothquant_scales.pt" + +# ---- 四栏 gblock MP (块间 Γ), n=10, 同批 diverse_10 ---- +run_mp() { # $1=tag(g758/g658/g632/g600) + CAL=results/mp_fractions_sc_$1.json + export SC_MP_CONFIG=$(python -c "import json;d=json.load(open('$CAL'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']},separators=(',',':')))") + export SC_MP_PER_MODULE=$PWD/$CAL + env $COMMON python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag scr10_$1 --keys_file results/diverse_10.json --num_samples 10 \ + --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM + unset SC_MP_CONFIG SC_MP_PER_MODULE +} +# ---- 四栏对应 uniform ---- +run_uni() { # $1=tag(u758/u658/u632/u600) $2=折半流长(96/48/40/32) + env $COMMON SC_UNIFORM_STOC_LEN=$2 python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag scr10_$1 --keys_file results/diverse_10.json --num_samples 10 \ + --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM +} +# ---- 备选1: 时间步 W_t 调度 (7.58位, 平均96) ---- +run_stepWt() { + export SC_STEP_SCHEDULE=$(cat results/step_sched_Wt.json) + env $COMMON python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag scr10_stepWt --keys_file results/diverse_10.json --num_samples 10 \ + --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM + unset SC_STEP_SCHEDULE +} +# ---- 备选2: 完整机制(阈值+保护通道) 先校准再评测 ---- +run_fullmp() { + python evaluate/calibrate_full_mp.py --phase both # 产 mp_fractions_sc_avg192_full.json + run_mp_generic sc_avg192_full scr10_fullmp +} +run_mp_generic() { # $1=配置名 $2=tag + CAL=results/mp_fractions_$1.json + export SC_MP_CONFIG=$(python -c "import json;d=json.load(open('$CAL'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']},separators=(',',':')))") + export SC_MP_PER_MODULE=$PWD/$CAL + env $COMMON python evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag $2 --keys_file results/diverse_10.json --num_samples 10 \ + --shard 0 --num_shards 1 --inference_steps 50 --scheduler PNDM + unset SC_MP_CONFIG SC_MP_PER_MODULE +} + +# 挑一个跑, 或全跑(串行, 每个~1h): +case "${1:-help}" in + g758) run_mp g758;; g658) run_mp g658;; g632) run_mp g632;; g600) run_mp g600;; + u758) run_uni u758 96;; u658) run_uni u658 48;; u632) run_uni u632 40;; u600) run_uni u600 32;; + stepWt) run_stepWt;; fullmp) run_fullmp;; + upload) # 把所有 scr10_* 结果 json 回传 HF (BDXXN/scmp-worldmodel-progress) + export SCMP_HF_TOKEN_FILE=${SCMP_HF_TOKEN_FILE:-$HOME/hf_token.txt} + export SCMP_ROOT=$PWD SCMP_RESULTS=$PWD/results + python evaluate/hf_backup.py ;; + all) # 串行跑所有未完成档 + 回传 (每档~1h, SC 350s/样本) + for t in g758 g658 g632 g600; do [ -d results/local_n_eval/scr10_$t/metrics ] && [ $(ls results/local_n_eval/scr10_$t/metrics|wc -l) -ge 10 ] || run_mp $t; done + run_uni u758 96; run_uni u658 48; run_uni u632 40; run_uni u600 32 + run_stepWt; run_fullmp + $0 upload ;; + *) echo "用法: $0 {g758|g658|g632|g600|u758|u658|u632|u600|stepWt|fullmp|upload|all}";; +esac diff --git a/configs/sc_spec.yaml b/configs/sc_spec.yaml new file mode 100644 index 0000000..2559d25 --- /dev/null +++ b/configs/sc_spec.yaml @@ -0,0 +1,80 @@ +# ============================================================================= +# SC 硬件规格(组内约定,权威版)— 2026-07-16 由用户口述固化 +# 本文件是"规格"而非可执行配置:描述目标硬件的 SC 行为,评测配置须与其对齐。 +# 改动需组内确认;实验若偏离此规格,必须在结果里显式标注。 +# ============================================================================= + +sc_spec: + # --- 量化 / 编码 --- + quantization: symmetric # 对称量化(bipolar 模式的 grouped_symmetric) + encoding: bipolar # 双极性随机流 + # kernel 映射: sc_matmul(mode="bipolar"), quant/_grouped_symmetric_quant + + # --- Scrambling --- + scrambling: + kind: index_bitrev # 按维度 index 取模 + 全宽 bit-reverse 掩码 + total_masks: 64 # 硬件可实现的不同掩码数(HW_MAX_MASKS=64) + # kernel 映射(当前即默认值,无需设 env): + # SC_OWEN_MODE=bitrev SC_SCRAMBLE_MASKS=64 + # 注意: kernels PR#24 之后 bitrev 是全宽 scramble;M=64 是硬件上限。 + + # --- Uniform vs heterogeneous --- + # int8 只跑 uniform(单一流长);更低 logic 精度允许 heterogeneous(MP 混合档位)。 + int8_policy: uniform_only + + # --- 精度阶梯 (logic bits × 平均流长) --- + # "Logic intN" = 量化格点位宽; "avgL" = (MP 混合后的)平均 stoc_len。 + # halve(uSystolic 符号-幅值)生效时,流长活在减半空间: 上限 2^(bits-1)。 + # ⇒ halve 模式下不存在 192/256 这样的流长;avg 值是混合平均,不是单一流长。 + # + # 【HPCA 规范 2026-07-22, 来源 scmp_llm:feat/mp-config-wiring 的 hpca 脚本】 + # 【组内确认 2026-07-23】kernel sc_prec 恒 = 8;实验变的是"平均周期(流长)"。 + # "int7/int6" 不是把量化格点降到 7/6,而是该平均周期对标的等效 INT 宽度。 + # levels 值本身就是 halved 周期数(hpca line13: "sc_prec=8, halve ON, tag + # value IS the cycle count"), 直接喂 kernel, 不再减半。 + # 名义流长 = 2 x 平均周期。规格里的 "Avg192" = 名义 192 = 96 周期。 + # 等效 INT 宽度 = ceil(log2(2*avg)): 128/96 -> int8, 64/48 -> int7, 32 -> int6 + # 【组内确认 2026-07-23】sc_prec 恒=8; "int 系列=uniform, avg 系列=heterogeneous(MP)" + # int8/int7/int6: uniform — 所有行同一流长(= avg_cycles) + # avg192/avg96: MP — 按行重要性分档混合(fractions 由校准解出) + hpca_configs: + sc_int8: {type: uniform, sc_prec: 8, uniform_stoc_len: 128, avg_cycles: 128} + sc_int7: {type: uniform, sc_prec: 8, uniform_stoc_len: 64, avg_cycles: 64} + sc_int6: {type: uniform, sc_prec: 8, uniform_stoc_len: 32, avg_cycles: 32} + sc_avg192: {type: mp, sc_prec: 8, mp_levels: [128, 96, 64], budget_ratio: 0.75, ref: 128, avg_cycles: 96} + sc_avg96: {type: mp, sc_prec: 8, mp_levels: [64, 48, 32], budget_ratio: 0.75, ref: 64, avg_cycles: 48} + # MP fractions 由 evaluate/calibrate_mp_fractions.py(拉格朗日预算分配)解出, + # 不是自由参数、也不是等分。 + # 完整 baseline 矩阵(HPCA): fp16 + W{8,7,6,5,4}A{同} x {symm, asymm} = 11 组 + mp_levels_legacy: [128, 96, 64, 32] # 早期口径, 已被上表取代 + # 【fractions = 搜索问题(组内指示:比例自己搜)】 + # 约束: sum(f)=1, f≥0, dot(f, levels)=avg 目标 → 每个 avg 目标是单纯形上 + # 的一个 2 自由度切片。搜索协议: + # 1) 在切片上取网格(含边界组合,如 avg96 的 [128,64] 对半 / [96]=1.0 / + # [128,96,64,32] 加权),每组合快扫 (DPM10, n=8, diverse 样本); + # 2) 按 latent L2 排序,top-3 用 PNDM50 + 更大 n 复验; + # 3) 优胜组合回填到 precision_ladder.fractions,并存 results/mp_search/。 + # 行→档位的运行时分派按重要性排序(|x|.amax(-1) 分位数,scmp_llm 同款)。 + precision_ladder: + - {logic_bits: 8, avg_stoc_len: 192, policy: uniform, # int8 只 uniform + note: "非 halve 空间的名义档;halve 生效时 uniform=128 (2^7)"} + - {logic_bits: 7, avg_stoc_len: 96, policy: heterogeneous, + levels: [128, 96, 64, 32], fractions: calibrate_to_avg} + - {logic_bits: 6, avg_stoc_len: 48, policy: heterogeneous, + levels: [128, 96, 64, 32], fractions: calibrate_to_avg} + - {logic_bits: 5, avg_stoc_len: null, policy: heterogeneous, + levels: [128, 96, 64, 32], fractions: calibrate_to_avg} # avg 待组内给 + - {logic_bits: 4, avg_stoc_len: null, policy: heterogeneous, + levels: [128, 96, 64, 32], fractions: calibrate_to_avg} # avg 待组内给 + +# ============================================================================= +# 与规格兼容、已确认启用的优化(不改变上述硬件语义): +# per_row 量化粒度 : SC_LINEAR_GRANULARITY=per_row [已实装, +6dB 实证] +# halve 流长减半 : SC_HALVE=1 [已实装, 探针验证中] +# SmoothQuant : sc_matmul(smooth_scales=...) [接线中, α=0.5] +# chunk_d 内维分块 : 宽 D linear (fc2 D=4608) 用 [待接] +# MP 档位(异构) : 仅 logic<8 时启用, 见 precision_ladder [待接, 需校准] +# per-row QK : scmp_diffusion PR#6 语义 [待评估] +# 不启用: timewise/layerwise 部分覆盖(组内实际全覆盖跑法)、noise-model 代理 +# (仅限探索, 不入正式结果)。 +# ============================================================================= diff --git a/evaluate/calibrate_full_mp.py b/evaluate/calibrate_full_mp.py new file mode 100644 index 0000000..cc564c6 --- /dev/null +++ b/evaluate/calibrate_full_mp.py @@ -0,0 +1,212 @@ +"""Full scmp_llm-style MP calibration for the world model. + +Produces the three ingredients the LLM ladder actually uses (and which the +naive quantile port lacked): + + 1. salient-channel protection: per (op, block), the top channels by + E[x_j^2] * sum_o W[o,j]^2 * E[(dL/dy_o)^2] + (activation energy x gradient-weighted weight-column energy — the + gradient-weighted selector from scmp_llm calibrate_mp_thresholds), run at + a fixed high stream length, with row dispatch on the residual columns; + 2. per-module THRESHOLDS on the per-call min-max-normalised metric + (distribution-adaptive fractions, not fixed quantiles); + 3. budget bookkeeping that charges the protected columns' extra cycles to + the same global average so the uniform comparison stays fair. + +Phase 1 (GPU): teacher forward + pixel-space Hutchinson probes accumulating +per-input-channel x^2 and per-output-channel grad^2 for every target linear. +Phase 2 (CPU): combine with the SmoothQuant-consistent error grid to solve the +row thresholds under the residual budget and emit the deployment JSON. +""" +from __future__ import annotations + +import argparse, json, os +import numpy as np +import torch + +from evaluate.calibrate_mp_fractions import ( + TARGET_SUFFIXES, build_args, load_model, + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + compute_actions_for_slice, +) +from models.sc_integration import reconfigure, get_config + + +def gpu_phase(cli, device): + args = build_args(cli.eval_config, 50) + model = load_model(args, device) + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2"): + setattr(cfg, f"enable_{f}", False) + from diffusers.models import AutoencoderKL + from diffusers.schedulers import PNDMScheduler + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device) + vae.requires_grad_(False) + sched = PNDMScheduler.from_pretrained( + args.scheduler_path, beta_start=args.beta_start, beta_end=args.beta_end, + beta_schedule=args.beta_schedule, variance_type=args.variance_type) + sched.set_timesteps(50, device=device) + probe_ts = [sched.timesteps[int(f * 49)] for f in (0.2, 0.5, 0.8)] + + x2, g2, W2 = {}, {}, {} + hold = {} + hooks = [] + + def mk(name, mod): + def hook(_m, inp, out): + x = inp[0].detach().reshape(-1, inp[0].shape[-1]).float() + x2[name] = x2.get(name, 0) + x.pow(2).sum(0).cpu() + if out.requires_grad: + out.retain_grad() + hold[name] = out + return hook + + for name, mod in model.named_modules(): + if isinstance(mod, torch.nn.Linear) and name.endswith(TARGET_SUFFIXES): + hooks.append(mod.register_forward_hook(mk(name, mod))) + W2[name] = mod.weight.detach().float().pow(2).cpu() + + gen = torch.Generator(device="cpu").manual_seed(0) + for key in json.load(open(cli.keys_file))[: cli.num_samples]: + parts = key.split("_"); eid, start = "_".join(parts[:-2]), int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + x0 = torch.load(os.path.join(GT_LATENT_DIR, f"{key}.pt"), + weights_only=False, map_location=device).float().unsqueeze(0) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + act = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0).to(device) + for t in probe_ts: + noise = torch.randn_like(x0) + x_t = sched.add_noise(x0, noise, t.reshape(1)); x_t[:, :1] = x0[:, :1] + abar = sched.alphas_cumprod.to(device)[t.long()].float() + for _ in range(cli.probes): + hold.clear(); model.zero_grad(set_to_none=True) + out = model(x_t.clone(), actions=act, t=t.reshape(1).to(device), + mask_frame_num=1, use_fp16=False) + if isinstance(out, (tuple, list)): + out = out[0] + x0_hat = (x_t - torch.sqrt(1 - abar) * out) / torch.sqrt(abar) + fr = torch.randperm(x0_hat.shape[1], generator=gen)[:2] + pix = vae.decode(x0_hat[0, fr].float() / vae.config.scaling_factor).sample + (pix * torch.randn_like(pix)).sum().backward() + for name, o in hold.items(): + if o.grad is not None: + g = o.grad.detach().reshape(-1, o.shape[-1]).float() + g2[name] = g2.get(name, 0) + g.pow(2).sum(0).cpu() + print(f" {key} t={int(t)} ok", flush=True) + for h in hooks: + h.remove() + np.savez_compressed(cli.stats_out, + names=np.array(sorted(x2)), + **{f"x2::{n}": x2[n].numpy() for n in x2}, + **{f"g2::{n}": g2[n].numpy() for n in g2}, + **{f"w2sum::{n}": W2[n].numpy().sum(0) for n in W2}) # fallback (unweighted) + # gradient-weighted column energy: sum_o W[o,j]^2 g2[o] + np.savez_compressed(cli.stats_out.replace(".npz", "_sal.npz"), + names=np.array(sorted(x2)), + **{f"sal::{n}": (x2[n] * (W2[n] * g2[n][:, None]).sum(0)).numpy() + for n in x2 if n in g2}) + print("stats written", flush=True) + + +def assemble(cli): + g = np.load(cli.grid, allow_pickle=True) + E, grid_asc = g["errors"].astype(np.float64), [int(x) for x in g["grid"]] + mod, met, ref = g["module_idx"], g["row_metric"], g["ref_norm"] + gmods = [str(m) for m in g["modules"]] + od = np.argsort(grid_asc)[::-1] + grid = [grid_asc[i] for i in od] + sig = (E / np.maximum(ref[:, None], 1e-8))[:, od] + cur = np.maximum(sig - sig[:, :1], 0.0) ** 2 # delta_sigma2 + + sal = np.load(cli.grid.replace("mp_error_grid_sq2.npz", "") + + os.path.basename(cli.stats_out).replace(".npz", "_sal.npz"), + allow_pickle=True) if False else np.load( + cli.stats_out.replace(".npz", "_sal.npz"), allow_pickle=True) + + # protected channels + residual budget + protected = {} + p_frac_tot, n_mod = 0.0, 0 + for name in gmods: + key = f"sal::{name}" + if key not in sal: + continue + v = sal[key] + k = max(1, int(round(cli.protect_frac * v.shape[0]))) + protected[name] = np.argsort(-v)[:k].tolist() + p_frac_tot += k / v.shape[0]; n_mod += 1 + p = p_frac_tot / max(n_mod, 1) + resid_budget = (cli.budget - p * cli.protect_sl) / max(1 - p, 1e-6) + print(f"protected frac/module ~{p:.4f}, protect_sl={cli.protect_sl}, " + f"residual budget {resid_budget:.2f} (global {cli.budget})") + + import sys + sys.path.insert(0, ".") + from evaluate.search_mp_levels import _assign + a = _assign(cur, np.array(grid, float), resid_budget * cur.shape[0]) + + pm = {} + for mi, name in enumerate(gmods): + rows = np.where(mod == mi)[0] + if not len(rows): + continue + m = met[rows] + mn = (m - m.min()) / max(m.max() - m.min(), 1e-8) + lv_rows = a[rows] + ths = [] + for li in range(len(grid) - 1): # threshold between level li and li+1 + hi = mn[lv_rows <= li] + lo = mn[lv_rows > li] + if len(hi) == 0: + ths.append(1.0) + elif len(lo) == 0: + ths.append(0.0) + else: + ths.append(float((hi.min() + lo.max()) / 2)) + ths = sorted(ths, reverse=True) + pm[name] = {"thresholds": ths, + "protected": protected.get(name, []), + "protect_sl": cli.protect_sl, + "avg_cycles": float(np.mean([grid[i] for i in lv_rows])), + "invert": False} + cnt = np.bincount(a, minlength=len(grid)) + fr = (cnt / cnt.sum()).round(4) + j = int(np.argmax(fr)); fr[j] = round(fr[j] + (1.0 - fr.sum()), 10) + out = {"config_name": cli.name, "sc_prec": 8, "stoc_len_levels": grid, + "level_fractions": fr.tolist(), "target_avg_cycles": cli.budget, + "achieved_avg_cycles": round(float(np.dot(fr, grid)) * (1 - p) + + p * cli.protect_sl, 2), + "source": "full scmp_llm mechanism: thresholds + protected channels " + "+ delta_sigma2 relative currency", + "per_module_fractions": pm} + json.dump(out, open(cli.out, "w"), indent=2) + print(f"wrote {cli.out}") + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--phase", choices=["gpu", "assemble", "both"], default="both") + ap.add_argument("--eval_config", default="configs/evaluation/bridge/frame_ada_sc_full.yaml") + ap.add_argument("--keys_file", default="results/diverse_300.json") + ap.add_argument("--num_samples", type=int, default=2) + ap.add_argument("--probes", type=int, default=2) + ap.add_argument("--grid", default="results/mp_error_grid_sq2.npz") + ap.add_argument("--stats_out", default="results/channel_stats.npz") + ap.add_argument("--budget", type=float, default=96.0) + ap.add_argument("--protect_frac", type=float, default=0.01) + ap.add_argument("--protect_sl", type=int, default=128) + ap.add_argument("--name", default="sc_avg192_full") + ap.add_argument("--out", default="results/mp_fractions_sc_avg192_full.json") + cli = ap.parse_args() + if cli.phase in ("gpu", "both"): + gpu_phase(cli, torch.device("cuda:0")) + if cli.phase in ("assemble", "both"): + assemble(cli) + + +if __name__ == "__main__": + main() diff --git a/evaluate/calibrate_mp_fractions.py b/evaluate/calibrate_mp_fractions.py new file mode 100644 index 0000000..d885051 --- /dev/null +++ b/evaluate/calibrate_mp_fractions.py @@ -0,0 +1,215 @@ +"""Calibrate MP level fractions for a HPCA SC config on this world model. + +Port of the allocation core in scmp_llm's calibrate_mp_thresholds.py, reduced +to what we need: given mp_levels and a cycle budget (budget_ratio * ref), +decide what fraction of rows runs at each stream length. + +Method + 1. Teacher pass: run the model with SC disabled, hook the SC'd linears, and + capture real activation rows (per operator). + 2. Error curves: for each captured row, measure |SC(row) - FP(row)| at every + candidate stoc_len (the real kernel, not a surrogate). + 3. Allocation: Lagrangian relaxation — each row picks argmin(error + λ·cost), + binary-search λ so mean cost hits the budget. Fractions = level counts. + +Rows are ranked at runtime by |x|.amax(-1) (same metric as the dispatcher), so +the calibrated fractions translate directly into MPConfig.level_fractions. + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N python3 \ + evaluate/calibrate_mp_fractions.py --config_name sc_avg192 \ + --out results/mp_fractions_sc_avg192.json +""" +import argparse, json, os +import numpy as np +import torch +from diffusers.models import AutoencoderKL + +from scmp_kernels import sc_matmul +from scmp_kernels.sc.config_helpers import make_sobol_simple_config +from models.sc_integration import reconfigure, get_config +from evaluate.eval_local_n_samples import ( + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, +) + +# HPCA config table (scmp_llm hpca script; see configs/sc_spec.yaml). +# KEY: the level values ARE halved cycle counts (hpca line 13: "sc_prec=8, +# halve ON, tag value IS the cycle count"). So kernel sc_prec stays 8 for every +# config — "int7/int6" is the ISO-EQUIVALENT int width for that cycle budget +# (line 320: halved 128/96/64/48/32 -> int 8/8/7/7/6), NOT a lowered grid. +HPCA = { + "sc_int8": dict(sc_prec=8, levels=[128, 96, 64], ratio=1.00, ref=128), + "sc_avg192": dict(sc_prec=8, levels=[128, 96, 64], ratio=0.75, ref=128), + "sc_int7": dict(sc_prec=8, levels=[128, 64, 32], ratio=0.50, ref=128), + "sc_avg96": dict(sc_prec=8, levels=[64, 48, 32], ratio=0.75, ref=64), + "sc_int6": dict(sc_prec=8, levels=[64, 48, 32], ratio=0.50, ref=64), + # 6.32-bit MP tier (nominal L = 80 = 2 x 40 halved cycles). Levels are + # shifted down so the 40-cycle budget lands INSIDE [48, 32] — with the + # sc_avg96 level set [64,48,32] a 40 budget would still be interior, but + # anchoring at 48 keeps the same 3-level shape as the other MP tiers and + # avoids reusing a coarser grid than the budget needs. + "sc_avg80": dict(sc_prec=8, levels=[48, 40, 32], ratio=0.625, ref=64), + + # ---- level-set ablation ------------------------------------------------ + # The 3-level {ref, 0.75ref, 0.5ref} shape above spans only 2x, which caps + # how much budget MP can move: at target 96 at most 50% of rows can reach + # 128. The scmp_llm ladder uses 5-8 levels spanning ~4x for the same + # targets (its target-96 set, [128,96,64,48,32], is identical across 4B / + # 8B / 14B / 30B). These entries vary LEVEL COUNT and SPAN independently so + # the two can be told apart: + # _w5 = scmp_llm's set verbatim (5 levels, 4x span) + # _n5 = 5 levels at the OLD 2x span (isolates level count) + # _w7 = 7 levels, 8x span (pushes span further) + "sc_avg192_w5": dict(sc_prec=8, levels=[128, 96, 64, 48, 32], ratio=0.75, ref=128), + "sc_avg192_n5": dict(sc_prec=8, levels=[128, 112, 96, 80, 64], ratio=0.75, ref=128), + "sc_avg192_w7": dict(sc_prec=8, levels=[128, 96, 64, 48, 32, 24, 16], ratio=0.75, ref=128), + "sc_avg96_w5": dict(sc_prec=8, levels=[64, 48, 32, 24, 16], ratio=0.75, ref=64), + "sc_avg96_n5": dict(sc_prec=8, levels=[64, 56, 48, 40, 32], ratio=0.75, ref=64), + "sc_avg96_w7": dict(sc_prec=8, levels=[128, 96, 64, 48, 32, 24, 16], ratio=0.375, ref=128), +} +TARGET_SUFFIXES = ("attn.qkv", "attn.proj", "mlp.fc1", "mlp.fc2") + + +def cost_assignments(errors, costs, budget_total): + """errors [n_units, n_levels], costs [n_levels] -> level index per unit.""" + n = errors.shape[0] + if budget_total <= n * costs[-1]: + return np.full(n, len(costs) - 1, dtype=np.int64) + if budget_total >= n * costs[0]: + return np.zeros(n, dtype=np.int64) + + def solve(lmbd): + a = (errors + lmbd * costs[None, :]).argmin(axis=1) + return a, float(costs[a].sum()) + + lo, hi = 0.0, 1.0 + _, c = solve(hi) + while c > budget_total and hi < 1e6: + hi *= 2.0 + _, c = solve(hi) + best = np.zeros(n, dtype=np.int64) + for _ in range(64): + mid = 0.5 * (lo + hi) + best, c = solve(mid) + if c > budget_total: + lo = mid + else: + hi = mid + return best + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config_name", required=True, choices=list(HPCA)) + p.add_argument("--eval_config", default="configs/evaluation/bridge/frame_ada_sc_full.yaml") + p.add_argument("--keys_file", default="results/diverse_300.json") + p.add_argument("--num_samples", type=int, default=2) + p.add_argument("--inference_steps", type=int, default=10) + p.add_argument("--max_rows", type=int, default=4096, help="rows sampled per operator") + p.add_argument("--out", required=True) + cli = p.parse_args() + spec = HPCA[cli.config_name] + levels = spec["levels"]; sc_prec = spec["sc_prec"] + budget_per_row = spec["ratio"] * spec["ref"] + + args = build_args(cli.eval_config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2"): + setattr(cfg, f"enable_{f}", False) # teacher pass: pure FP + + # ---- capture activation rows from the SC'd linears ---- + caps = {} + hooks = [] + for name, mod in model.named_modules(): + if isinstance(mod, torch.nn.Linear) and name.endswith(TARGET_SUFFIXES): + def mk(n, m): + def hook(_m, inp, _out): + x = inp[0].detach().reshape(-1, inp[0].shape[-1]).float() + keep = caps.setdefault(n, []) + if sum(t.shape[0] for t in keep) < 512: + idx = torch.randperm(x.shape[0], device=x.device)[:64] + keep.append(x[idx].cpu()) + return hook + hooks.append(mod.register_forward_hook(mk(name, mod))) + + pipe = make_pipe(args, vae, model, "DPM") + keys = json.load(open(cli.keys_file))[: cli.num_samples] + for k in keys: + parts = k.split("_"); eid = "_".join(parts[:-2]); start = int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + gt = torch.load(os.path.join(GT_LATENT_DIR, f"{k}.pt"), weights_only=False, map_location=device) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + act = torch.from_numpy(compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + with torch.no_grad(): + pipe(act.to(device).float(), mask_x=gt[0:1].unsqueeze(0).to(device).float(), + video_length=args.num_frames, height=args.video_size[0], width=args.video_size[1], + num_inference_steps=cli.inference_steps, guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only") + print(f" teacher pass {k}", flush=True) + for h in hooks: + h.remove() + + # ---- per-row error at each level (real SC kernel) ---- + named = dict(model.named_modules()) + all_err, all_metric = [], [] + for name, chunks in caps.items(): + X = torch.cat(chunks, 0)[: cli.max_rows].to(device) + W = named[name].weight.detach().float() + ref_out = X @ W.t() + errs = [] + for L in levels: + with torch.no_grad(): + y = sc_matmul(X, W, granularity="per_row", mode="bipolar", + sc_prec=sc_prec, stoc_len=L, + config=make_sobol_simple_config(X.shape[-1], X.shape[-1], sc_prec), + halve_bipolar_stoc_len=True) + errs.append(((y - ref_out) ** 2).mean(dim=-1).sqrt().cpu().numpy()) + all_err.append(np.stack(errs, 1)) # [rows, n_levels] + all_metric.append(X.abs().amax(-1).cpu().numpy()) + print(f" error curve {name}: rows={X.shape[0]}", flush=True) + + E = np.concatenate(all_err, 0) + costs = np.array(levels, dtype=np.float64) + assign = cost_assignments(E, costs, budget_per_row * E.shape[0]) + counts = np.bincount(assign, minlength=len(levels)) + fractions = (counts / counts.sum()).tolist() + achieved = float(np.dot(fractions, levels)) + + # The Lagrangian above already lets budget FLOW ACROSS modules: a module + # with steeper error curves takes more of its rows at the high levels. + # Collapsing `assign` to one global fraction triple throws that away and + # spends an identical average on every (operator, block) — which is why a + # global-fraction MP schedule measured no better than uniform at matched + # budget. Keep the per-module split the solver actually produced. + per_module, off = {}, 0 + for (name, _chunks), err in zip(caps.items(), all_err): + n_rows = err.shape[0] + c = np.bincount(assign[off:off + n_rows], minlength=len(levels)) + f = (c / max(c.sum(), 1)).tolist() + per_module[name] = {"level_fractions": [round(v, 4) for v in f], + "avg_cycles": round(float(np.dot(f, levels)), 2), + "n_rows": int(n_rows)} + off += n_rows + assert off == E.shape[0], f"row bookkeeping mismatch: {off} vs {E.shape[0]}" + + out = {"config_name": cli.config_name, "sc_prec": sc_prec, "stoc_len_levels": levels, + "level_fractions": [round(f, 4) for f in fractions], + "target_avg_cycles": budget_per_row, "achieved_avg_cycles": round(achieved, 2), + "n_rows_calibrated": int(E.shape[0]), + "per_module_fractions": per_module} + os.makedirs(os.path.dirname(cli.out) or ".", exist_ok=True) + json.dump(out, open(cli.out, "w"), indent=2) + print(json.dumps(out, indent=2), flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/calibrate_smoothquant.py b/evaluate/calibrate_smoothquant.py new file mode 100644 index 0000000..e43acc0 --- /dev/null +++ b/evaluate/calibrate_smoothquant.py @@ -0,0 +1,97 @@ +"""SmoothQuant calibration for the SC'd linears (qkv / proj / fc1 / fc2). + +Runs N calibration clips through the FP model (attention_mode from config but +all SC disabled), hooks every to-be-SC'd nn.Linear to accumulate per-channel +activation |max|, then computes smooth scales s = act^alpha / w^(1-alpha) +via scmp_kernels.quant and saves {module_name: (D,) tensor} to a .pt file. + +At eval time pass SC_SMOOTH_SCALES= (loader in eval_local_n_samples +attaches tensors as module._sc_smooth_scales; sc_linear_forward picks it up). + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N \ + python3 evaluate/calibrate_smoothquant.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --keys_file results/diverse_300.json --num_samples 8 --alpha 0.5 \ + --out results/smoothquant_scales.pt +""" +import argparse, json, os +import numpy as np, torch +from diffusers.models import AutoencoderKL + +from scmp_kernels.quant import accumulate_act_scales, compute_smooth_scales +from models.sc_integration import reconfigure, get_config +from evaluate.eval_local_n_samples import ( + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, +) + +TARGET_SUFFIXES = ("attn.qkv", "attn.proj", "mlp.fc1", "mlp.fc2") + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config", required=True) + p.add_argument("--keys_file", required=True) + p.add_argument("--num_samples", type=int, default=8) + p.add_argument("--inference_steps", type=int, default=10) + p.add_argument("--alpha", type=float, default=0.5) + p.add_argument("--out", required=True) + cli = p.parse_args() + + args = build_args(cli.config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + + # calibration must see FP activations: disable every SC op + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2"): + setattr(cfg, f"enable_{f}", False) + + # hook target linears: accumulate per-channel |max| of inputs + act_scales, hooks = {}, [] + for name, mod in model.named_modules(): + if isinstance(mod, torch.nn.Linear) and name.endswith(TARGET_SUFFIXES): + def make_hook(n): + def hook(m, inp, out): + act_scales[n] = accumulate_act_scales( + inp[0].float(), act_scales.get(n)) + return hook + hooks.append(mod.register_forward_hook(make_hook(name))) + print(f"hooked {len(hooks)} linears", flush=True) + + pipe = make_pipe(args, vae, model, "DPM") + keys = json.load(open(cli.keys_file))[: cli.num_samples] + for k in keys: + parts = k.split("_"); eid = "_".join(parts[:-2]); start = int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + gt_lat = torch.load(os.path.join(GT_LATENT_DIR, f"{k}.pt"), weights_only=False, map_location=device) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + actions = torch.from_numpy(compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + with torch.no_grad(): + pipe(actions.to(device).float(), mask_x=gt_lat[0:1].unsqueeze(0).to(device).float(), + video_length=args.num_frames, height=args.video_size[0], width=args.video_size[1], + num_inference_steps=cli.inference_steps, guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only") + print(f" calibrated on {k}", flush=True) + for h in hooks: + h.remove() + + scales = {} + for name, mod in model.named_modules(): + if name in act_scales: + scales[name] = compute_smooth_scales( + act_scales[name].to(device), mod.weight.detach().float(), alpha=cli.alpha).cpu() + os.makedirs(os.path.dirname(cli.out) or ".", exist_ok=True) + torch.save({"alpha": cli.alpha, "scales": scales}, cli.out) + print(f"saved {len(scales)} scale vectors -> {cli.out}", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/compute_fid_fvd_stream.py b/evaluate/compute_fid_fvd_stream.py new file mode 100644 index 0000000..e4f9f05 --- /dev/null +++ b/evaluate/compute_fid_fvd_stream.py @@ -0,0 +1,170 @@ +"""Streaming FID + FVD for a directory of generated mp4s (no frame dumps). + +FID: frames -> vendored pytorch-fid InceptionV3 (local pt_inception weights) + -> accumulate mu/sigma -> Frechet vs bridge test_fid_cache.npz. +FVD: 16-frame clip per mp4 -> i3d torchscript (StyleGAN-V) features + -> mu/sigma vs GT clip features (GT stats cached to disk for reuse). + +Everything is streamed; nothing is written except the output json (and the +GT FVD stats cache). Safe on a full disk. + +Usage: + PYTHONPATH=.:pytorch-fid/src CUDA_VISIBLE_DEVICES=N python3 evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/final_sc_full/videos \ + --out results/fidfvd_final_sc_full.json [--limit 64] +""" +import argparse, json, os +import numpy as np +import torch +import imageio.v2 as imageio +from scipy import linalg + +BRIDGE = os.environ.get("BRIDGE_ROOT", "/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge") +GT_DIR = f"{BRIDGE}/evaluation_videos/test_sample_videos" +FID_CACHE = f"{BRIDGE}/evaluation_cache/test_fid_cache.npz" +# Detector weights live next to the dataset (dataset_dir/evaluation_model) — +# overridable so the same script runs on any machine. +EM = os.environ.get("SCMP_EVAL_MODEL_DIR", os.path.join(os.path.dirname(BRIDGE), "evaluation_model")) +INCEPTION_PTH = f"{EM}/pt_inception-2015-12-05-6726825d.pth" +I3D_PT = f"{EM}/i3d_torchscript.pt" +GT_FVD_STATS = os.environ.get("SCMP_GT_FVD_STATS", "results/gt_fvd_stats_bridge.npz") + + +def frechet(mu1, s1, mu2, s2, eps=1e-6): + diff = mu1 - mu2 + covmean, _ = linalg.sqrtm(s1.dot(s2), disp=False) + if not np.isfinite(covmean).all(): + covmean = linalg.sqrtm((s1 + eps * np.eye(s1.shape[0])).dot(s2 + eps * np.eye(s2.shape[0]))) + if np.iscomplexobj(covmean): + covmean = covmean.real + return float(diff.dot(diff) + np.trace(s1) + np.trace(s2) - 2 * np.trace(covmean)) + + +def load_inception(device): + import pytorch_fid.inception as pi + import torch.hub + orig = torch.hub.load_state_dict_from_url + torch.hub.load_state_dict_from_url = lambda *a, **k: torch.load(INCEPTION_PTH, map_location="cpu", weights_only=False) + try: + model = pi.InceptionV3([pi.InceptionV3.BLOCK_INDEX_BY_DIM[2048]]).to(device).eval() + finally: + torch.hub.load_state_dict_from_url = orig + return model + + +def video_frames(path): + r = imageio.get_reader(path) + for fr in r: + yield fr + r.close() + + +def fid_stats_for_dir(mp4s, model, device, bs=64): + feats = [] + buf = [] + with torch.no_grad(): + for p in mp4s: + for fr in video_frames(p): + buf.append(torch.from_numpy(fr.copy()).permute(2, 0, 1).float() / 255.0) + if len(buf) == bs: + x = torch.stack(buf).to(device); buf = [] + feats.append(model(x)[0].squeeze(-1).squeeze(-1).cpu().numpy()) + if buf: + x = torch.stack(buf).to(device) + feats.append(model(x)[0].squeeze(-1).squeeze(-1).cpu().numpy()) + f = np.concatenate(feats, 0) + return f.mean(0), np.cov(f, rowvar=False), len(f) + + +def fvd_feats_for_dir(mp4s, i3d, device, bs=16, n_frames=16): + feats, buf, skipped = [], [], 0 + # Official StyleGAN-V FVD: rescale=True means i3d normalizes internally from + # raw [0,255] pixels — so we must feed uint8-range floats, NOT pre-scaled. + kw = dict(rescale=True, resize=True, return_features=True) + with torch.no_grad(): + for p in mp4s: + try: + frs = [torch.from_numpy(fr.copy()).permute(2, 0, 1) for fr in video_frames(p)] + except Exception as e: + print(f" [fvd] skip unreadable {os.path.basename(p)}: {e}", flush=True) + skipped += 1; continue + if len(frs) < n_frames: # uniform clip length is required to batch + skipped += 1; continue + v = torch.stack(frs[:n_frames], 1).float() # (C,16,H,W) in [0,255] + buf.append(v) + if len(buf) == bs: + feats.append(i3d(torch.stack(buf).to(device), **kw).cpu().numpy()); buf = [] + if buf: + feats.append(i3d(torch.stack(buf).to(device), **kw).cpu().numpy()) + if skipped: + print(f" [fvd] skipped {skipped}/{len(mp4s)} videos (short/unreadable)", flush=True) + f = np.concatenate(feats, 0) + return f + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--pred_dir", required=True) + ap.add_argument("--out", required=True) + ap.add_argument("--limit", type=int, default=None) + ap.add_argument("--fid_precomputed", type=float, default=None, + help="reuse an already-computed FID (skip the inception pass)") + cli = ap.parse_args() + device = torch.device("cuda:0") + + preds = sorted(f"{cli.pred_dir}/{f}" for f in os.listdir(cli.pred_dir) if f.endswith(".mp4")) + if cli.limit: + preds = preds[: cli.limit] + keys = [os.path.basename(p) for p in preds] + gts = [f"{GT_DIR}/{k}" for k in keys if os.path.exists(f"{GT_DIR}/{k}")] + print(f"pred={len(preds)} gt_matched={len(gts)}", flush=True) + + out = {"pred_dir": cli.pred_dir, "n_videos": len(preds)} + + # ---- FID ---- + if cli.fid_precomputed is not None: + out["fid"] = cli.fid_precomputed + print(f"FID = {out['fid']} (precomputed, reused)", flush=True) + else: + inc = load_inception(device) + mu_p, s_p, nf = fid_stats_for_dir(preds, inc, device) + cache = np.load(FID_CACHE) + mu_r, s_r = cache["mu"], cache["sigma"] + out["fid"] = round(frechet(mu_p, s_p, mu_r, s_r), 3) + out["fid_frames"] = nf + print(f"FID = {out['fid']} ({nf} frames)", flush=True) + del inc; torch.cuda.empty_cache() + json.dump(out, open(cli.out, "w"), indent=2) # incremental save (FID survives an FVD crash) + + # ---- FVD ---- + # feature extraction is chunked so a full 2946-video run never holds more + # than CHUNK videos' activations at once (the un-chunked version OOM'd). + CHUNK = 300 + i3d = torch.jit.load(I3D_PT).to(device).eval() + + def stats_chunked(paths, label): + parts = [] + for i in range(0, len(paths), CHUNK): + f = fvd_feats_for_dir(paths[i:i + CHUNK], i3d, device) + parts.append(f) + print(f" [{label}] {min(i+CHUNK, len(paths))}/{len(paths)}", flush=True) + allf = np.concatenate(parts, 0) + return allf.mean(0), np.cov(allf, rowvar=False) + + if os.path.exists(GT_FVD_STATS) and cli.limit is None: + g = np.load(GT_FVD_STATS); mu_g, s_g = g["mu"], g["sigma"] + print("GT FVD stats: cached", flush=True) + else: + mu_g, s_g = stats_chunked(gts, "gt") + if cli.limit is None: + np.savez(GT_FVD_STATS, mu=mu_g, sigma=s_g) + mu_p2, s_p2 = stats_chunked(preds, "pred") + out["fvd"] = round(frechet(mu_p2, s_p2, mu_g, s_g), 3) + print(f"FVD = {out['fvd']}", flush=True) + + json.dump(out, open(cli.out, "w"), indent=2) + print("saved", cli.out, flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/eval_local_n_samples.py b/evaluate/eval_local_n_samples.py index 982324c..00c3747 100644 --- a/evaluate/eval_local_n_samples.py +++ b/evaluate/eval_local_n_samples.py @@ -45,7 +45,8 @@ from util import update_paths -BRIDGE_ROOT = "/home/dingqy/Bench/IRASim/robotdata/opensource_robotdata/bridge" +BRIDGE_ROOT = os.environ.get( + "BRIDGE_ROOT", "/home/dingqy/Bench/IRASim/robotdata/opensource_robotdata/bridge") GT_LATENT_DIR = f"{BRIDGE_ROOT}/evaluation_latent_videos/test_sample_latent_videos" GT_VIDEO_DIR = f"{BRIDGE_ROOT}/evaluation_videos/test_sample_videos" ANNOT_DIR = f"{BRIDGE_ROOT}/annotation/test" @@ -174,16 +175,44 @@ def main(): p.add_argument("--scheduler", choices=["PNDM", "DPM"], default="PNDM") p.add_argument("--shard", type=int, default=0) p.add_argument("--num_shards", type=int, default=1) - p.add_argument("--out_root", default="/home/dingqy/Bench/IRASim/results/local_n_eval") + p.add_argument("--keys_file", default=None, + help="JSON list of sample keys to evaluate (e.g. diverse_300.json); " + "overrides the default sorted-first-N selection") + p.add_argument("--out_root", default=os.environ.get( + "EVAL_OUT_ROOT", "/home/dingqy/Bench/IRASim/results/local_n_eval")) + p.add_argument("--naive_int8", action="store_true", + help="replace SC kernels with naive per-tensor int8 fake-quant " + "(uniform quantization baseline); ops still selected by attention_mode") + p.add_argument("--naive_bits", type=int, default=8, + help="bit width for --naive_int8 (WxAx, x=bits); 8 reproduces the original baseline") + p.add_argument("--naive_asymm", action="store_true", + help="use asymmetric (zero-point) quantization instead of symmetric for --naive_int8") cli = p.parse_args() args = build_args(cli.config, cli.inference_steps) skip_map = parse_skip(cli.skip) + if cli.naive_int8: + from evaluate.eval_with_naive_int8 import install_naive_int8_patches + install_naive_int8_patches(bits=cli.naive_bits, asymm=cli.naive_asymm) + b = cli.naive_bits + print(f"naive W{b}A{b}_{'asymm' if cli.naive_asymm else 'symm'} patches " + f"installed over sc_* kernels", flush=True) + device = torch.device("cuda:0") vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() vae.requires_grad_(False) model = load_model(args, device) + sq_path = os.environ.get("SC_SMOOTH_SCALES") + if sq_path: # SmoothQuant: attach calibrated per-channel scales to linears + payload = torch.load(sq_path, map_location=device, weights_only=False) + named = dict(model.named_modules()) + n_att = 0 + for name, s in payload["scales"].items(): + if name in named: + named[name]._sc_smooth_scales = s.to(device).float() + n_att += 1 + print(f"smoothquant: attached {n_att} scale vectors (alpha={payload['alpha']})", flush=True) reconfigure(args.attention_mode) clear_skip_blocks() for op, blocks in skip_map.items(): @@ -193,7 +222,11 @@ def main(): f"steps={args.infer_num_sampling_steps} sched={cli.scheduler}", flush=True) # Decide which samples to handle this shard. - all_files = sorted(f for f in os.listdir(GT_LATENT_DIR) if f.endswith(".pt"))[: cli.num_samples] + if getattr(cli, "keys_file", None): # explicit diverse-sample list + keys = json.load(open(cli.keys_file))[: cli.num_samples] + all_files = [f"{k}.pt" for k in keys] + else: + all_files = sorted(f for f in os.listdir(GT_LATENT_DIR) if f.endswith(".pt"))[: cli.num_samples] shard_files = all_files[cli.shard::cli.num_shards] print(f"[shard {cli.shard}] {len(shard_files)}/{len(all_files)} samples", flush=True) @@ -209,6 +242,11 @@ def main(): for fn in shard_files: eid, cam, start = parse_key(fn) key = f"{eid}_{cam}_{start}" + done_path = os.path.join(met_dir, f"{key}.json") + if os.path.exists(done_path): # resume: already computed in a prior run + with open(done_path) as f: + metrics.append(json.load(f)) + continue ann_path = os.path.join(ANNOT_DIR, f"{eid}.json") if not os.path.exists(ann_path): print(f" [{key}] skip — no annotation", flush=True) diff --git a/evaluate/eval_with_naive_int8.py b/evaluate/eval_with_naive_int8.py index 0100024..35888da 100644 --- a/evaluate/eval_with_naive_int8.py +++ b/evaluate/eval_with_naive_int8.py @@ -36,13 +36,33 @@ import imageio +# Bit width / symmetry for the integer baseline. Set by install_naive_int8_patches(); +# the defaults reproduce the original per-tensor symmetric int8 path exactly. +_QUANT_BITS = 8 +_QUANT_ASYMM = False + + def _q_int8_per_tensor(x: torch.Tensor) -> torch.Tensor: - """Per-tensor symmetric int8 fake-quant of x. Returns dequantized fp32 tensor.""" + """Per-tensor fake-quant of x at _QUANT_BITS. Returns dequantized fp32 tensor. + + symmetric: q = round(x/s).clamp(-qmax, qmax), s = max|x| / qmax, qmax = 2^(b-1)-1 + asymmetric: q = (round(x/s)+z).clamp(0, qmax), s = (max-min) / qmax, qmax = 2^b - 1 + """ if x.numel() == 0: return x.float() - amax = x.detach().abs().amax().clamp_min(1e-8) - scale = amax / 127.0 - q = (x.float() / scale).round().clamp(-127, 127) + xf = x.float() + if _QUANT_ASYMM: + qmax = float(2 ** _QUANT_BITS - 1) + xmin = xf.detach().amin() + xmax = xf.detach().amax() + scale = ((xmax - xmin) / qmax).clamp_min(1e-8) + zp = (-xmin / scale).round() + q = ((xf / scale).round() + zp).clamp(0, qmax) + return (q - zp) * scale + qmax = float(2 ** (_QUANT_BITS - 1) - 1) + amax = xf.detach().abs().amax().clamp_min(1e-8) + scale = amax / qmax + q = (xf / scale).round().clamp(-qmax, qmax) return q * scale @@ -66,7 +86,12 @@ def naive_int8_linear_forward(x: torch.Tensor, linear, sc_prec: int = 8, stoc_le return y.to(x.dtype) -def install_naive_int8_patches(): +def install_naive_int8_patches(bits: int = 8, asymm: bool = False): + """Swap the SC kernels for plain WxAx fake-quant matmuls (x = `bits`).""" + global _QUANT_BITS, _QUANT_ASYMM + if not 2 <= bits <= 8: + raise ValueError(f"naive quant bits must be in [2,8], got {bits}") + _QUANT_BITS, _QUANT_ASYMM = bits, asymm sc_attention.sc_qk_matmul = naive_int8_qk sc_attention.sc_av_matmul = naive_int8_av sc_linear.sc_linear_forward = naive_int8_linear_forward diff --git a/evaluate/final_recipe_decider.py b/evaluate/final_recipe_decider.py new file mode 100644 index 0000000..ad5b49e --- /dev/null +++ b/evaluate/final_recipe_decider.py @@ -0,0 +1,86 @@ +"""Final SC recipe decider: combine every optimization that adds value. + +Waits for: results/skip_winner.json (skip arbitration) and the nb_sq probe +(SmoothQuant on per_row+halve). If SQ is positive, runs one combined probe +(SQ + winning skip) so the exact final recipe is validated end-to-end before +committing the multi-day full run. Writes results/final_sc_recipe.json — +the gated gpu_scheduler_final.py picks it up and launches the SC line. + +Run: cd worldmodel && PYTHONPATH=. nohup python evaluate/final_recipe_decider.py & +""" +import json, os, subprocess, time + +ROOT = "/home/qiuyid/scmp_worldmodel" +PY = "/home/qiuyid/.conda/envs/scmp/bin/python" +BRIDGE = f"{ROOT}/robotdata/opensource_robotdata/bridge" +SQ_FILE = f"{ROOT}/results/smoothquant_scales.pt" +os.chdir(ROOT) + + +def mean_of(tag): + f = f"results/line_eval/{tag}/summary_shard_0.json" + if not os.path.exists(f): + return None + d = json.load(open(f)) + return d["mean_psnr"], -d["mean_l2"] + + +def wait_for(path, proc_pat, label): + while not os.path.exists(path): + r = subprocess.run(["pgrep", "-f", proc_pat], capture_output=True) + if r.returncode != 0: + print(f"[decider] {label}: process gone without result", flush=True) + return os.path.exists(path) + time.sleep(60) + return True + + +def run_probe(tag, skip, use_sq): + env = dict(os.environ, BRIDGE_ROOT=BRIDGE, EVAL_OUT_ROOT=f"{ROOT}/results/line_eval", + PYTHONPATH=".", CUDA_VISIBLE_DEVICES="3", + SC_LINEAR_GRANULARITY="per_row", SC_HALVE="1") + if use_sq: + env["SC_SMOOTH_SCALES"] = SQ_FILE + cmd = [PY, "evaluate/eval_local_n_samples.py", + "--config", "configs/evaluation/bridge/frame_ada_sc_full.yaml", + "--tag", tag, "--num_samples", "8", "--inference_steps", "10", "--scheduler", "DPM"] + if skip: + cmd += ["--skip", skip] + print(f"[decider] probing {tag} ...", flush=True) + subprocess.run(cmd, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + return mean_of(tag) + + +def main(): + wait_for("results/skip_winner.json", "tag nb_skip17_final", "skip winner") + wait_for("results/line_eval/nb_sq/summary_shard_0.json", "tag nb_sq", "sq probe") + + sw = json.load(open("results/skip_winner.json")) if os.path.exists("results/skip_winner.json") \ + else {"winner": "q_perrow_halve", "skip": ""} + base = mean_of("q_perrow_halve") + sq = mean_of("nb_sq") + skip_str = sw["skip"] + use_sq = bool(sq and base and sq[0] > base[0]) + print(f"[decider] base={base} sq={sq} use_sq={use_sq} skip_winner={sw['winner']}", flush=True) + + # 用户指令: full 线必须带 skip。候选只在"带 skip"的变体里选, + # 唯一自由度是 SmoothQuant 开/关(组合探针实测决定)。 + cands = {} + cands[(False, skip_str)] = mean_of(sw["winner"]) + if use_sq: + cands[(True, skip_str)] = run_probe("nb_sq_skip", skip_str, True) + + best = max((v[0], v[1], k) for k, v in cands.items() if v) + use_sq_f, skip_f = best[2] + env = {"SC_LINEAR_GRANULARITY": "per_row", "SC_HALVE": "1"} + if use_sq_f: + env["SC_SMOOTH_SCALES"] = SQ_FILE + recipe = {"env": env, "skip": skip_f, + "decision_table": {f"sq={k[0]},skip={bool(k[1])}": v for k, v in cands.items() if v}, + "chosen": {"sq": use_sq_f, "skip": bool(skip_f), "psnr": best[0]}} + json.dump(recipe, open("results/final_sc_recipe.json", "w"), indent=2) + print(f"[decider] RECIPE WRITTEN: sq={use_sq_f} skip='{skip_f}' psnr={best[0]}", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/gpu_scheduler.py b/evaluate/gpu_scheduler.py new file mode 100644 index 0000000..ecacc4a --- /dev/null +++ b/evaluate/gpu_scheduler.py @@ -0,0 +1,108 @@ +"""GPU auto-grab scheduler for the n=300 per-block sensitivity sweep. + +Watches every GPU; whenever one is free (enough free memory + low util and not +already ours), it launches the next pending task on it. Tasks are (block, +key-slice) units; per-sample result files make everything resume-safe, so the +scheduler can die/restart or re-dispatch freely without recomputation. + +Blocks: -1 (reference, no skip) + 0..27 => 29 configs. +Each config runs over the 300 diverse samples, sliced into CHUNK-sized tasks. + +Run under nohup so it survives the conversation: + cd /home/qiuyid/scmp_worldmodel && nohup PYTHONPATH=. \ + /home/qiuyid/.conda/envs/scmp/bin/python evaluate/gpu_scheduler.py \ + > /edrive2/qiuyid/sens300_sched.log 2>&1 & disown +""" +import json, os, subprocess, time + +ROOT = "/home/qiuyid/scmp_worldmodel" +PY = "/home/qiuyid/.conda/envs/scmp/bin/python" +CONFIG = "configs/evaluation/bridge/frame_ada_sc_full.yaml" +KEYS_FILE = f"{ROOT}/results/diverse_300.json" +OUT_DIR = "/edrive2/qiuyid/sens300" # persistent (edrive2) +BRIDGE = "/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge" +DEPTH = 28 +CHUNK = 15 # samples per task (~3h each @PNDM50) +FREE_MIN_MIB = 22000 # need ~20G for eval + margin +UTIL_MAX = 40 # don't steal a GPU someone is actively using +POLL_SEC = 30 + +os.chdir(ROOT) +os.makedirs(OUT_DIR, exist_ok=True) +keys = json.load(open(KEYS_FILE)) +N = len(keys) +BLOCKS = [-1] + list(range(DEPTH)) # -1 = reference + +TASKS = [] # (block, start, end) +for b in BLOCKS: + for s in range(0, N, CHUNK): + TASKS.append((b, s, min(s + CHUNK, N))) + + +def task_done(t): + b, s, e = t + bdir = os.path.join(OUT_DIR, f"block_{b}") + return all(os.path.exists(os.path.join(bdir, f"{keys[i]}.json")) for i in range(s, e)) + + +def gpu_status(): + try: + out = subprocess.check_output( + ["nvidia-smi", "--query-gpu=index,memory.free,utilization.gpu", + "--format=csv,noheader,nounits"], timeout=30).decode() + except Exception: + return {} + st = {} + for line in out.strip().splitlines(): + i, free, util = [x.strip() for x in line.split(",")] + st[int(i)] = (int(free), int(util)) + return st + + +def launch(gpu, task): + b, s, e = task + log = open(os.path.join(OUT_DIR, f"sched_g{gpu}_b{b}_{s}.log"), "w") + env = dict(os.environ, CUDA_VISIBLE_DEVICES=str(gpu), BRIDGE_ROOT=BRIDGE, PYTHONPATH=".") + proc = subprocess.Popen( + [PY, "evaluate/sensitivity_shard.py", "--config", CONFIG, + "--block", str(b), "--keys_file", KEYS_FILE, + "--key_start", str(s), "--key_end", str(e), + "--inference_steps", "50", "--scheduler", "PNDM", "--out_dir", OUT_DIR], + env=env, stdout=log, stderr=subprocess.STDOUT) + return proc + + +def main(): + running = {} # gpu -> (proc, task) + print(f"scheduler start: {len(TASKS)} tasks ({len(BLOCKS)} blocks x {N} samples / {CHUNK})", flush=True) + while True: + # reap finished + for g in list(running): + proc, _ = running[g] + if proc.poll() is not None: + running.pop(g) + pending = [t for t in TASKS if not task_done(t)] + if not pending and not running: + print("ALL TASKS DONE", flush=True) + break + busy_tasks = {t for _, t in running.values()} + st = gpu_status() + for g, (free, util) in sorted(st.items()): + if g in running: + continue + if free >= FREE_MIN_MIB and util <= UTIL_MAX: + nxt = next((t for t in pending if t not in busy_tasks), None) + if nxt is None: + break + proc = launch(g, nxt) + running[g] = (proc, nxt) + busy_tasks.add(nxt) + b, s, e = nxt + print(f"[{time.strftime('%m-%d %H:%M:%S')}] GPU{g} <- block{b} keys[{s}:{e}] " + f"(free={free}MiB util={util}%) running={len(running)} pending={len(pending)-1}", + flush=True) + time.sleep(POLL_SEC) + + +if __name__ == "__main__": + main() diff --git a/evaluate/gpu_scheduler_final.py b/evaluate/gpu_scheduler_final.py new file mode 100644 index 0000000..d9a7dd4 --- /dev/null +++ b/evaluate/gpu_scheduler_final.py @@ -0,0 +1,129 @@ +"""GPU auto-grab scheduler for the FINAL full-test two lines (bridge, 2946): + + line 1: FP baseline (frame_ada.yaml, math) — dispatches immediately + line 2: SC final recipe (frame_ada_sc_full.yaml) — GATED on recipe file + +The SC line waits until results/final_sc_recipe.json exists, so the recipe +(env + skip string) can be finalized (LOI final top-17 + SmoothQuant/chunk_d +probe verdicts) without holding up the FP line. Recipe file schema: + {"env": {"SC_LINEAR_GRANULARITY": "per_row", "SC_HALVE": "1", ...}, + "skip": "mlp_fc1=...;mlp_fc2=...;qkv=..."} + +Both lines run PNDM 50-step over all test clips, sliced into NUM_SHARDS +shard-tasks (eval_local_n_samples --shard/--num_shards). Per-sample metric +files enable resume, so tasks can be re-dispatched freely. + + cd /home/qiuyid/scmp_worldmodel && PYTHONPATH=. nohup \ + /home/qiuyid/.conda/envs/scmp/bin/python evaluate/gpu_scheduler_final.py \ + > /edrive2/qiuyid/final_sched.log 2>&1 & disown +""" +import json, os, subprocess, time + +ROOT = "/home/qiuyid/scmp_worldmodel" +PY = "/home/qiuyid/.conda/envs/scmp/bin/python" +BRIDGE = f"{ROOT}/robotdata/opensource_robotdata/bridge" +OUT_ROOT = f"{ROOT}/results/local_n_eval" +RECIPE_FILE = f"{ROOT}/results/final_sc_recipe.json" +GT_LATENT_DIR = f"{BRIDGE}/evaluation_latent_videos/test_sample_latent_videos" +NUM_SHARDS = 24 +FREE_MIN_MIB = 22000 +UTIL_MAX = 40 +POLL_SEC = 45 +# 用户指定(2026-07-17, 按算力空闲修订): 排除别人算力占用最高的 GPU1/GPU7 +# (各被实跑 ~50% SM)。GPU0 上 vggt 只囤显存不占算力,拿回来用。 +EXCLUDE_GPUS = {1, 7} + +os.chdir(ROOT) +ALL_FILES = sorted(f for f in os.listdir(GT_LATENT_DIR) if f.endswith(".pt")) +N = len(ALL_FILES) + +LINES = [ + {"tag": "final_fp_full", "config": "configs/evaluation/bridge/frame_ada.yaml", + "env": {}, "skip": "", "gated": False}, + {"tag": "final_sc_full", "config": "configs/evaluation/bridge/frame_ada_sc_full.yaml", + "env": None, "skip": None, "gated": True}, # filled from RECIPE_FILE +] + + +def shard_keys(shard): + return [f[:-3] for f in ALL_FILES[shard::NUM_SHARDS]] + + +def task_done(line, shard): + met = os.path.join(OUT_ROOT, line["tag"], "metrics") + return all(os.path.exists(os.path.join(met, f"{k}.json")) for k in shard_keys(shard)) + + +def gpu_status(): + try: + out = subprocess.check_output( + ["nvidia-smi", "--query-gpu=index,memory.free,utilization.gpu", + "--format=csv,noheader,nounits"], timeout=30).decode() + except Exception: + return {} + st = {} + for ln in out.strip().splitlines(): + i, free, util = [x.strip() for x in ln.split(",")] + st[int(i)] = (int(free), int(util)) + return st + + +def load_recipe(line): + if not line["gated"] or line["env"] is not None: + return True + if not os.path.exists(RECIPE_FILE): + return False + r = json.load(open(RECIPE_FILE)) + line["env"] = r.get("env", {}) + line["skip"] = r.get("skip", "") + print(f"[recipe] SC line armed: env={line['env']} skip='{line['skip']}'", flush=True) + return True + + +def launch(gpu, line, shard): + log = open(f"/edrive2/qiuyid/final_{line['tag']}_s{shard}.log", "w") + env = dict(os.environ, CUDA_VISIBLE_DEVICES=str(gpu), BRIDGE_ROOT=BRIDGE, + EVAL_OUT_ROOT=OUT_ROOT, PYTHONPATH=".", **line["env"]) + cmd = [PY, "evaluate/eval_local_n_samples.py", "--config", line["config"], + "--tag", line["tag"], "--num_samples", str(N), + "--shard", str(shard), "--num_shards", str(NUM_SHARDS)] + if line["skip"]: + cmd += ["--skip", line["skip"]] + return subprocess.Popen(cmd, env=env, stdout=log, stderr=subprocess.STDOUT) + + +def main(): + running = {} + print(f"final scheduler: {N} clips x {len(LINES)} lines, {NUM_SHARDS} shards each", flush=True) + while True: + for g in list(running): + if running[g][0].poll() is not None: + running.pop(g) + pending = [] + for li, line in enumerate(LINES): + if line["gated"] and not load_recipe(line): + continue + for s in range(NUM_SHARDS): + if not task_done(line, s): + pending.append((li, s)) + if not pending and not running: + print("ALL FINAL TASKS DONE", flush=True) + break + busy = {t for _, t in running.values()} + for g, (free, util) in sorted(gpu_status().items()): + if g in EXCLUDE_GPUS or g in running: + continue + if free >= FREE_MIN_MIB and util <= UTIL_MAX: + nxt = next((t for t in pending if t not in busy), None) + if nxt is None: + break + li, s = nxt + running[g] = (launch(g, LINES[li], s), nxt) + busy.add(nxt) + print(f"[{time.strftime('%m-%d %H:%M:%S')}] GPU{g} <- {LINES[li]['tag']} shard{s} " + f"running={len(running)} pending={len(pending)-1}", flush=True) + time.sleep(POLL_SEC) + + +if __name__ == "__main__": + main() diff --git a/evaluate/gpu_scheduler_loi.py b/evaluate/gpu_scheduler_loi.py new file mode 100644 index 0000000..d08dc2f --- /dev/null +++ b/evaluate/gpu_scheduler_loi.py @@ -0,0 +1,105 @@ +"""GPU auto-grab scheduler for the leave-one-IN op-level sensitivity sweep +(aligned with the repo's original sensitivity_sweep.py method). + +Configs: fp reference + 6 ops x 28 blocks = 169. Each runs the 300 diverse +samples. Network is ~all-FP per config (~30-40s/sample), so chunks are large. +Per-sample result files make everything resume-safe. + +Run under nohup: + cd /home/qiuyid/scmp_worldmodel && PYTHONPATH=. nohup \ + /home/qiuyid/.conda/envs/scmp/bin/python evaluate/gpu_scheduler_loi.py \ + > /edrive2/qiuyid/sens300_loi_sched.log 2>&1 & disown +""" +import json, os, subprocess, time + +ROOT = "/home/qiuyid/scmp_worldmodel" +PY = "/home/qiuyid/.conda/envs/scmp/bin/python" +CONFIG = "configs/evaluation/bridge/frame_ada_sc_full.yaml" +KEYS_FILE = f"{ROOT}/results/diverse_300.json" +OUT_DIR = "/edrive2/qiuyid/sens300_loi" +BRIDGE = "/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge" +DEPTH = 28 +OPS = ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2") +CHUNK = 100 # ~35s/sample -> ~1h/task +FREE_MIN_MIB = 22000 +UTIL_MAX = 40 +POLL_SEC = 30 + +os.chdir(ROOT) +os.makedirs(OUT_DIR, exist_ok=True) +keys = json.load(open(KEYS_FILE)) +N = len(keys) + +CONFIGS = [("fp", -1)] + [(op, b) for op in OPS for b in range(DEPTH)] +TASKS = [] +for op, b in CONFIGS: + for s in range(0, N, CHUNK): + TASKS.append((op, b, s, min(s + CHUNK, N))) + + +def tag(op, b): + return "fp_ref" if op == "fp" else f"{op}_{b}" + + +def task_done(t): + op, b, s, e = t + d = os.path.join(OUT_DIR, f"loi_{tag(op, b)}") + return all(os.path.exists(os.path.join(d, f"{keys[i]}.json")) for i in range(s, e)) + + +def gpu_status(): + try: + out = subprocess.check_output( + ["nvidia-smi", "--query-gpu=index,memory.free,utilization.gpu", + "--format=csv,noheader,nounits"], timeout=30).decode() + except Exception: + return {} + st = {} + for line in out.strip().splitlines(): + i, free, util = [x.strip() for x in line.split(",")] + st[int(i)] = (int(free), int(util)) + return st + + +def launch(gpu, task): + op, b, s, e = task + log = open(os.path.join(OUT_DIR, f"sched_g{gpu}_{tag(op, b)}_{s}.log"), "w") + env = dict(os.environ, CUDA_VISIBLE_DEVICES=str(gpu), BRIDGE_ROOT=BRIDGE, PYTHONPATH=".") + return subprocess.Popen( + [PY, "evaluate/sensitivity_shard_loi.py", "--config", CONFIG, + "--op", op, "--block", str(b), "--keys_file", KEYS_FILE, + "--key_start", str(s), "--key_end", str(e), + "--inference_steps", "50", "--scheduler", "PNDM", "--out_dir", OUT_DIR], + env=env, stdout=log, stderr=subprocess.STDOUT) + + +def main(): + running = {} + print(f"LOI scheduler: {len(TASKS)} tasks ({len(CONFIGS)} configs x {N}/{CHUNK})", flush=True) + while True: + for g in list(running): + if running[g][0].poll() is not None: + running.pop(g) + pending = [t for t in TASKS if not task_done(t)] + if not pending and not running: + print("ALL LOI TASKS DONE", flush=True) + break + busy = {t for _, t in running.values()} + for g, (free, util) in sorted(gpu_status().items()): + if g in running: + continue + if free >= FREE_MIN_MIB and util <= UTIL_MAX: + nxt = next((t for t in pending if t not in busy), None) + if nxt is None: + break + running[g] = (launch(g, nxt), nxt) + busy.add(nxt) + op, b, s, e = nxt + print(f"[{time.strftime('%m-%d %H:%M:%S')}] GPU{g} <- {tag(op,b)} [{s}:{e}] " + f"(free={free} util={util}) running={len(running)} pending={len(pending)-1}", + flush=True) + time.sleep(POLL_SEC) + + +if __name__ == "__main__": + main() diff --git a/evaluate/hf_backup.py b/evaluate/hf_backup.py new file mode 100644 index 0000000..1810c37 --- /dev/null +++ b/evaluate/hf_backup.py @@ -0,0 +1,61 @@ +"""Back up experiment progress to a private HuggingFace dataset (anti-local-loss). + +Reads the token from a file (never prints it). Uploads results (json/log/figures) ++ my scripts, skipping big regenerable blobs (mp4/latents/checkpoints). + +Usage: + python3 evaluate/hf_backup.py [--once] +""" +import argparse, os, sys +from huggingface_hub import HfApi + +# Overridable so the same script works on any machine (PSC, workstation, ...). +TOKEN_FILE = os.environ.get("SCMP_HF_TOKEN_FILE", "/home/qiuyid/huggingface_api_cmu.txt") +ROOT = os.environ.get("SCMP_ROOT", "/home/qiuyid/scmp_worldmodel") + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--repo_name", default="scmp-worldmodel-progress") + ap.parse_args() + + token = open(TOKEN_FILE).read().strip() + api = HfApi(token=token) + user = api.whoami()["name"] + repo_id = f"{user}/scmp-worldmodel-progress" + api.create_repo(repo_id, repo_type="dataset", private=True, exist_ok=True) + print(f"dataset: https://huggingface.co/datasets/{repo_id} (private)") + + # results: json/log/figures/csv — skip regenerable big blobs + if os.path.isdir(f"{ROOT}/results"): + api.upload_folder( + folder_path=f"{ROOT}/results", path_in_repo="results", + repo_id=repo_id, repo_type="dataset", + ignore_patterns=["*.mp4", "*.pt", "*.npz", "*.avi", "*.png.tmp"], + ) + # my scripts (reproducibility) + api.upload_folder( + folder_path=f"{ROOT}/evaluate", path_in_repo="evaluate", + repo_id=repo_id, repo_type="dataset", allow_patterns=["*.py"], + ) + # eval configs + if os.path.isdir(f"{ROOT}/configs/evaluation/bridge"): + api.upload_folder( + folder_path=f"{ROOT}/configs/evaluation/bridge", path_in_repo="configs_bridge", + repo_id=repo_id, repo_type="dataset", allow_patterns=["*.yaml"], + ) + # Calibration artifacts are small but need a GPU to regenerate, and the + # blanket *.pt ignore above drops them (this is how smoothquant_scales.pt + # went missing). Upload them explicitly, size-guarded. + for name in ("smoothquant_scales.pt",): + f = f"{ROOT}/results/{name}" + if os.path.isfile(f) and os.path.getsize(f) < 512 * 2**20: + api.upload_file(path_or_fileobj=f, path_in_repo=f"results/{name}", + repo_id=repo_id, repo_type="dataset") + print(f"uploaded {name} ({os.path.getsize(f)/2**20:.1f} MB)") + + print("backup done") + + +if __name__ == "__main__": + main() diff --git a/evaluate/hf_backup_videos.py b/evaluate/hf_backup_videos.py new file mode 100644 index 0000000..4527022 --- /dev/null +++ b/evaluate/hf_backup_videos.py @@ -0,0 +1,96 @@ +"""Daily video backup to the HF progress dataset. + +Kept separate from hf_backup.py (hourly, json/log only) because uploading a few +thousand mp4s in one go burns the 1000-req/5min API quota. This runs once a day +and uploads only what changed, in batches with pauses between them. + +Usage: python3 evaluate/hf_backup_videos.py [--batch 400] [--pause 90] +""" +import argparse, os, time +from huggingface_hub import HfApi + +# Overridable so the same script works on any machine (PSC, workstation, ...). +TOKEN_FILE = os.environ.get("SCMP_HF_TOKEN_FILE", "/home/qiuyid/huggingface_api_cmu.txt") +ROOT = os.environ.get("SCMP_RESULTS", "/home/qiuyid/scmp_worldmodel/results") + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--batch", type=int, default=400, help="files per upload call") + ap.add_argument("--pause", type=int, default=90, help="seconds between batches") + ap.add_argument("--prune", action="store_true", + help="delete local mp4s that are confirmed present on HF " + "(keeps disk flat; videos stay retrievable from the dataset)") + ap.add_argument("--keep-min", type=int, default=30, + help="with --prune: keep this many newest mp4s per directory " + "(FID/FVD and spot-checks need recent files on disk)") + cli = ap.parse_args() + + token = open(TOKEN_FILE).read().strip() + api = HfApi(token=token) + repo_id = f"{api.whoami()['name']}/scmp-worldmodel-progress" + api.create_repo(repo_id, repo_type="dataset", private=True, exist_ok=True) + + remote = set(api.list_repo_files(repo_id, repo_type="dataset")) + local = [] + for dirpath, _dirs, files in os.walk(ROOT): + for f in files: + if not f.endswith(".mp4"): + continue + full = os.path.join(dirpath, f) + rel = "results/" + os.path.relpath(full, ROOT) + if rel not in remote: + local.append((full, rel)) + print(f"{len(local)} new videos to upload (remote has {sum(1 for r in remote if r.endswith('.mp4'))})", + flush=True) + if not local and not cli.prune: + return + + for i in range(0, len(local), cli.batch): + chunk = local[i:i + cli.batch] + # upload_folder with allow_patterns is the cheapest batched path: one + # commit per batch instead of one per file. + api.upload_folder( + folder_path=ROOT, path_in_repo="results", repo_id=repo_id, repo_type="dataset", + allow_patterns=[rel[len("results/"):] for _full, rel in chunk], + commit_message=f"videos batch {i//cli.batch + 1} ({len(chunk)} files)", + ) + print(f" batch {i//cli.batch + 1}: {len(chunk)} files", flush=True) + if i + cli.batch < len(local): + time.sleep(cli.pause) # stay under the 1000-req / 5-min quota + print("VIDEO_BACKUP_DONE", flush=True) + + if cli.prune: + prune_local(api, repo_id, cli.keep_min) + + +def prune_local(api, repo_id, keep_min): + """Delete local mp4s that are verifiably on HF, keeping the newest few. + + Re-lists the remote AFTER uploading so we only ever delete files the + dataset actually has. Keeps keep_min newest per directory because + FID/FVD and visual spot-checks read videos off local disk. + """ + remote = set(api.list_repo_files(repo_id, repo_type="dataset")) + freed = 0 + for dirpath, _dirs, files in os.walk(ROOT): + mp4s = [os.path.join(dirpath, f) for f in files if f.endswith(".mp4")] + if not mp4s: + continue + # Never prune a line whose FID/FVD hasn't been computed yet — those + # metrics need every video of the run present on local disk. + tag = os.path.basename(os.path.dirname(dirpath)) # ...//videos + if not os.path.exists(f"{ROOT}/fidfvd_{tag}.json"): + continue + mp4s.sort(key=lambda p: os.path.getmtime(p), reverse=True) + for full in mp4s[keep_min:]: # keep newest keep_min + rel = "results/" + os.path.relpath(full, ROOT) + if rel in remote: # confirmed backed up + sz = os.path.getsize(full) + os.remove(full) + freed += sz + print(f"PRUNED {freed/2**30:.2f} GB of backed-up local videos", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/measure_block_gamma.py b/evaluate/measure_block_gamma.py new file mode 100644 index 0000000..e8858a4 --- /dev/null +++ b/evaluate/measure_block_gamma.py @@ -0,0 +1,99 @@ +"""Per-(block, timestep) sensitivity via the 6Bit-Diffusion Gamma signal. + +6Bit-Diffusion (arXiv:2603.18742) observes that a transformer block's relative +input-output change Gamma = ||Y - X||_1 / ||X||_1 at step t-1 linearly +predicts the quantization error of that block's linears at step t. Gamma is +BLOCK-level and the step index is exact, so this signal needs none of the +row-ordering information whose absence killed row-level MP here (Spearman +0.02). This script records Gamma[t, b] over an FP teacher rollout; the +allocator then solves min sum W(t,b) * sigma(L)^2 at matched average cycles. + + python evaluate/measure_block_gamma.py --out results/block_gamma.npz +""" +import argparse, json, os +import numpy as np +import torch + +from evaluate.calibrate_mp_fractions import ( + build_args, load_model, make_pipe, + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + compute_actions_for_slice, +) +from models.sc_integration import reconfigure, get_config +from models.sc_integration.sc_controller import get_current_step + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--eval_config", default="configs/evaluation/bridge/frame_ada_sc_full.yaml") + p.add_argument("--keys_file", default="results/diverse_300.json") + p.add_argument("--num_samples", type=int, default=2) + p.add_argument("--inference_steps", type=int, default=50) + p.add_argument("--out", required=True) + cli = p.parse_args() + + args = build_args(cli.eval_config, cli.inference_steps) + device = torch.device("cuda:0") + from diffusers.models import AutoencoderKL + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "qkv_proj", "proj", "mlp_fc1", "mlp_fc2"): + if hasattr(cfg, f"enable_{f}"): + setattr(cfg, f"enable_{f}", False) # FP teacher + + blocks = list(model.blocks) + n_steps = cli.inference_steps + acc = np.zeros((n_steps, len(blocks))) + cnt = np.zeros((n_steps, len(blocks))) + + hooks = [] + for bi, blk in enumerate(blocks): + def mk(bi): + def hook(_m, inp, out): + x = inp[0].detach() + y = out[0].detach() if isinstance(out, (tuple, list)) else out.detach() + g = ((y - x).abs().sum() / x.abs().sum().clamp_min(1e-8)).item() + step, _tot = get_current_step() + if 0 <= step < n_steps: + acc[step, bi] += g + cnt[step, bi] += 1 + return hook + hooks.append(blk.register_forward_hook(mk(bi))) + + pipe = make_pipe(args, vae, model, "PNDM") + for key in json.load(open(cli.keys_file))[: cli.num_samples]: + parts = key.split("_") + eid, start = "_".join(parts[:-2]), int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + gt = torch.load(os.path.join(GT_LATENT_DIR, f"{key}.pt"), + weights_only=False, map_location=device) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + act = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + with torch.no_grad(): + pipe(act.to(device).float(), mask_x=gt[0:1].unsqueeze(0).to(device).float(), + video_length=args.num_frames, height=args.video_size[0], + width=args.video_size[1], num_inference_steps=cli.inference_steps, + guidance_scale=args.guidance_scale, device=device, + return_dict=False, output_type="latent_only") + print(f" teacher rollout {key}", flush=True) + for h in hooks: + h.remove() + + G = acc / np.maximum(cnt, 1) + np.savez_compressed(cli.out, gamma=G) + print(f"wrote {cli.out}: Gamma{G.shape}", flush=True) + print("每步均值(前/中/后):", + [round(float(G[i].mean()), 4) for i in (0, n_steps // 2, n_steps - 1)]) + print("每块均值范围:", round(float(G.mean(0).min()), 4), "~", + round(float(G.mean(0).max()), 4)) + + +if __name__ == "__main__": + main() diff --git a/evaluate/measure_row_sensitivity.py b/evaluate/measure_row_sensitivity.py new file mode 100644 index 0000000..fa22872 --- /dev/null +++ b/evaluate/measure_row_sensitivity.py @@ -0,0 +1,196 @@ +"""Per-row downstream sensitivity for MP allocation (the un-simplified loss). + +First-order, the end-to-end damage of SC noise injected at row i of a linear's +output is + + dQ ~= sum_i w_i * sigma_i(L_i)^2, w_i = || d(model out) / d(y_i) ||^2 + +sigma_i(L) we already measure exactly with the real kernels (the error grid). +What was missing is w_i: every objective tried so far hard-codes it (absolute +RMSE: w=1; relative L2: w ~ 1/||y_i||^2) instead of measuring it. This script +measures it the way scmp_diffusion's Method 3 does — Hutchinson probes +backpropagated from the model output, grad norms read off each target linear's +output — but per ROW rather than per (op, block) bucket, and it records the +runtime ranking metric (smoothed row amax) alongside so the search can learn +the metric -> weight mapping and, crucially, its SIGN. + + python evaluate/measure_row_sensitivity.py --out results/row_sensitivity.npz +""" +from __future__ import annotations + +import argparse +import json +import os + +import numpy as np +import torch + +from evaluate.calibrate_mp_fractions import ( + TARGET_SUFFIXES, build_args, load_model, + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + compute_actions_for_slice, +) +from models.sc_integration import reconfigure, get_config + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--eval_config", default="configs/evaluation/bridge/frame_ada_sc_full.yaml") + p.add_argument("--keys_file", default="results/diverse_300.json") + p.add_argument("--num_samples", type=int, default=2) + p.add_argument("--timestep_fracs", default="0.2,0.5,0.8", + help="positions in the 50-step schedule to probe") + p.add_argument("--probes", type=int, default=2, help="Hutchinson probes per state") + p.add_argument("--pixel_frames", type=int, default=2, + help="frames decoded per pixel-space probe (0 disables)") + p.add_argument("--rows_per_call", type=int, default=512) + p.add_argument("--smooth_scales", default="results/smoothquant_scales.pt") + p.add_argument("--out", required=True) + cli = p.parse_args() + + args = build_args(cli.eval_config, 50) + device = torch.device("cuda:0") + model = load_model(args, device) + # Pixel-space probes need the decoder: PSNR lives after the VAE, whose + # Jacobian reweights token rows. latent-L2 probes do not (x0_hat is affine + # in eps, so eps-probes already rank rows correctly for it). + from diffusers.models import AutoencoderKL + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device) + vae.requires_grad_(False) + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2"): + setattr(cfg, f"enable_{f}", False) # FP teacher; plain autograd + + smooth = torch.load(cli.smooth_scales, map_location=device, + weights_only=False)["scales"] + + from diffusers.schedulers import PNDMScheduler + sched = PNDMScheduler.from_pretrained( + args.scheduler_path, beta_start=args.beta_start, beta_end=args.beta_end, + beta_schedule=args.beta_schedule, variance_type=args.variance_type) + sched.set_timesteps(50, device=device) + fracs = [float(x) for x in cli.timestep_fracs.split(",")] + probe_ts = [sched.timesteps[int(f * (len(sched.timesteps) - 1))] for f in fracs] + + # ---- hooks: keep each target linear's output grad + the runtime metric of + # the SAME sampled rows (row i of input maps to row i of output) ---- + captured: dict[str, dict] = {} + hooks = [] + gen = torch.Generator(device="cpu").manual_seed(0) + + def mk(name, mod): + s = smooth.get(name) + s_dev = s.to(device).float() if s is not None else None + + def hook(_m, inp, out): + if not out.requires_grad: + return + out.retain_grad() + x = inp[0].detach().reshape(-1, inp[0].shape[-1]).float() + n = x.shape[0] + k = min(cli.rows_per_call, n) + idx = torch.randperm(n, generator=gen)[:k].to(device) + xs = x[idx] / s_dev if s_dev is not None else x[idx] + amax = xs.abs().amax(-1) + l2 = xs.norm(dim=-1) + # candidate dispatch metrics, mirroring scmp_llm's "auto" mode: + # the calibrator picks the best of amax / l2 / crest per module by + # rank correlation with the true weight, instead of assuming amax. + captured[name] = {"out": out, "idx": idx, + "metric": amax.cpu(), "l2": l2.cpu(), + "crest": (amax / (l2 + 1e-12)).cpu()} + return hook + + for name, mod in model.named_modules(): + if isinstance(mod, torch.nn.Linear) and name.endswith(TARGET_SUFFIXES): + hooks.append(mod.register_forward_hook(mk(name, mod))) + + recs: dict[str, list] = {} + keys = json.load(open(cli.keys_file))[: cli.num_samples] + for key in keys: + parts = key.split("_") + eid, start = "_".join(parts[:-2]), int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + x0 = torch.load(os.path.join(GT_LATENT_DIR, f"{key}.pt"), + weights_only=False, map_location=device).float().unsqueeze(0) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + act = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER + ).float().unsqueeze(0).to(device) + + for t in probe_ts: + noise = torch.randn_like(x0) + x_t = sched.add_noise(x0, noise, t.reshape(1)) + x_t[:, :1] = x0[:, :1] # conditioning frame stays clean + abar = sched.alphas_cumprod.to(device)[t.long()].float() + for _pr in range(cli.probes): + for kind in (("eps",) if cli.pixel_frames == 0 else ("eps", "pix")): + captured.clear() + model.zero_grad(set_to_none=True) + out = model(x_t.clone(), actions=act, + t=t.reshape(1).to(device), + mask_frame_num=1, use_fp16=False) + if isinstance(out, (tuple, list)): + out = out[0] + if kind == "eps": + # Gauss-Newton weight for latent-space MSE: x0_hat is + # affine in eps, so probing eps ranks rows identically. + v = torch.randn_like(out) + (out * v).sum().backward() + else: + # PSNR weight: push the probe through the VAE decoder + # so its Jacobian reweights the rows. + x0_hat = (x_t - torch.sqrt(1 - abar) * out) / torch.sqrt(abar) + fr = torch.randperm(x0_hat.shape[1], generator=gen)[: cli.pixel_frames] + pix = vae.decode( + x0_hat[0, fr].float() / vae.config.scaling_factor).sample + u = torch.randn_like(pix) + (pix * u).sum().backward() + for name, c in captured.items(): + g = c["out"].grad + if g is None: + continue + g2 = g.detach().reshape(-1, g.shape[-1]).float()[c["idx"]] + g2 = g2.pow(2).sum(-1).cpu().numpy() + recs.setdefault((name, kind), []).append( + np.stack([c["metric"].numpy(), c["l2"].numpy(), + c["crest"].numpy(), g2], 1)) + print(f" {key} t={int(t)}: {len(recs)} modules recorded", flush=True) + + for h in hooks: + h.remove() + + names = sorted(recs) + mats = [np.concatenate(recs[n], 0) for n in names] + lens = np.array([m.shape[0] for m in mats]) + np.savez_compressed(cli.out, data=np.concatenate(mats, 0), lengths=lens, + modules=np.array([f"{n}|{k}" for n, k in names])) + print(f"wrote {cli.out}: {int(lens.sum())} (metric, grad^2) pairs " + f"over {len(names)} module-kind pairs", flush=True) + + # quick readout: does the runtime metric rank the true weight, and which way? + def spearman(a, b): + ra = np.argsort(np.argsort(a)).astype(float) + rb = np.argsort(np.argsort(b)).astype(float) + ra -= ra.mean(); rb -= rb.mean() + d = np.sqrt((ra * ra).sum() * (rb * rb).sum()) + return float((ra * rb).sum() / d) if d > 0 else float("nan") + + for want in ("eps", "pix"): + for ci, mname in ((0, "amax"), (1, "l2"), (2, "crest")): + rhos = [spearman(m[:, ci], m[:, 3]) + for (n, k), m in zip(names, mats) if k == want] + if rhos: + ab = [abs(r) for r in rhos] + print(f"Spearman({mname:5}, w_{want}): mean {np.mean(rhos):+.3f} " + f"mean|rho| {np.mean(ab):.3f} P90|rho| {np.percentile(ab,90):.3f}") + print(" >0: long streams belong to HIGH-metric rows (current direction)") + print(" <0: long streams belong to LOW-metric rows (inverted direction)") + + +if __name__ == "__main__": + main() diff --git a/evaluate/plot_results.py b/evaluate/plot_results.py new file mode 100644 index 0000000..522a28b --- /dev/null +++ b/evaluate/plot_results.py @@ -0,0 +1,154 @@ +"""Static PNG figures for the SC-quantization world-model study. + +Outputs (results/figures/): + fig_comparison.png 4 configs x 3 metrics (latent L2 / PSNR / SSIM) + fig_sensitivity.png per-block leave-one-out sensitivity (Δ latent L2) + fig_overview.png both panels stacked, one-glance summary +""" +import os +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from matplotlib.ticker import MultipleLocator + +# ---- validated palette (light surface) ---- +C_FP, C_NAIVE, C_SCU, C_SKIP = "#2a78d6", "#1baf7a", "#e34948", "#eb6834" +C_NEG, C_POS = "#2a78d6", "#e34948" # improve / worsen (diverging) +INK, INK2, MUTED, GRID = "#0f1319", "#555b66", "#868b95", "#e6e9ee" + +plt.rcParams.update({ + "font.family": "DejaVu Sans", "font.size": 11, + "axes.edgecolor": "#c3c2b7", "axes.linewidth": 0.8, + "axes.labelcolor": INK2, "text.color": INK, + "xtick.color": MUTED, "ytick.color": MUTED, + "figure.dpi": 200, "savefig.dpi": 200, +}) + +METHODS = [ + ("FP baseline\n(math)", 0.1702, 25.75, 0.834, C_FP), + ("Naive int8\n(uniform)", 0.1755, 25.08, 0.816, C_NAIVE), + ("SC uniform\n(sc_int8_full)",0.5637, 13.61, 0.408, C_SCU), + ("SC + skip\n0,4,18", 0.3521, 16.53, 0.472, C_SKIP), +] +REF = 0.5585 +SENS = {0:0.4843,1:6.2325,2:0.5361,3:0.5798,4:0.5117,5:0.5329,6:0.5315,7:0.5312,8:0.5323,9:0.5331, +10:0.5473,11:0.5407,12:0.5376,13:0.5472,14:0.5311,15:0.5468,16:0.5432,17:0.5333,18:0.5142,19:0.5447, +20:0.5612,21:0.5460,22:0.5417,23:0.5611,24:0.5352,25:0.5262-0.001,26:0.5262,27:0.5278} +SENS[25]=0.5252 +TOP3 = {0,4,18} + +OUT = "results/figures" +os.makedirs(OUT, exist_ok=True) + + +def _clean(ax): + ax.spines["top"].set_visible(False) + ax.spines["right"].set_visible(False) + + +def draw_comparison(axes): + names = [m[0] for m in METHODS] + colors = [m[4] for m in METHODS] + y = range(len(METHODS)) + specs = [ + (1, "latent L2 (↓ lower better)", 0.62, "{:.3f}"), + (2, "PSNR / dB (↑ higher better)", 29, "{:.2f}"), + (3, "SSIM (↑ higher better)", 1.02,"{:.3f}"), + ] + for ax, (idx, title, xmax, fmt) in zip(axes, specs): + vals = [m[idx] for m in METHODS] + bars = ax.barh(y, vals, height=0.62, color=colors, zorder=3) + ax.set_xlim(0, xmax) + ax.set_ylim(-0.6, len(METHODS)-0.4) + ax.invert_yaxis() + ax.set_title(title, fontsize=11, color=INK, pad=8, loc="left") + ax.xaxis.grid(True, color=GRID, linewidth=1, zorder=0) + ax.set_axisbelow(True) + _clean(ax) + ax.tick_params(length=0) + for b, v in zip(bars, vals): + ax.text(v + xmax*0.02, b.get_y()+b.get_height()/2, fmt.format(v), + va="center", ha="left", fontsize=10, color=INK, fontweight="600") + axes[0].set_yticks(list(y)); axes[0].set_yticklabels(names, fontsize=9.5, color=INK) + for ax in axes[1:]: + ax.set_yticks(list(y)); ax.set_yticklabels([]) + + +def draw_sensitivity(ax): + ymin, ymax = -0.085, 0.042 + blocks = list(range(28)) + for b in blocks: + d = SENS[b] - REF + clipped = d > ymax + dd = ymax if clipped else d + color = C_NEG if d < 0 else C_POS + ax.bar(b, dd, width=0.72, color=color, zorder=3, + edgecolor=INK if b in TOP3 else "none", linewidth=1.1 if b in TOP3 else 0) + if clipped: + # break marks near the clipped top, then value above the bar + ax.plot([b-0.36, b+0.36], [ymax*0.60]*2, color="white", lw=1.3, zorder=5) + ax.plot([b-0.36, b+0.36], [ymax*0.74]*2, color="white", lw=1.3, zorder=5) + ax.text(b, ymax+0.003, "L2=6.23", ha="center", va="bottom", + fontsize=8.5, color=C_POS, fontweight="700") + if b in TOP3: + ax.text(b, d-0.004, f"{d:.3f}", ha="center", va="top", + fontsize=8.5, color=INK, fontweight="700") + ax.axhline(0, color="#c3c2b7", lw=1.2, zorder=2) + ax.set_xlim(-0.8, 27.8) + ax.set_ylim(ymin, 0.052) + ax.set_xticks(blocks) + ax.set_xticklabels([str(b) for b in blocks], fontsize=8) + for t, b in zip(ax.get_xticklabels(), blocks): + t.set_color(INK if b in TOP3 else MUTED) + if b in TOP3: t.set_fontweight("700") + ax.yaxis.set_major_locator(MultipleLocator(0.025)) + ax.yaxis.grid(True, color=GRID, linewidth=1, zorder=0) + ax.set_axisbelow(True) + _clean(ax) + ax.tick_params(length=0) + ax.set_xlabel("transformer block index (0–27)", fontsize=10, color=INK2) + ax.set_ylabel("Δ latent L2 vs SC uniform baseline", fontsize=10, color=INK2) + # direction legend, placed in the empty middle band (avoids all bars) + ax.text(14, 0.036, "red ↑ skip → worsens", ha="center", + fontsize=9, color=C_POS, fontweight="600") + ax.text(14, -0.080, "blue ↓ noise source, skip → improves", ha="center", + fontsize=9, color=C_NEG, fontweight="600") + + +# ---- fig 1: comparison ---- +fig, axes = plt.subplots(1, 3, figsize=(11, 3.1)) +draw_comparison(axes) +fig.suptitle("SC quantization vs baselines · bridge test, n=20, PNDM 50-step", + fontsize=12.5, color=INK, fontweight="700", x=0.02, ha="left", y=1.04) +fig.tight_layout(rect=[0, 0, 1, 0.98]) +fig.savefig(f"{OUT}/fig_comparison.png", bbox_inches="tight", facecolor="white") +plt.close(fig) + +# ---- fig 2: sensitivity ---- +fig, ax = plt.subplots(figsize=(11, 3.6)) +draw_sensitivity(ax) +fig.suptitle("Per-block leave-one-out sensitivity · DPM 10-step, n=2 · top-3 = blocks 0, 4, 18", + fontsize=12.5, color=INK, fontweight="700", x=0.02, ha="left", y=1.0) +fig.tight_layout() +fig.savefig(f"{OUT}/fig_sensitivity.png", bbox_inches="tight", facecolor="white") +plt.close(fig) + +# ---- fig 3: overview (both) ---- +fig = plt.figure(figsize=(11, 7.0)) +gs = fig.add_gridspec(2, 3, height_ratios=[1, 1.15], hspace=0.55, wspace=0.12) +axes = [fig.add_subplot(gs[0, i]) for i in range(3)] +draw_comparison(axes) +axb = fig.add_subplot(gs[1, :]) +draw_sensitivity(axb) +fig.suptitle("Stochastic-computing int8 in the IRASim world model — full comparison", + fontsize=14, color=INK, fontweight="700", x=0.02, ha="left", y=0.99) +fig.text(0.02, 0.945, + "SC full-replace collapses quality (PSNR 25.75→13.61); naive int8 is near-lossless " + "→ damage is SC noise, not low precision. Skipping the 3 most sensitive blocks recovers 53.8% of the L2 gap.", + fontsize=9.5, color=INK2, ha="left") +fig.savefig(f"{OUT}/fig_overview.png", bbox_inches="tight", facecolor="white") +plt.close(fig) + +print("wrote:") +for f in ("fig_comparison.png", "fig_sensitivity.png", "fig_overview.png"): + print(" ", os.path.abspath(f"{OUT}/{f}")) diff --git a/evaluate/plot_sc_curve.py b/evaluate/plot_sc_curve.py new file mode 100644 index 0000000..8b26bba --- /dev/null +++ b/evaluate/plot_sc_curve.py @@ -0,0 +1,119 @@ +"""SC progressive-replacement line chart (facet by metric). + +x-axis = how many op-types run on SC (FP → +qk → +av → +proj → +fc1 → full). +One subplot per metric (latent L2 / PSNR / SSIM). Overlaid references: + - naive int8 uniform (horizontal dashed line): int8 but NOT stochastic + - SC full + skip 0,4,18 (star): the sensitivity-anchor recovery point + +All points share one self-consistent setting: DPM 10-step, n=8. +""" +import os, json +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt + +ROOT = "results/line_eval" +C_SEQ, C_NAIVE, C_SKIP = "#2a78d6", "#1baf7a", "#eb6834" +INK, INK2, MUTED, GRID = "#0f1319", "#555b66", "#868b95", "#e6e9ee" + +plt.rcParams.update({ + "font.family": "DejaVu Sans", "font.size": 11, + "axes.edgecolor": "#c3c2b7", "axes.linewidth": 0.8, + "axes.labelcolor": INK2, "text.color": INK, + "xtick.color": MUTED, "ytick.color": MUTED, + "figure.dpi": 200, "savefig.dpi": 200, +}) + +SEQ = [("line_v0_fp", "FP\n(math)"), ("line_v1_qk", "+qk"), ("line_v2_qkav", "+av"), + ("line_v3_qkavproj", "+proj"), ("line_v4_fc1", "+fc1"), ("line_v5_full", "full\n(6 ops)")] + + +def load(tag): + with open(f"{ROOT}/{tag}/summary_shard_0.json") as f: + return json.load(f) + + +data = [load(t) for t, _ in SEQ] +naive = load("line_naive") +skip = load("line_skip") +xs = list(range(len(SEQ))) +xlabels = [l for _, l in SEQ] + +METRICS = [ + ("mean_l2", "latent L2 (↓ lower better)", "{:.3f}"), + ("mean_psnr", "PSNR / dB (↑ higher better)", "{:.2f}"), + ("mean_ssim", "SSIM (↑ higher better)", "{:.3f}"), +] + + +def _clean(ax): + ax.spines["top"].set_visible(False) + ax.spines["right"].set_visible(False) + ax.tick_params(length=0) + ax.set_axisbelow(True) + ax.yaxis.grid(True, color=GRID, linewidth=1) + + +fig, axes = plt.subplots(1, 3, figsize=(12.4, 4.1)) +for ax, (key, title, fmt) in zip(axes, METRICS): + ys = [d[key] for d in data] + # SC progressive main line + ax.plot(xs, ys, "-o", color=C_SEQ, lw=2.2, ms=7, zorder=4, + markerfacecolor=C_SEQ, markeredgecolor="white", markeredgewidth=1.2) + # value labels on FP (start) and full (end) + ax.annotate(fmt.format(ys[0]), (xs[0], ys[0]), textcoords="offset points", + xytext=(2, 9), fontsize=9, color=INK, fontweight="700") + ax.annotate(fmt.format(ys[-1]), (xs[-1], ys[-1]), textcoords="offset points", + xytext=(-4, -15), fontsize=9, color=INK, fontweight="700", ha="center") + # naive int8 reference (horizontal) + ax.axhline(naive[key], ls="--", color=C_NAIVE, lw=1.8, zorder=2) + # skip anchor point (same x as full, better y), with recovery arrow + ax.plot([xs[-1]], [skip[key]], marker="*", ms=17, color=C_SKIP, + markeredgecolor="white", markeredgewidth=1, ls="", zorder=5) + ax.annotate("", xy=(xs[-1], skip[key]), xytext=(xs[-1], ys[-1]), + arrowprops=dict(arrowstyle="->", color=C_SKIP, lw=1.6)) + + ax.set_title(title, fontsize=11.5, color=INK, pad=9, loc="left") + ax.set_xticks(xs) + ax.set_xticklabels(xlabels, fontsize=9) + ax.set_xlim(-0.35, len(SEQ) - 0.4) + _clean(ax) + # headroom for labels + lo = min(min(ys), naive[key], skip[key]) + hi = max(max(ys), naive[key], skip[key]) + pad = (hi - lo) * 0.16 + 1e-6 + ax.set_ylim(lo - pad, hi + pad) + +# shared legend (proxy handles) +from matplotlib.lines import Line2D +handles = [ + Line2D([0], [0], color=C_SEQ, lw=2.2, marker="o", markerfacecolor=C_SEQ, + markeredgecolor="white", label="SC progressive (FP → full)"), + Line2D([0], [0], color=C_NAIVE, lw=1.8, ls="--", label="naive int8 uniform (non-SC)"), + Line2D([0], [0], color=C_SKIP, lw=0, marker="*", ms=13, markeredgecolor="white", + label="SC full + skip blocks 0,4,18"), +] +fig.legend(handles=handles, loc="upper center", ncol=3, frameon=False, + fontsize=10, bbox_to_anchor=(0.5, 1.005)) +fig.suptitle("How SC degrades the world model — quality vs. how many matmul types run on stochastic int8", + fontsize=13, color=INK, fontweight="700", x=0.012, ha="left", y=1.10) +fig.text(0.012, 1.005, + "Each matmul type is moved onto SC left→right. naive int8 (same ops, uniform quant) stays flat near FP → " + "the collapse is SC noise, not low precision. The star shows skipping the 3 most sensitive blocks pulls quality back.", + fontsize=9.3, color=INK2, ha="left") +fig.text(0.5, -0.02, "operator types moved to SC (cumulative)", + fontsize=10.5, color=INK2, ha="center") + +os.makedirs("results/figures", exist_ok=True) +fig.savefig("results/figures/fig_sc_curve.png", bbox_inches="tight", facecolor="white") +plt.close(fig) +print("wrote", os.path.abspath("results/figures/fig_sc_curve.png")) + +# also dump the numbers used +tbl = {"setting": "DPM 10-step, n=8", + "sequence": {l.replace(chr(10), " "): {k: data[i][k] for k in ("mean_l2", "mean_psnr", "mean_ssim")} + for i, (t, l) in enumerate(SEQ)}, + "naive_int8": {k: naive[k] for k in ("mean_l2", "mean_psnr", "mean_ssim")}, + "skip_0_4_18": {k: skip[k] for k in ("mean_l2", "mean_psnr", "mean_ssim")}} +json.dump(tbl, open("results/figures/sc_curve_data.json", "w"), indent=2) +print("wrote results/figures/sc_curve_data.json") diff --git a/evaluate/search_mp_levels.py b/evaluate/search_mp_levels.py new file mode 100644 index 0000000..5034c8a --- /dev/null +++ b/evaluate/search_mp_levels.py @@ -0,0 +1,401 @@ +"""Search MP stoc_len level sets instead of hand-picking them. + +The 3-level {ref, 0.75ref, 0.5ref} shape used by the HPCA table spans only 2x, +which bounds how much budget mixed precision can move: at a 96-cycle budget at +most 50% of rows can reach 128. The scmp_llm ladder instead uses 5-8 irregular +levels per (model, target) - values like [111, 85, 49, 48, 33] that are clearly +searched, not derived from a rule. + +This does that search. Phase 1 measures the real per-row SC error on a DENSE +grid of candidate stream lengths (one GPU pass). Phase 2 is pure CPU: for a +given budget and level count k, every candidate subset is scored by running the +same Lagrangian assignment the calibrator uses, and the subset with the lowest +assigned error wins. Scoring a subset costs a few ms, so the subsets can be +enumerated exhaustively. + + # phase 1 (GPU, ~20 min) + python evaluate/search_mp_levels.py measure --out results/mp_error_grid.npz + + # phase 2 (CPU, seconds) + python evaluate/search_mp_levels.py search --grid results/mp_error_grid.npz \ + --budget 96 --k 3,5,7 --out results/mp_levels_search_b96.json +""" +from __future__ import annotations + +import argparse +import itertools +import json +import os + +import numpy as np + +# Dense candidate grid, in HALVED cycle counts (see the HPCA note in +# calibrate_mp_fractions.py: a level value IS the cycle count). 128 is the +# ceiling - the uniform int8 rung - so nothing above it is searched. +DEFAULT_GRID = [16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128] +# Every integer stream length in [16, 128]. Measuring this costs one longer +# GPU pass but lets the refinement land on off-grid values like 111 or 49. +DENSE_GRID = list(range(16, 129)) + + +def measure(cli): + """Phase 1: per-row SC error at every candidate stream length.""" + import torch + from diffusers.models import AutoencoderKL + from scmp_kernels.sc import sc_matmul + from scmp_kernels.sc.config_helpers import make_sobol_simple_config + from models.sc_integration import reconfigure, get_config + from evaluate.calibrate_mp_fractions import ( + TARGET_SUFFIXES, build_args, load_model, make_pipe, + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + compute_actions_for_slice, + ) + + grid = [int(x) for x in cli.grid.split(",")] if cli.grid else DEFAULT_GRID + args = build_args(cli.eval_config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + cfg = get_config() + for f in ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2"): + setattr(cfg, f"enable_{f}", False) # teacher pass stays FP + + caps: dict[str, list] = {} + hooks = [] + for name, mod in model.named_modules(): + if isinstance(mod, torch.nn.Linear) and name.endswith(TARGET_SUFFIXES): + def mk(n): + def hook(_m, inp, _out): + x = inp[0].detach().reshape(-1, inp[0].shape[-1]).float() + keep = caps.setdefault(n, []) + if sum(t.shape[0] for t in keep) < 512: + idx = torch.randperm(x.shape[0], device=x.device)[:64] + keep.append(x[idx].cpu()) + return hook + hooks.append(mod.register_forward_hook(mk(name))) + + pipe = make_pipe(args, vae, model, "DPM") + for k in json.load(open(cli.keys_file))[: cli.num_samples]: + parts = k.split("_") + eid, start = "_".join(parts[:-2]), int(parts[-1]) + ann = json.load(open(os.path.join(ANNOT_DIR, f"{eid}.json"))) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + gt = torch.load(os.path.join(GT_LATENT_DIR, f"{k}.pt"), + weights_only=False, map_location=device) + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + act = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + with torch.no_grad(): + pipe(act.to(device).float(), mask_x=gt[0:1].unsqueeze(0).to(device).float(), + video_length=args.num_frames, height=args.video_size[0], + width=args.video_size[1], num_inference_steps=cli.inference_steps, + guidance_scale=args.guidance_scale, device=device, + return_dict=False, output_type="latent_only") + print(f" teacher pass {k}", flush=True) + for h in hooks: + h.remove() + + # Deployment passes smooth_scales into every MP sc_matmul call, so the + # error curves must be measured on the SAME smoothed matmul. Measuring + # without them (as the original calibrator did) optimises fractions on a + # different error landscape than the one deployment runs on — SmoothQuant + # rescales per-channel, which reorders per-row errors. + smooth_payload = None + if cli.smooth_scales: + smooth_payload = torch.load(cli.smooth_scales, map_location=device, + weights_only=False)["scales"] + print(f" measuring WITH SmoothQuant scales ({len(smooth_payload)} linears)", + flush=True) + + named = dict(model.named_modules()) + all_err, all_module, order = [], [], [] + all_refnorm, all_rowmetric = [], [] + for name, chunks in caps.items(): + X = torch.cat(chunks, 0)[: cli.max_rows].to(device) + W = named[name].weight.detach().float() + ref_out = X @ W.t() + smooth = smooth_payload.get(name) if smooth_payload else None + if smooth is not None: + smooth = smooth.to(device).float() + errs = [] + for L in grid: + with torch.no_grad(): + y = sc_matmul(X, W, granularity="per_row", mode="bipolar", + sc_prec=8, stoc_len=L, + config=make_sobol_simple_config(X.shape[-1], X.shape[-1], 8), + halve_bipolar_stoc_len=True, + smooth_scales=smooth) + errs.append(((y - ref_out) ** 2).mean(dim=-1).sqrt().cpu().numpy()) + all_err.append(np.stack(errs, 1)) + all_module.append(np.full(X.shape[0], len(order))) + # Needed to reconstruct scmp_llm's objective offline: its calibrator + # prices RELATIVE per-row L2 (||y-ref||/||ref||) through delta_sigma2, + # not the raw absolute RMSE above. Save the per-row ref norm plus the + # runtime ranking signal so `search` can re-derive both. + all_refnorm.append((ref_out ** 2).mean(dim=-1).sqrt().cpu().numpy()) + xs = X / smooth if smooth is not None else X + all_rowmetric.append(xs.abs().amax(dim=-1).cpu().numpy()) + order.append(name) + print(f" error curve {name}: rows={X.shape[0]} levels={len(grid)}", flush=True) + + E = np.concatenate(all_err, 0) + M = np.concatenate(all_module, 0) + np.savez_compressed(cli.out, errors=E, module_idx=M, + ref_norm=np.concatenate(all_refnorm, 0), + row_metric=np.concatenate(all_rowmetric, 0), + grid=np.array(grid), modules=np.array(order)) + print(f"wrote {cli.out}: E{E.shape} over grid {grid}", flush=True) + + +def llm_objective(E_abs, ref_norm, objective="delta_sigma2"): + """scmp_llm's calibration currency (benchmark/ppl/mp_objectives.py). + + sigma is the RELATIVE per-row L2; delta_sigma2 prices only the error a row + gains by running below the longest stream, squared to penalise the + low-precision cliff superlinearly. Our original absolute-RMSE objective + kept neither the normalisation nor the delta nor the square. + """ + sig = E_abs / np.maximum(ref_norm[:, None], 1e-8) + if objective == "sigma": + return sig + if objective == "sigma2": + return sig ** 2 + if objective == "delta_sigma2": + return np.maximum(sig - sig[:, :1], 0.0) ** 2 + raise ValueError(objective) + + +def _assign(errors, costs, budget_total): + """Lagrangian per-row level assignment (same solver as the calibrator).""" + n = errors.shape[0] + if budget_total <= n * costs[-1]: + return np.full(n, len(costs) - 1, dtype=np.int64) + if budget_total >= n * costs[0]: + return np.zeros(n, dtype=np.int64) + + def solve(lmbd): + a = (errors + lmbd * costs[None, :]).argmin(axis=1) + return a, float(costs[a].sum()) + + lo, hi = 0.0, 1.0 + _, c = solve(hi) + while c > budget_total and hi < 1e6: + hi *= 2.0 + _, c = solve(hi) + best = np.zeros(n, dtype=np.int64) + for _ in range(40): + mid = 0.5 * (lo + hi) + best, c = solve(mid) + if c > budget_total: + lo = mid + else: + hi = mid + return best + + +def score(E_sub, costs, budget_per_row, objective="abs"): + """Mean assigned error for one candidate level set. Lower is better. + + E_sub columns must be in DESCENDING level order. For the scmp_llm + currencies E_sub is relative sigma and the transform runs here so that + delta_sigma2's baseline is this subset's own longest stream. + """ + if objective == "sigma2": + E_sub = E_sub ** 2 + elif objective == "delta_sigma2": + E_sub = np.maximum(E_sub - E_sub[:, :1], 0.0) ** 2 + n = E_sub.shape[0] + a = _assign(E_sub, np.asarray(costs, dtype=np.float64), budget_per_row * n) + return float(E_sub[np.arange(n), a].mean()), a + + +def search(cli): + """Phase 2: exhaustive subset search over the measured grid.""" + d = np.load(cli.grid_file, allow_pickle=True) + E_full, grid = d["errors"], [int(x) for x in d["grid"]] + objective = getattr(cli, "objective", "abs") + if objective != "abs": + if "ref_norm" not in d: + raise SystemExit("grid has no ref_norm; re-run measure for relative objectives") + # Convert to relative sigma only; the delta/square transform is applied + # inside score() AFTER subset columns are selected, because delta's + # baseline is the subset's own longest stream (its column 0 once + # descending) — applying it here against the ascending grid made the + # baseline L=16, the objective identically zero, and every search + # degenerate to the cheapest level. + E_full = E_full / np.maximum(d["ref_norm"][:, None], 1e-8) + # Scoring a subset costs one Lagrangian solve over every row, and there are + # up to ~18k subsets per (budget, k). Subsampling rows keeps the ranking + # intact — the score is a mean over rows — while making the exhaustive + # search minutes instead of hours. Sampling is deterministic. + if cli.max_search_rows and E_full.shape[0] > cli.max_search_rows: + rs = np.random.RandomState(0) + idx = rs.choice(E_full.shape[0], cli.max_search_rows, replace=False) + E_full = E_full[np.sort(idx)] + print(f" subsampled {cli.max_search_rows} of {d['errors'].shape[0]} rows " + f"for the subset search", flush=True) + budget = cli.budget + ks = [int(x) for x in cli.k.split(",")] + + # A level set must bracket the budget, otherwise the assignment collapses + # onto one level and the schedule degenerates to uniform. + feasible = [i for i, g in enumerate(grid)] + out = {"budget": budget, "grid": grid, "n_rows": int(E_full.shape[0]), "results": {}} + + for k in ks: + best = None + n_tried = 0 + for combo in itertools.combinations(feasible, k): + lv = [grid[i] for i in combo][::-1] # descending + if not (min(lv) < budget < max(lv)): + continue + n_tried += 1 + s, _ = score(E_full[:, list(combo)][:, ::-1], lv, budget, objective) + if best is None or s < best[0]: + best = (s, lv) + if best is None: + print(f"k={k}: no feasible set brackets budget {budget}") + continue + s, lv = best + a = score(E_full[:, [grid.index(x) for x in lv]], lv, budget, objective)[1] + counts = np.bincount(a, minlength=k) + fr = (counts / counts.sum()).tolist() + # Rounding each fraction independently makes the sum drift off 1.0 by + # ~1e-4, and MPConfig rejects anything outside its tolerance — with more + # levels the drift grows, so the k=6/7/8 sets failed at import time and + # the job exited 0 before loading the model (Slurm reported COMPLETED). + # Absorb the residual into the largest fraction. + fr_r = [round(f, 4) for f in fr] + j = max(range(len(fr_r)), key=lambda i: fr_r[i]) + fr_r[j] = round(fr_r[j] + (1.0 - sum(fr_r)), 10) + out["results"][str(k)] = { + "levels": lv, + "level_fractions": fr_r, + "achieved_avg_cycles": round(float(np.dot(fr, lv)), 2), + "mean_assigned_error": round(s, 6), + "n_subsets_tried": n_tried, + } + print(f"k={k}: levels={lv} fractions={[round(f,3) for f in fr]} " + f"err={s:.6f} (searched {n_tried} subsets)", flush=True) + + # Reference points: what the current hand-picked sets score on the same data. + for name, lv in (cli.compare or {}).items(): + if all(x in grid for x in lv) and min(lv) < budget < max(lv): + s, a = score(E_full[:, [grid.index(x) for x in lv]], lv, budget) + out.setdefault("reference", {})[name] = { + "levels": lv, "mean_assigned_error": round(s, 6)} + print(f" reference {name}: levels={lv} err={s:.6f}", flush=True) + + json.dump(out, open(cli.out, "w"), indent=2) + print(f"wrote {cli.out}", flush=True) + + +def refine(cli): + """Coordinate-descent refinement of a level set on a DENSE measured grid. + + The subset search picks the best k values out of a coarse grid, so its + answer is quantised to that grid: it can return 112 but never 111. The + scmp_llm ladder is full of off-grid values (111, 85, 49, 47, 46, 45, 30, + 19), which is what a search over the values themselves produces. Exhaustive + subset search over every integer stream length is infeasible - C(113, 4) is + 6.8M - so this starts from the coarse-grid optimum and moves one level at a + time to its best nearby value, in the same spirit as the boundary search in + scmp_kernels.mp.auto_calibrator. + """ + d = np.load(cli.grid_file, allow_pickle=True) + E_full, grid = d["errors"], [int(x) for x in d["grid"]] + if cli.max_search_rows and E_full.shape[0] > cli.max_search_rows: + rs = np.random.RandomState(0) + E_full = E_full[np.sort(rs.choice(E_full.shape[0], cli.max_search_rows, replace=False))] + gi = {g: i for i, g in enumerate(grid)} + budget = cli.budget + levels = sorted((int(x) for x in cli.init.split(",")), reverse=True) + for x in levels: + if x not in gi: + raise SystemExit(f"init level {x} not measured; grid is {grid}") + + def sc(lv): + if not (min(lv) < budget < max(lv)): + return float("inf") + return score(E_full[:, [gi[x] for x in lv]], lv, budget)[0] + + best = sc(levels) + print(f" init {levels} err={best:.6f}", flush=True) + for sweep in range(cli.sweeps): + moved = False + for pos in range(len(levels)): + cur = levels[pos] + # candidates: every measured value not already in the set + for cand in grid: + if cand in levels: + continue + trial = sorted(levels[:pos] + [cand] + levels[pos + 1:], reverse=True) + if len(set(trial)) != len(trial): + continue + s = sc(trial) + if s < best - 1e-12: + best, levels, moved = s, trial, True + if levels[pos if pos < len(levels) else -1] != cur: + pass + print(f" sweep {sweep}: {levels} err={best:.6f}", flush=True) + if not moved: + break + + a = score(E_full[:, [gi[x] for x in levels]], levels, budget)[1] + fr = (np.bincount(a, minlength=len(levels)) / len(a)).tolist() + out = {"budget": budget, "levels": levels, + "level_fractions": [round(f, 4) for f in fr], + "achieved_avg_cycles": round(float(np.dot(fr, levels)), 2), + "mean_assigned_error": round(best, 6), + "init": [int(x) for x in cli.init.split(",")]} + json.dump(out, open(cli.out, "w"), indent=2) + print(f"wrote {cli.out}", flush=True) + + +def main(): + p = argparse.ArgumentParser() + sub = p.add_subparsers(dest="cmd", required=True) + + m = sub.add_parser("measure") + m.add_argument("--eval_config", default="configs/evaluation/bridge/frame_ada_sc_full.yaml") + m.add_argument("--keys_file", default="results/diverse_300.json") + m.add_argument("--num_samples", type=int, default=2) + m.add_argument("--inference_steps", type=int, default=10) + m.add_argument("--max_rows", type=int, default=4096) + m.add_argument("--grid", default=None, help="comma-separated halved cycle counts") + m.add_argument("--smooth_scales", default="results/smoothquant_scales.pt", + help="SmoothQuant scales applied in deployment; pass '' to measure without") + m.add_argument("--out", required=True) + m.set_defaults(func=measure) + + s = sub.add_parser("search") + s.add_argument("--grid_file", "--grid", dest="grid_file", required=True) + s.add_argument("--budget", type=float, required=True) + s.add_argument("--k", default="3,5,7") + s.add_argument("--max_search_rows", type=int, default=8192, + help="rows used to score candidate subsets (0 = all)") + s.add_argument("--objective", default="abs", + choices=["abs", "sigma", "sigma2", "delta_sigma2"], + help="'abs' = original absolute RMSE; others = scmp_llm currencies") + s.add_argument("--out", required=True) + s.set_defaults(func=search, compare=None) + + r = sub.add_parser("refine") + r.add_argument("--grid_file", "--grid", dest="grid_file", required=True) + r.add_argument("--budget", type=float, required=True) + r.add_argument("--init", required=True, help="comma-separated starting levels") + r.add_argument("--sweeps", type=int, default=6) + r.add_argument("--max_search_rows", type=int, default=8192) + r.add_argument("--out", required=True) + r.set_defaults(func=refine) + + cli = p.parse_args() + cli.func(cli) + + +if __name__ == "__main__": + main() diff --git a/evaluate/select_diverse_samples.py b/evaluate/select_diverse_samples.py new file mode 100644 index 0000000..80668c0 --- /dev/null +++ b/evaluate/select_diverse_samples.py @@ -0,0 +1,79 @@ +"""Select N diverse test clips from bridge test set (anti-同质化). + +Two-stage: + 1) De-dup by episode: one clip per episode (same-episode clips are near-duplicates). + 2) Farthest-point sampling (FPS) on latent features to pick the N most spread-out. + +Feature = per-(frame,channel) spatial-mean of the latent, z-normalized. +Output: JSON list of N sample keys (episodeid_cam_start), used by the sensitivity sweep. + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... python3 evaluate/select_diverse_samples.py --n 300 \ + --out results/diverse_300.json +""" +import argparse, json, os +import numpy as np +import torch + +BRIDGE_ROOT = os.environ.get( + "BRIDGE_ROOT", "/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge") +LAT = f"{BRIDGE_ROOT}/evaluation_latent_videos/test_sample_latent_videos" + + +def parse_key(fn): + parts = fn[:-3].split("_") + return "_".join(parts[:-2]), parts[-2], parts[-1] + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--n", type=int, default=300) + p.add_argument("--out", required=True) + p.add_argument("--seed", type=int, default=0) + cli = p.parse_args() + + files = sorted(f for f in os.listdir(LAT) if f.endswith(".pt")) + by_ep = {} + for f in files: + eid, cam, start = parse_key(f) + by_ep.setdefault(eid, f) + reps = sorted(by_ep.values()) + print(f"{len(files)} clips -> {len(reps)} unique-episode reps", flush=True) + + if cli.n >= len(reps): + keys = [f[:-3] for f in reps] + os.makedirs(os.path.dirname(cli.out) or ".", exist_ok=True) + json.dump(keys, open(cli.out, "w"), indent=2) + print(f"n>=reps, took all {len(keys)}"); return + + feats = [] + for i, f in enumerate(reps): + lat = torch.load(os.path.join(LAT, f), map_location="cpu", weights_only=False) + feats.append(lat.float().mean(dim=(2, 3)).flatten().numpy()) + if (i + 1) % 300 == 0: + print(f" loaded {i+1}/{len(reps)} features", flush=True) + X = np.stack(feats).astype(np.float64) + X = (X - X.mean(0)) / (X.std(0) + 1e-8) + + # farthest-point sampling, deterministic start = point nearest the centroid + start = int(((X - X.mean(0)) ** 2).sum(1).argmin()) + sel = [start] + d = np.full(len(X), np.inf) + for _ in range(cli.n - 1): + d = np.minimum(d, ((X - X[sel[-1]]) ** 2).sum(1)) + sel.append(int(d.argmax())) + keys = [reps[i][:-3] for i in sel] + + os.makedirs(os.path.dirname(cli.out) or ".", exist_ok=True) + json.dump(keys, open(cli.out, "w"), indent=2) + # diversity report: min pairwise distance among selected (higher = more spread) + S = X[sel]; dmin = np.inf + for i in range(len(S) - 1): + dd = ((S[i + 1:] - S[i]) ** 2).sum(1) + if len(dd): + dmin = min(dmin, float(dd.min()) ** 0.5) + print(f"wrote {cli.out} ({len(keys)} keys); FPS min-pairwise-dist = {dmin:.3f}") + + +if __name__ == "__main__": + main() diff --git a/evaluate/select_mp_or_uniform.py b/evaluate/select_mp_or_uniform.py new file mode 100644 index 0000000..3b32e0a --- /dev/null +++ b/evaluate/select_mp_or_uniform.py @@ -0,0 +1,55 @@ +"""Validation gate with uniform fallback. + +Uniform is a feasible point of the MP search space, so a correctly selected +schedule can never deploy worse than uniform — enforce that by construction: +every candidate is compared PAIRED against uniform on the same keys, on the +TRUE metrics, and the deployment is the argmax with uniform as the floor. + + python evaluate/select_mp_or_uniform.py --uniform scr10_UNI96 \ + --candidates scr10_sc_avg192,scr10w_sc_avg192_sens --margin 0.0 +""" +import argparse, glob, json, os + +P = "results/local_n_eval" + + +def load(tag): + return {os.path.basename(f)[:-5]: json.load(open(f)) + for f in glob.glob(f"{P}/{tag}/metrics/*.json")} + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--uniform", required=True) + ap.add_argument("--candidates", required=True, help="comma-separated tags") + ap.add_argument("--margin", type=float, default=0.0, help="required paired dPSNR") + ap.add_argument("--ssim_guard", type=float, default=0.005) + ap.add_argument("--l2_guard", type=float, default=0.005) + a = ap.parse_args() + + U = load(a.uniform) + best, rows = None, [] + for tag in a.candidates.split(","): + M = load(tag) + ks = sorted(set(M) & set(U)) + if not ks: + rows.append((tag, None)); continue + dp = sum(M[k]["psnr"] - U[k]["psnr"] for k in ks) / len(ks) + ds = sum(M[k]["ssim"] - U[k]["ssim"] for k in ks) / len(ks) + dl = sum(M[k]["latent_l2"] - U[k]["latent_l2"] for k in ks) / len(ks) + ok = dp > a.margin and ds >= -a.ssim_guard and dl <= a.l2_guard + rows.append((tag, (len(ks), dp, ds, dl, ok))) + if ok and (best is None or dp > best[1]): + best = (tag, dp) + + print(f"{'candidate':34} {'n':>3} {'dPSNR':>8} {'dSSIM':>8} {'dL2':>8} gate") + for tag, r in rows: + if r is None: + print(f"{tag:34} no paired data"); continue + n, dp, ds, dl, ok = r + print(f"{tag:34} {n:3} {dp:+8.3f} {ds:+8.4f} {dl:+8.4f} {'PASS' if ok else 'fail'}") + print(f"\nDEPLOY: {best[0] if best else a.uniform + ' (uniform fallback — degenerate solution)'}") + + +if __name__ == "__main__": + main() diff --git a/evaluate/sensitivity_block_sweep.py b/evaluate/sensitivity_block_sweep.py new file mode 100644 index 0000000..b6a9339 --- /dev/null +++ b/evaluate/sensitivity_block_sweep.py @@ -0,0 +1,131 @@ +"""Block-level SC sensitivity sweep using per-clip GT latents (local data only). + +Unlike sensitivity_sweep.py this does NOT need the per-episode latent dir +(dataset get_dataset); it iterates the same per-clip GT latents as +eval_local_n_samples.py, so it runs off the partially-extracted bridge data. + +For each block i in 0..depth-1, skip ALL SC ops in block i (leave-one-out, +i.e. "escape" the whole block back to FP) and record mean latent L2 vs GT. +A reference run with no skips (SC uniform) is recorded as "none". + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N \ + python3 evaluate/sensitivity_block_sweep.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --num_samples 3 --inference_steps 50 \ + --out_json results/sensitivity_block_sc_full.json +""" +from __future__ import annotations + +import argparse +import json +import os +import time + +import numpy as np +import torch +import torch.nn.functional as F +from omegaconf import OmegaConf +from diffusers.models import AutoencoderKL + +from models.sc_integration import reconfigure, set_skip_blocks, clear_skip_blocks +from evaluate.eval_local_n_samples import ( + BRIDGE_ROOT, GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, parse_key, +) + +ALL_OPS = ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2") + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config", required=True) + p.add_argument("--depth", type=int, default=28) + p.add_argument("--num_samples", type=int, default=3) + p.add_argument("--inference_steps", type=int, default=50) + p.add_argument("--scheduler", choices=["PNDM", "DPM"], default="PNDM") + p.add_argument("--out_json", required=True) + p.add_argument("--block_start", type=int, default=0) + p.add_argument("--block_end", type=int, default=None) + p.add_argument("--skip_reference", action="store_true", + help="skip the no-skip SC-uniform reference run (when chunking)") + cli = p.parse_args() + + args = build_args(cli.config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + clear_skip_blocks() + pipe = make_pipe(args, vae, model, cli.scheduler) + + # Cache samples (same ordering as eval_local_n_samples). + files = sorted(f for f in os.listdir(GT_LATENT_DIR) if f.endswith(".pt"))[: cli.num_samples] + samples = [] + for fn in files: + eid, cam, start = parse_key(fn) + key = f"{eid}_{cam}_{start}" + ann_path = os.path.join(ANNOT_DIR, f"{eid}.json") + if not os.path.exists(ann_path): + continue + gt_lat = torch.load(os.path.join(GT_LATENT_DIR, fn), weights_only=False, map_location=device) + with open(ann_path) as f: + ann = json.load(f) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + actions = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + samples.append({"key": key, "mask_x": gt_lat[0:1].unsqueeze(0), + "actions": actions, "gt_lat": gt_lat}) + print(f"cached {len(samples)} samples; variant={args.attention_mode} " + f"steps={cli.inference_steps} sched={cli.scheduler}", flush=True) + + def eval_setting(label): + l2s = {} + for s in samples: + with torch.no_grad(): + _, lat = pipe( + s["actions"].to(device).float(), + mask_x=s["mask_x"].to(device).float(), + video_length=args.num_frames, + height=args.video_size[0], width=args.video_size[1], + num_inference_steps=args.infer_num_sampling_steps, + guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only", + ) + lat = lat.squeeze(0) + l2s[s["key"]] = F.mse_loss(lat[1:], s["gt_lat"][1:]).item() + mean = sum(l2s.values()) / len(l2s) + print(f"[{time.strftime('%H:%M:%S')}] {label}: mean L2={mean:.4f} " + f"{ {k: round(v,4) for k,v in l2s.items()} }", flush=True) + return {"mean_l2": mean, "per_sample": l2s} + + out = {"config": cli.config, "attention_mode": args.attention_mode, + "depth": cli.depth, "steps": cli.inference_steps, + "samples": [s["key"] for s in samples], "results": {}} + os.makedirs(os.path.dirname(cli.out_json) or ".", exist_ok=True) + + def save(): + with open(cli.out_json, "w") as f: + json.dump(out, f, indent=2) + + if not cli.skip_reference: + clear_skip_blocks() + out["results"]["none"] = eval_setting("SC uniform (no skip)") + save() + + end = cli.block_end if cli.block_end is not None else cli.depth + for i in range(cli.block_start, end): + for op in ALL_OPS: + set_skip_blocks(op, [i]) + out["results"][str(i)] = eval_setting(f"skip block {i} (all ops)") + save() + clear_skip_blocks() + print("DONE", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/sensitivity_op_block_sweep.py b/evaluate/sensitivity_op_block_sweep.py new file mode 100644 index 0000000..efc2a70 --- /dev/null +++ b/evaluate/sensitivity_op_block_sweep.py @@ -0,0 +1,127 @@ +"""Per-(block, op) SC sensitivity sweep — leave-one-out at operator granularity. + +For each (block b, op o) with o in the 6 SC ops, keep every other op on SC +(sc_int8_full) and revert ONLY (b, o) back to FP; measure latent L2. Lower L2 +(bigger improvement over the no-skip SC-uniform baseline) = that single +operator is a bigger SC-noise source. Ranking all 168 (b,o) lets us fix the +"most-sensitive 10%" (~17 ops) as a permanent skip set. + +Loads model/VAE/samples ONCE and loops all configs (cheap per-config: just +set_skip_blocks + a short eval). Shard across GPUs by block range. + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N \ + python3 evaluate/sensitivity_op_block_sweep.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --num_samples 3 --inference_steps 10 --scheduler DPM \ + --block_start 0 --block_end 4 \ + --out_json results/opblock/sens_0_3.json +""" +from __future__ import annotations + +import argparse +import json +import os +import time + +import numpy as np +import torch +import torch.nn.functional as F +from diffusers.models import AutoencoderKL + +from models.sc_integration import reconfigure, set_skip_blocks, clear_skip_blocks +from evaluate.eval_local_n_samples import ( + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, parse_key, +) + +ALL_OPS = ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2") + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config", required=True) + p.add_argument("--depth", type=int, default=28) + p.add_argument("--num_samples", type=int, default=3) + p.add_argument("--inference_steps", type=int, default=10) + p.add_argument("--scheduler", choices=["PNDM", "DPM"], default="DPM") + p.add_argument("--out_json", required=True) + p.add_argument("--block_start", type=int, default=0) + p.add_argument("--block_end", type=int, default=None) + p.add_argument("--skip_reference", action="store_true") + cli = p.parse_args() + + args = build_args(cli.config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + clear_skip_blocks() + pipe = make_pipe(args, vae, model, cli.scheduler) + + files = sorted(f for f in os.listdir(GT_LATENT_DIR) if f.endswith(".pt"))[: cli.num_samples] + samples = [] + for fn in files: + eid, cam, start = parse_key(fn) + ann_path = os.path.join(ANNOT_DIR, f"{eid}.json") + if not os.path.exists(ann_path): + continue + gt_lat = torch.load(os.path.join(GT_LATENT_DIR, fn), weights_only=False, map_location=device) + with open(ann_path) as f: + ann = json.load(f) + if start + SEQUENCE_LENGTH > len(ann["state"]): + continue + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + actions = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + samples.append({"key": f"{eid}_{cam}_{start}", "mask_x": gt_lat[0:1].unsqueeze(0), + "actions": actions, "gt_lat": gt_lat}) + print(f"cached {len(samples)} samples; variant={args.attention_mode} " + f"blocks[{cli.block_start},{cli.block_end}) steps={cli.inference_steps}", flush=True) + + def eval_mean_l2(): + l2s = [] + for s in samples: + with torch.no_grad(): + _, lat = pipe( + s["actions"].to(device).float(), mask_x=s["mask_x"].to(device).float(), + video_length=args.num_frames, height=args.video_size[0], width=args.video_size[1], + num_inference_steps=args.infer_num_sampling_steps, guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only", + ) + l2s.append(F.mse_loss(lat.squeeze(0)[1:], s["gt_lat"][1:]).item()) + return sum(l2s) / len(l2s) + + out = {"config": cli.config, "attention_mode": args.attention_mode, + "depth": cli.depth, "steps": cli.inference_steps, + "samples": [s["key"] for s in samples], "results": {}} + os.makedirs(os.path.dirname(cli.out_json) or ".", exist_ok=True) + + def save(): + with open(cli.out_json, "w") as f: + json.dump(out, f, indent=2) + + if not cli.skip_reference: + clear_skip_blocks() + ref = eval_mean_l2() + out["reference_no_skip"] = ref + print(f"[{time.strftime('%H:%M:%S')}] SC-uniform baseline L2={ref:.4f}", flush=True) + save() + + end = cli.block_end if cli.block_end is not None else cli.depth + for b in range(cli.block_start, end): + for op in ALL_OPS: + clear_skip_blocks() + set_skip_blocks(op, [b]) + l2 = eval_mean_l2() + out["results"][f"{b}:{op}"] = l2 + print(f"[{time.strftime('%H:%M:%S')}] skip ({b},{op}) L2={l2:.4f}", flush=True) + save() + clear_skip_blocks() + print("DONE", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/sensitivity_shard.py b/evaluate/sensitivity_shard.py new file mode 100644 index 0000000..f9b161b --- /dev/null +++ b/evaluate/sensitivity_shard.py @@ -0,0 +1,107 @@ +"""One sensitivity task unit: single block (leave-one-out, all 6 ops) over a +slice of the diverse sample list. Per-sample result files enable resume. + +block = -1 means the reference run (no skip, SC uniform baseline). +Each sample writes out_dir/block_{block}/{key}.json = {"key","block","l2"}. +Already-present result files are skipped, so the GPU scheduler can re-dispatch +any (block, key-slice) freely without recomputation. + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N python3 evaluate/sensitivity_shard.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --block 4 --keys_file results/diverse_300.json --key_start 0 --key_end 25 \ + --inference_steps 50 --scheduler PNDM --out_dir results/sens300 +""" +import argparse, json, os +import numpy as np, torch +import torch.nn.functional as F +from diffusers.models import AutoencoderKL + +from models.sc_integration import reconfigure, set_skip_blocks, clear_skip_blocks +from evaluate.eval_local_n_samples import ( + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, +) + +ALL_OPS = ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2") + + +def key_parts(k): + parts = k.split("_") + return "_".join(parts[:-2]), int(parts[-2]), int(parts[-1]) + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config", required=True) + p.add_argument("--block", type=int, required=True) # -1 = reference (no skip) + p.add_argument("--keys_file", required=True) + p.add_argument("--key_start", type=int, default=0) + p.add_argument("--key_end", type=int, default=None) + p.add_argument("--inference_steps", type=int, default=50) + p.add_argument("--scheduler", default="PNDM") + p.add_argument("--out_dir", required=True) + cli = p.parse_args() + + all_keys = json.load(open(cli.keys_file)) + end = cli.key_end if cli.key_end is not None else len(all_keys) + keys = all_keys[cli.key_start:end] + + bdir = os.path.join(cli.out_dir, f"block_{cli.block}") + os.makedirs(bdir, exist_ok=True) + todo = [k for k in keys if not os.path.exists(os.path.join(bdir, f"{k}.json"))] + if not todo: + print(f"block {cli.block} keys[{cli.key_start}:{end}] ALL DONE", flush=True) + return + + args = build_args(cli.config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + reconfigure(args.attention_mode) + clear_skip_blocks() + if cli.block >= 0: + for op in ALL_OPS: + set_skip_blocks(op, [cli.block]) + pipe = make_pipe(args, vae, model, cli.scheduler) + tag = "ref(no-skip)" if cli.block < 0 else f"skip block {cli.block}" + print(f"[{tag}] todo {len(todo)}/{len(keys)} steps={cli.inference_steps} sched={cli.scheduler}", flush=True) + + for k in todo: + outp = os.path.join(bdir, f"{k}.json") + if os.path.exists(outp): + continue + try: + eid, cam, start = key_parts(k) + ann_path = os.path.join(ANNOT_DIR, f"{eid}.json") + if not os.path.exists(ann_path): + json.dump({"key": k, "block": cli.block, "l2": None, "err": "no_annotation"}, open(outp, "w")) + continue + gt_lat = torch.load(os.path.join(GT_LATENT_DIR, f"{k}.pt"), weights_only=False, map_location=device) + ann = json.load(open(ann_path)) + if start + SEQUENCE_LENGTH > len(ann["state"]): + json.dump({"key": k, "block": cli.block, "l2": None, "err": "oob"}, open(outp, "w")) + continue + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + actions = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + mask_x = gt_lat[0:1].unsqueeze(0) + with torch.no_grad(): + _, lat = pipe( + actions.to(device).float(), mask_x=mask_x.to(device).float(), + video_length=args.num_frames, height=args.video_size[0], width=args.video_size[1], + num_inference_steps=args.infer_num_sampling_steps, guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only", + ) + l2 = F.mse_loss(lat.squeeze(0)[1:], gt_lat[1:]).item() + json.dump({"key": k, "block": cli.block, "l2": round(l2, 6)}, open(outp, "w")) + print(f" [{tag}] {k} L2={l2:.4f}", flush=True) + except Exception as e: + print(f" [{tag}] {k} FAILED: {e}", flush=True) + print(f"[{tag}] shard done", flush=True) + + +if __name__ == "__main__": + main() diff --git a/evaluate/sensitivity_shard_loi.py b/evaluate/sensitivity_shard_loi.py new file mode 100644 index 0000000..853ab66 --- /dev/null +++ b/evaluate/sensitivity_shard_loi.py @@ -0,0 +1,119 @@ +"""Leave-one-IN sensitivity shard (aligned with the repo's original +sensitivity_sweep.py method, extended to all 6 ops): + +For target (op, block): ONLY `op` is SC-enabled, and its skip set = all blocks +EXCEPT `block` — i.e. exactly one operator instance runs on SC, everything +else is FP. Sensitivity of (op, block) = how much latent L2 rises vs the pure +FP reference. Network is ~all-FP so each sample is fast (~30-40s @PNDM50). + +block = -1 with op = "fp" means the pure-FP reference run. + +Per-sample result files (out_dir/loi_{op}_{block}/{key}.json) enable resume. + +Usage: + PYTHONPATH=. BRIDGE_ROOT=... CUDA_VISIBLE_DEVICES=N python3 evaluate/sensitivity_shard_loi.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml \ + --op mlp_fc2 --block 4 --keys_file results/diverse_300.json \ + --key_start 0 --key_end 100 --out_dir /edrive2/qiuyid/sens300_loi +""" +import argparse, json, os +import numpy as np, torch +import torch.nn.functional as F +from diffusers.models import AutoencoderKL + +from models.sc_integration import reconfigure, set_skip_blocks, clear_skip_blocks, get_config +from evaluate.eval_local_n_samples import ( + GT_LATENT_DIR, ANNOT_DIR, C_ACT_SCALER, SEQUENCE_LENGTH, + build_args, load_model, make_pipe, compute_actions_for_slice, +) + +ALL_OPS = ("qkv", "qk", "av", "proj", "mlp_fc1", "mlp_fc2") + + +def key_parts(k): + parts = k.split("_") + return "_".join(parts[:-2]), int(parts[-2]), int(parts[-1]) + + +def main(): + p = argparse.ArgumentParser() + p.add_argument("--config", required=True) + p.add_argument("--op", required=True, choices=list(ALL_OPS) + ["fp"]) + p.add_argument("--block", type=int, required=True) # -1 + op=fp -> FP reference + p.add_argument("--keys_file", required=True) + p.add_argument("--key_start", type=int, default=0) + p.add_argument("--key_end", type=int, default=None) + p.add_argument("--inference_steps", type=int, default=50) + p.add_argument("--scheduler", default="PNDM") + p.add_argument("--depth", type=int, default=28) + p.add_argument("--out_dir", required=True) + cli = p.parse_args() + + all_keys = json.load(open(cli.keys_file)) + end = cli.key_end if cli.key_end is not None else len(all_keys) + keys = all_keys[cli.key_start:end] + + tag = "fp_ref" if cli.op == "fp" else f"{cli.op}_{cli.block}" + bdir = os.path.join(cli.out_dir, f"loi_{tag}") + os.makedirs(bdir, exist_ok=True) + todo = [k for k in keys if not os.path.exists(os.path.join(bdir, f"{k}.json"))] + if not todo: + print(f"[{tag}] keys[{cli.key_start}:{end}] ALL DONE", flush=True) + return + + args = build_args(cli.config, cli.inference_steps) + device = torch.device("cuda:0") + vae = AutoencoderKL.from_pretrained(args.vae_model_path, subfolder="vae").to(device).eval() + vae.requires_grad_(False) + model = load_model(args, device) + + # leave-one-in: enable ONLY target op, and only at target block + reconfigure(args.attention_mode) + clear_skip_blocks() + cfg = get_config() + for f in ALL_OPS: + setattr(cfg, f"enable_{f}", False) + if cli.op != "fp": + setattr(cfg, f"enable_{cli.op}", True) + set_skip_blocks(cli.op, [b for b in range(cli.depth) if b != cli.block]) + + pipe = make_pipe(args, vae, model, cli.scheduler) + print(f"[LOI {tag}] todo {len(todo)}/{len(keys)} steps={cli.inference_steps} " + f"sched={cli.scheduler}", flush=True) + + for k in todo: + outp = os.path.join(bdir, f"{k}.json") + if os.path.exists(outp): + continue + try: + eid, cam, start = key_parts(k) + ann_path = os.path.join(ANNOT_DIR, f"{eid}.json") + if not os.path.exists(ann_path): + json.dump({"key": k, "tag": tag, "l2": None, "err": "no_annotation"}, open(outp, "w")) + continue + gt_lat = torch.load(os.path.join(GT_LATENT_DIR, f"{k}.pt"), weights_only=False, map_location=device) + ann = json.load(open(ann_path)) + if start + SEQUENCE_LENGTH > len(ann["state"]): + json.dump({"key": k, "tag": tag, "l2": None, "err": "oob"}, open(outp, "w")) + continue + arm = np.array(ann["state"])[start:start + SEQUENCE_LENGTH, :6] + grip = np.array(ann["continuous_gripper_state"])[start:start + SEQUENCE_LENGTH] + actions = torch.from_numpy( + compute_actions_for_slice(arm, grip) * C_ACT_SCALER).float().unsqueeze(0) + with torch.no_grad(): + _, lat = pipe( + actions.to(device).float(), mask_x=gt_lat[0:1].unsqueeze(0).to(device).float(), + video_length=args.num_frames, height=args.video_size[0], width=args.video_size[1], + num_inference_steps=args.infer_num_sampling_steps, guidance_scale=args.guidance_scale, + device=device, return_dict=False, output_type="latent_only", + ) + l2 = F.mse_loss(lat.squeeze(0)[1:], gt_lat[1:]).item() + json.dump({"key": k, "tag": tag, "l2": round(l2, 6)}, open(outp, "w")) + print(f" [{tag}] {k} L2={l2:.4f}", flush=True) + except Exception as e: + print(f" [{tag}] {k} FAILED: {e}", flush=True) + print(f"[LOI {tag}] shard done", flush=True) + + +if __name__ == "__main__": + main() diff --git a/kernels b/kernels new file mode 160000 index 0000000..fd0982e --- /dev/null +++ b/kernels @@ -0,0 +1 @@ +Subproject commit fd0982ec36895bebcadc0c23e14d50971f9c24d3 diff --git a/models/irasim.py b/models/irasim.py index 3c12f14..5f5561a 100644 --- a/models/irasim.py +++ b/models/irasim.py @@ -89,7 +89,7 @@ def forward(self, x): configure(self.attention_mode) # idempotent b = self.block_idx - qkv_out = sc_linear_forward(x, self.qkv) if is_op_enabled("qkv", b) else self.qkv(x) + qkv_out = sc_linear_forward(x, self.qkv, op="qkv", block_idx=b) if is_op_enabled("qkv", b) else self.qkv(x) qkv = qkv_out.reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4).contiguous() q, k, v = qkv.unbind(0) q_scaled = q * self.scale @@ -107,7 +107,7 @@ def forward(self, x): x = (attn @ v).transpose(1, 2).reshape(B, N, C) if is_op_enabled("proj", b): - x = sc_linear_forward(x, self.proj) + x = sc_linear_forward(x, self.proj, op="proj", block_idx=b) x = self.proj_drop(x) return x # fall through to standard proj below diff --git a/models/sc_integration/__init__.py b/models/sc_integration/__init__.py index 3f4f66f..a4b5130 100644 --- a/models/sc_integration/__init__.py +++ b/models/sc_integration/__init__.py @@ -1,21 +1,22 @@ -"""SC (Stochastic Computing) int8 QK replacement for IRASim. +"""SC (Stochastic Computing) int8 replacement ops for IRASim. -Pulls SC kernels from /home/dingqy/Bench/scmp_llm/SC/ without copying code. -""" -import os -import sys +The actual SC Triton kernels live in the ``scmp_kernels`` package, vendored as +a git submodule at ``kernels/`` (repo root) and installed editable with +``pip install -e ./kernels``. This package only holds the IRASim-specific glue +(attention / linear / MLP drop-ins + the global SC controller); the kernels +themselves are shared with the other SC applications, so kernel updates +propagate here automatically by bumping the submodule. -_SC_KERNEL_ROOT = os.environ.get( - "IRASIM_SC_KERNEL_ROOT", - "/home/dingqy/Bench/scmp_llm/SC", -) -if _SC_KERNEL_ROOT not in sys.path: - sys.path.insert(0, _SC_KERNEL_ROOT) +If imports below fail with ``ModuleNotFoundError: scmp_kernels``, the submodule +is not installed — run:: -from .sc_attention import sc_qk_matmul, sc_av_matmul # noqa: E402 -from .sc_linear import sc_linear_forward # noqa: E402 -from .sc_mlp import SCMlp # noqa: E402 -from .sc_controller import ( # noqa: E402 + git submodule update --init --recursive + pip install -e ./kernels +""" +from .sc_attention import sc_qk_matmul, sc_av_matmul +from .sc_linear import sc_linear_forward +from .sc_mlp import SCMlp +from .sc_controller import ( configure, reconfigure, get_config, diff --git a/models/sc_integration/sc_attention.py b/models/sc_integration/sc_attention.py index 0b17caf..4953e9a 100644 --- a/models/sc_integration/sc_attention.py +++ b/models/sc_integration/sc_attention.py @@ -1,33 +1,39 @@ -"""Int8 SC QK matmul for IRASim attention. - -Only the Q @ K^T step is replaced. Softmax, dropout, attn @ V, and projections -remain FP32. The kernel is imported from the shared scmp_llm SC library. +"""Bipolar int8 SC attention matmuls (Q·Kᵀ and softmax·V) for IRASim. + +Both ops route through the shared ``scmp_kernels.sc_matmul`` dispatcher with +``granularity="per_head"`` (one ``(max, min)`` per attention head). Only these +two matmuls are replaced; softmax, dropout, and the projections stay FP32. The +dispatcher computes ``a @ b.T`` and auto-detects the per-head batched layout +from the 3D shape, so it handles the non-square attn·V case directly — no +local kernel orchestration needed. """ from __future__ import annotations -import torch +import os -import triton +import torch -from sc_triton import ( - sc_matmul_enable_batched_bipolar, - sc_matmul_enable_triton, - fused_quant_bipolar_batched_kernel, - enable_matmul_bipolar_batched_kernel, - _get_cached_sequences, - _get_cached_enable_tables, - _COMPACT_ENABLE_THRESHOLD_BYTES, -) -from config_helpers import make_sobol_simple_config +from scmp_kernels import sc_matmul +from scmp_kernels.sc.config_helpers import make_sobol_simple_config _CONFIG_CACHE: dict[tuple[int, int], dict] = {} +# SC_HALVE=1: uSystolic bipolar stream halving (stoc_len=None lets the kernel +# derive 2**(sc_prec-1)). Same knob as sc_linear.py / scmp_diffusion. +_HALVE = os.environ.get("SC_HALVE") == "1" -def _get_config(head_dim: int, sc_prec: int) -> dict: - key = (head_dim, sc_prec) + +def _get_config(contraction_dim: int, sc_prec: int) -> dict: + """Cache one Sobol RNG/SNG config per (contraction dim, precision). + + ``contraction_dim`` is the inner (summed) dimension of the matmul: the + head dim ``D`` for Q·Kᵀ, the key length ``Nk`` for softmax·V, and the input + feature count for linear layers. + """ + key = (contraction_dim, sc_prec) cfg = _CONFIG_CACHE.get(key) if cfg is None: - cfg = make_sobol_simple_config(head_dim, head_dim, sc_prec) + cfg = make_sobol_simple_config(contraction_dim, contraction_dim, sc_prec) _CONFIG_CACHE[key] = cfg return cfg @@ -38,7 +44,7 @@ def sc_qk_matmul( sc_prec: int = 8, stoc_len: int | None = None, ) -> torch.Tensor: - """Bipolar int8 SC QK matmul. + """Bipolar int8 SC Q·Kᵀ matmul. Args: q_scaled: (B, H, N, D) — Q already multiplied by 1/sqrt(D). @@ -47,151 +53,64 @@ def sc_qk_matmul( stoc_len: Stochastic stream length. Defaults to 2**sc_prec. Returns: - (B, H, N, N) float32 attention logits. + (B, H, N, N) attention logits in q_scaled.dtype. """ B, H, N, D = q_scaled.shape - if stoc_len is None: + if stoc_len is None and not _HALVE: stoc_len = 2 ** sc_prec config = _get_config(D, sc_prec) q_flat = q_scaled.reshape(B * H, N, D).float().contiguous() k_flat = k.reshape(B * H, N, D).float().contiguous() - q_maxs = q_flat.amax(dim=(1, 2)) - q_mins = q_flat.amin(dim=(1, 2)) - k_maxs = k_flat.amax(dim=(1, 2)) - k_mins = k_flat.amin(dim=(1, 2)) - - out = sc_matmul_enable_batched_bipolar( + out = sc_matmul( q_flat, k_flat, - q_maxs, q_mins, k_maxs, k_mins, - sc_prec, config, stoc_len=stoc_len, + granularity="per_head", + mode="bipolar", + sc_prec=sc_prec, + stoc_len=stoc_len, + config=config, + halve_bipolar_stoc_len=_HALVE, ) return out.reshape(B, H, N, N).to(q_scaled.dtype) -def _sc_matmul_enable_batched_bipolar_nm( - a_flat: torch.Tensor, # (BH, N, K) - b_flat: torch.Tensor, # (BH, M, K) - a_maxs: torch.Tensor, # (BH,) - a_mins: torch.Tensor, - b_maxs: torch.Tensor, - b_mins: torch.Tensor, - sc_prec: int, - config: dict, - stoc_len: int, -) -> torch.Tensor: - """BH-batched bipolar int8 SC matmul with N != M. - - Structurally identical to sc_matmul_enable_batched_bipolar but does not - hard-code M = N (that version is QK-only). Output: (BH, N, M). - """ - a_flat = a_flat.contiguous() - b_flat = b_flat.contiguous() - BH, N, K = a_flat.shape - M = b_flat.shape[1] - assert b_flat.shape[2] == K and b_flat.shape[0] == BH - device = a_flat.device - - q_max = 2 ** (sc_prec - 1) - 1 - q_min = -(2 ** (sc_prec - 1)) - max_rng_val = 2 ** sc_prec - q_max_sq = float(q_max * q_max) - - abs_max_a = torch.maximum(a_maxs.abs(), a_mins.abs()).clamp(min=1e-5) - abs_max_b = torch.maximum(b_maxs.abs(), b_mins.abs()).clamp(min=1e-5) - scale_a = abs_max_a / q_max - scale_b = abs_max_b / q_max - inv_scale_a = 1.0 / scale_a - inv_scale_b = 1.0 / scale_b - - # Quantize a and b — note the quant kernel writes transposed (BH, K, N/M). - boundary_a = torch.empty(BH, K, N, dtype=torch.int16, device=device) - sign_a = torch.empty(BH, K, N, dtype=torch.int8, device=device) - boundary_b = torch.empty(BH, K, M, dtype=torch.int16, device=device) - sign_b = torch.empty(BH, K, M, dtype=torch.int8, device=device) - - BLOCK = 1024 - slice_a = N * K - slice_b = M * K - fused_quant_bipolar_batched_kernel[(triton.cdiv(slice_a, BLOCK), BH)]( - a_flat, boundary_a, sign_a, inv_scale_a, - q_max, q_min, max_rng_val, slice_a, N, K, BLOCK, - ) - fused_quant_bipolar_batched_kernel[(triton.cdiv(slice_b, BLOCK), BH)]( - b_flat, boundary_b, sign_b, inv_scale_b, - q_max, q_min, max_rng_val, slice_b, M, K, BLOCK, - ) - - rand_seqs_a_t, rand_seqs_b_t = _get_cached_sequences(config, sc_prec, device) - V = 2 ** sc_prec + 1 - cum_table_bytes = K * (stoc_len + 1) * V * 2 - if cum_table_bytes > _COMPACT_ENABLE_THRESHOLD_BYTES: - raise RuntimeError( - "Compact enable path not supported in N!=M variant; shrink K or stoc_len." - ) - cum_indicator, k_table = _get_cached_enable_tables( - config, sc_prec, device, rand_seqs_a_t, rand_seqs_b_t, stoc_len) - V_actual = cum_indicator.shape[2] - out_scale = scale_a * scale_b # (BH,) - - output = torch.empty(BH, N, M, dtype=torch.float32, device=device) - if N <= 64 or M <= 64: - BLOCK_M, BLOCK_N = 16, 16 - else: - BLOCK_M, BLOCK_N = 32, 32 - if K >= 4 and K % 4 == 0: - BLOCK_K = 4 - elif K % 2 == 0: - BLOCK_K = 2 - else: - BLOCK_K = 1 - nw = 8 if BLOCK_M == 32 else 2 - grid_mm = (triton.cdiv(N, BLOCK_M), triton.cdiv(M, BLOCK_N), BH) - enable_matmul_bipolar_batched_kernel[grid_mm]( - cum_indicator, k_table, - boundary_a, boundary_b, - sign_a, sign_b, - output, out_scale, - N, M, K, - stoc_len, V_actual, q_max_sq, - BLOCK_M, BLOCK_N, BLOCK_K, - num_warps=nw, - ) - return output - - def sc_av_matmul( attn: torch.Tensor, v: torch.Tensor, sc_prec: int = 8, stoc_len: int | None = None, ) -> torch.Tensor: - """Bipolar int8 SC attn @ V matmul, BH-batched (single kernel launch). + """Bipolar int8 SC (softmax·V) matmul, per-head batched. + + Args: + attn: (B, H, N, Nk) — softmax output. + v: (B, H, Nk, D) — value. + sc_prec: SC bit precision (8 ⇒ int8). + stoc_len: Stochastic stream length. Defaults to 2**sc_prec. - attn: (B, H, N, Nk) — softmax output - v: (B, H, Nk, D) — value Returns: (B, H, N, D) in attn.dtype. """ B, H, N, Nk = attn.shape _, _, _, D = v.shape - if stoc_len is None: + if stoc_len is None and not _HALVE: stoc_len = 2 ** sc_prec - # Inner contraction dim for AV is Nk (seq length). + # Inner contraction dim for attn·V is Nk (key/sequence length). config = _get_config(Nk, sc_prec) a_flat = attn.reshape(B * H, N, Nk).float().contiguous() + # sc_matmul computes a @ b.T, so feed V transposed to (BH, D, Nk); + # b.T then restores (BH, Nk, D) and a @ b.T == attn @ V. v_t_flat = v.transpose(-1, -2).reshape(B * H, D, Nk).float().contiguous() - a_maxs = a_flat.amax(dim=(1, 2)) - a_mins = a_flat.amin(dim=(1, 2)) - v_maxs = v_t_flat.amax(dim=(1, 2)) - v_mins = v_t_flat.amin(dim=(1, 2)) - - out = _sc_matmul_enable_batched_bipolar_nm( + out = sc_matmul( a_flat, v_t_flat, - a_maxs, a_mins, v_maxs, v_mins, - sc_prec, config, stoc_len, + granularity="per_head", + mode="bipolar", + sc_prec=sc_prec, + stoc_len=stoc_len, + config=config, + halve_bipolar_stoc_len=_HALVE, ) return out.reshape(B, H, N, D).to(attn.dtype) diff --git a/models/sc_integration/sc_controller.py b/models/sc_integration/sc_controller.py index ea5e4b1..3162822 100644 --- a/models/sc_integration/sc_controller.py +++ b/models/sc_integration/sc_controller.py @@ -96,3 +96,21 @@ def clear_skip_blocks(op: str = None) -> None: _cfg.skip_blocks.clear() elif op in _cfg.skip_blocks: del _cfg.skip_blocks[op] + + +# ---- diffusion step tracking (for per-timestep stream-length schedules) ---- +# Row-level MP failed because no runtime-observable signal ranks rows +# (Spearman vs true sensitivity = 0.02). A per-TIMESTEP schedule needs no +# such signal: the step index is exact, and diffusion steps are known to +# differ in sensitivity. The sampling pipeline publishes the step here. +_CURRENT_STEP = 0 +_TOTAL_STEPS = 1 + + +def set_current_step(i: int, total: int) -> None: + global _CURRENT_STEP, _TOTAL_STEPS + _CURRENT_STEP, _TOTAL_STEPS = int(i), max(int(total), 1) + + +def get_current_step() -> tuple: + return _CURRENT_STEP, _TOTAL_STEPS diff --git a/models/sc_integration/sc_linear.py b/models/sc_integration/sc_linear.py index e21e0ac..6f9294b 100644 --- a/models/sc_integration/sc_linear.py +++ b/models/sc_integration/sc_linear.py @@ -1,21 +1,232 @@ -"""Int8 SC replacement for nn.Linear forward.""" +"""Bipolar int8 SC replacement for nn.Linear forward. + +Quantization granularity & stream halving are env-controlled so runs can be +A/B'd without code edits (aligned with scmp_diffusion's integration): + + SC_LINEAR_GRANULARITY "per_tensor" (legacy default) | "per_row" + (kernel README: per_row is the intended mode for + all linear/MLP paths) + SC_HALVE=1 uSystolic/HUB bipolar stream halving — pass + stoc_len=None and let the kernel run 2**(prec-1) +""" from __future__ import annotations +import os + import torch import torch.nn as nn -from sc_triton import sc_matmul_enable_triton +from scmp_kernels import sc_matmul from .sc_attention import _get_config +_GRANULARITY = os.environ.get("SC_LINEAR_GRANULARITY", "per_tensor") +_HALVE = os.environ.get("SC_HALVE") == "1" + +# ---- mixed precision (heterogeneous stream lengths) ------------------------- +# SC_MP_CONFIG='{"stoc_len_levels":[128,96,64,32],"level_fractions":[...]}' +# rows are ranked by |x|.amax(-1) and bucketed into the levels (same policy as +# scmp_diffusion / scmp_llm), then each bucket runs sc_matmul at its own +# stoc_len. Per group spec, MP is only for logic<8; int8 stays uniform. +# SC_PREC=7|8 sets the quantization grid; SC_MP_FIXED_PREC=1 keeps sc_prec +# pinned instead of deriving it per level (both variants are to be measured). +_MP_CONFIG = None +# Per-(operator, block) fractions. A single global fraction triple spends the +# SAME average budget on every operator and block, so the only mixing it does +# is within a layer by |x| magnitude — at matched budget that measured no +# better than uniform. SC_MP_PER_MODULE points at a calibration JSON whose +# "per_module_fractions" keeps the split the Lagrangian solver actually +# produced, letting budget flow across layers/operators. +_MP_PER_MODULE = None # {(op, block_idx): [fractions]} +if os.environ.get("SC_MP_CONFIG"): + import json as _json + from scmp_kernels.mp import MPConfig as _MPConfig + _spec = _json.loads(os.environ["SC_MP_CONFIG"]) + _MP_CONFIG = _MPConfig(stoc_len_levels=_spec["stoc_len_levels"], + level_fractions=_spec.get("level_fractions")) +if os.environ.get("SC_MP_PER_MODULE"): + import json as _json, re as _re + _pm = _json.load(open(os.environ["SC_MP_PER_MODULE"]))["per_module_fractions"] + _SUFFIX_TO_OP = {"attn.qkv": "qkv", "attn.proj": "proj", + "mlp.fc1": "mlp_fc1", "mlp.fc2": "mlp_fc2"} + _MP_PER_MODULE = {} + for _name, _d in _pm.items(): + _m = _re.search(r"blocks\.(\d+)\.", _name) + if _m is None: + continue + for _suf, _op in _SUFFIX_TO_OP.items(): + if _name.endswith(_suf): + # Sensitivity calibration showed the metric-weight correlation + # flips sign per module, so each module carries its own + # ordering direction alongside its fractions. + _MP_PER_MODULE[(_op, int(_m.group(1)))] = { + "fractions": _d.get("level_fractions"), + # scmp_llm's full mechanism: absolute thresholds on the + # per-call min-max-normalised metric, and salient input + # channels split out at a fixed high stream length with + # row dispatch applied only to the residual columns. + "thresholds": _d.get("thresholds"), + "protected": _d.get("protected") or [], + "protect_sl": _d.get("protect_sl"), + "invert": bool(_d.get("invert", False))} + break + print(f"sc_mp: per-module fractions for {len(_MP_PER_MODULE)} (op, block) cells", + flush=True) +_SC_PREC = int(os.environ.get("SC_PREC", "8")) +_MP_FIXED_PREC = os.environ.get("SC_MP_FIXED_PREC") == "1" +# SC_UNIFORM_STOC_LEN: force a fixed stream length for the uniform ladder +# configs (sc_int8=128 / sc_int7=64 / sc_int6=32). Overrides the halve default. +_UNIFORM_STOC_LEN = os.environ.get("SC_UNIFORM_STOC_LEN") +_UNIFORM_STOC_LEN = int(_UNIFORM_STOC_LEN) if _UNIFORM_STOC_LEN else None +# SC_STEP_SCHEDULE: JSON list of halved cycle counts, indexed by diffusion +# step (resampled if its length differs from the sampler's step count). +_STEP_SCHEDULE = None +if os.environ.get("SC_STEP_SCHEDULE"): + import json as _json2 + _STEP_SCHEDULE = [int(x) for x in _json2.loads(os.environ["SC_STEP_SCHEDULE"])] + + +def _resolve_sc_prec(stoc_len: int, default_prec: int) -> int: + """Per-level sc_prec: pinned, or derived as ceil(log2(stoc_len)).""" + if _MP_FIXED_PREC: + return default_prec + import math + return max(1, min(default_prec, int(math.ceil(math.log2(max(stoc_len, 2)))))) + + +def _mp_linear_forward(x_flat, w, linear, orig_shape, sc_prec, out_dtype, + op=None, block_idx=None): + """Mixed-precision path: bucket rows by importance, one sc_matmul per level. + + Mirrors scmp_diffusion's SCLinear MP forward — rows ranked by |x|.amax(-1), + quantile-bucketed into MPConfig.stoc_len_levels, each bucket run at its own + stream length, results scattered back. + """ + from scmp_kernels.mp import classify_rows_by_metric + + in_dim = x_flat.shape[-1] + out_features = w.shape[0] + smooth = getattr(linear, "_sc_smooth_scales", None) + + fractions = _MP_CONFIG.level_fractions + mod_invert = False + thresholds = None + prot_idx = None + prot_sl = None + if _MP_PER_MODULE is not None and op is not None and block_idx is not None: + _ent = _MP_PER_MODULE.get((op, block_idx)) + if _ent is not None: + fractions = _ent["fractions"] or fractions + mod_invert = _ent["invert"] + thresholds = _ent.get("thresholds") + _pl = _ent.get("protected") + if _pl: + prot_idx = torch.as_tensor(sorted(set(int(i) for i in _pl)), + dtype=torch.long, device=x_flat.device) + prot_sl = int(_ent.get("protect_sl") + or max(_MP_CONFIG.stoc_len_levels)) + + out_prot = None + if prot_idx is not None and prot_idx.numel() > 0: + # Salient-channel split (scmp_llm sc_common semantics): protected + # columns run at a fixed high stream length, the row dispatch below + # sees only the residual columns, and the partial products sum. + mask = torch.ones(in_dim, dtype=torch.bool, device=x_flat.device) + mask[prot_idx] = False + rest_idx = mask.nonzero(as_tuple=True)[0] + x_prot = x_flat.index_select(1, prot_idx).contiguous() + w_prot = w.index_select(1, prot_idx).contiguous() + sm_prot = (smooth.index_select(0, prot_idx).contiguous() + if smooth is not None else None) + sp = _resolve_sc_prec(prot_sl, sc_prec) + out_prot = sc_matmul( + x_prot, w_prot, granularity=_GRANULARITY, mode="bipolar", + sc_prec=sp, stoc_len=prot_sl, + config=_get_config(int(prot_idx.numel()), sp), + halve_bipolar_stoc_len=_HALVE, smooth_scales=sm_prot) + x_flat = x_flat.index_select(1, rest_idx).contiguous() + w = w.index_select(1, rest_idx).contiguous() + smooth = (smooth.index_select(0, rest_idx).contiguous() + if smooth is not None else None) + in_dim = int(rest_idx.numel()) + + # Rank rows by the magnitude the kernel actually quantises. With + # SmoothQuant attached, sc_matmul divides x by the per-channel scales + # before per-row quantisation, so a row's SC error is set by + # max_j |x_j / s_j| — not by max_j |x_j|. The scales spread ~5x (up to + # 30x) across channels within one linear, so ranking on the raw amax + # systematically misorders rows and hands the long streams to the wrong + # ones; that misordering costs more than mixing gains (a wrong split is + # WORSE than uniform, see the shuffled-bucket control in the error-grid + # analysis). Rank on the smoothed activation instead. + if smooth is not None: + row_metric = (x_flat / smooth.to(x_flat.dtype)).abs().amax(dim=-1) + else: + row_metric = x_flat.abs().amax(dim=-1) + # SC_MP_INVERT=1 hands the long streams to the LOW-metric rows instead. + # Motivation: the more accurately rows are ranked by absolute matmul error + # (smoothed amax), the worse the end-to-end quality gets — which points to + # the PSNR-optimal allocation running in the opposite direction: per-row + # quantisation roughly equalises relative error, so high-magnitude rows + # carry structure that is robust to SC noise while low-magnitude detail + # rows are the quality bottleneck. + if os.environ.get("SC_MP_INVERT") == "1" or mod_invert: + row_metric = -row_metric + if thresholds is not None: + # scmp_llm calibrated-table path: min-max normalise the metric per + # call, then bucket against absolute descending thresholds — the + # realised fractions adapt to each call's metric distribution. + levels_ = _MP_CONFIG.stoc_len_levels + m_min, m_max = row_metric.min(), row_metric.max() + if float(m_max - m_min) < 1e-8: + row_levels = torch.zeros(row_metric.shape[0], dtype=torch.long, + device=row_metric.device) + else: + mn = (row_metric - m_min) / (m_max - m_min) + th = torch.as_tensor(thresholds, dtype=mn.dtype, device=mn.device) + row_levels = (mn.unsqueeze(1) < th.unsqueeze(0)).sum(dim=1) + from scmp_kernels.mp.config import RowAssignment + assignment = RowAssignment( + row_levels=row_levels, + level_row_indices={sl: (row_levels == i).nonzero(as_tuple=True)[0] + for i, sl in enumerate(levels_)}) + else: + assignment = classify_rows_by_metric( + row_metric, _MP_CONFIG.stoc_len_levels, fractions) + + out = torch.zeros(x_flat.shape[0], out_features, + device=x_flat.device, dtype=torch.float32) + for sl, rows in assignment.level_row_indices.items(): + if len(rows) == 0 or sl == 0: # level 0 == pruned rows, leave zeros + continue + sp = _resolve_sc_prec(sl, sc_prec) + idx = rows if torch.is_tensor(rows) else torch.as_tensor(rows, device=x_flat.device) + out[idx] = sc_matmul( + x_flat[idx].contiguous(), w, + granularity=_GRANULARITY, + mode="bipolar", + sc_prec=sp, + stoc_len=sl, + config=_get_config(in_dim, sp), + halve_bipolar_stoc_len=_HALVE, + smooth_scales=smooth, + ) + if out_prot is not None: + out = out + out_prot + if linear.bias is not None: + out = out + linear.bias.float() + return out.reshape(*orig_shape[:-1], -1).to(out_dtype) + def sc_linear_forward( x: torch.Tensor, linear: nn.Linear, sc_prec: int = 8, stoc_len: int | None = None, + op: str | None = None, + block_idx: int | None = None, ) -> torch.Tensor: - """Compute y = SC(x @ W^T) + bias with bipolar int8 SC. + """Compute y = SC(x @ Wᵀ) + bias with per-tensor bipolar int8 SC. Args: x: (..., in_dim) FP tensor @@ -23,23 +234,48 @@ def sc_linear_forward( Returns: (..., out_dim) tensor in x.dtype """ - if stoc_len is None: + sc_prec = _SC_PREC if sc_prec == 8 else sc_prec # SC_PREC env overrides default + if _STEP_SCHEDULE is not None: + # Per-timestep schedule: uniform within a step, varying across steps at + # matched average. Needs no row-ordering signal — the step index is + # exact — which is why this axis survives the rho=0.02 finding that + # killed row-level MP. + from .sc_controller import get_current_step + _i, _n = get_current_step() + stoc_len = _STEP_SCHEDULE[min(_i * len(_STEP_SCHEDULE) // max(_n, 1), + len(_STEP_SCHEDULE) - 1)] + elif _UNIFORM_STOC_LEN is not None: # uniform ladder: fixed stream length + stoc_len = _UNIFORM_STOC_LEN + elif stoc_len is None and not _HALVE: stoc_len = 2 ** sc_prec + # with SC_HALVE=1 keep stoc_len=None: the kernel then runs the bipolar + # stream at 2**(sc_prec-1) (uSystolic sign-magnitude trick, lossless). orig_shape = x.shape in_dim = orig_shape[-1] x_flat = x.reshape(-1, in_dim).float().contiguous() w = linear.weight.float().contiguous() # (out_dim, in_dim) + if _MP_CONFIG is not None: + return _mp_linear_forward(x_flat, w, linear, orig_shape, sc_prec, x.dtype, op=op, block_idx=block_idx) + config = _get_config(in_dim, sc_prec) - y = sc_matmul_enable_triton( + # SmoothQuant: calibration (evaluate/calibrate_smoothquant.py) attaches a + # per-channel (D,) scale vector to the module; kernel rewrites the matmul + # as (x/s) @ (w*s).T — mathematically equivalent, easier to quantize. + smooth = getattr(linear, "_sc_smooth_scales", None) + # granularity: legacy "per_tensor" (one (max,min) per operand matrix) or + # "per_row" (one scale per row — kernel README's intended linear/MLP + # mode, same as scmp_diffusion). sc_matmul computes x_flat @ w.T == x @ Wᵀ. + y = sc_matmul( x_flat, w, - x_flat.max().item(), x_flat.min().item(), - w.max().item(), w.min().item(), + granularity=_GRANULARITY, mode="bipolar", sc_prec=sc_prec, - config=config, stoc_len=stoc_len, + config=config, + halve_bipolar_stoc_len=_HALVE, + smooth_scales=smooth, ) if linear.bias is not None: y = y + linear.bias.float() diff --git a/models/sc_integration/sc_mlp.py b/models/sc_integration/sc_mlp.py index cce5f97..1624c1f 100644 --- a/models/sc_integration/sc_mlp.py +++ b/models/sc_integration/sc_mlp.py @@ -23,9 +23,9 @@ def __init__(self, in_features, hidden_features=None, out_features=None, def forward(self, x): b = self.block_idx - x = sc_linear_forward(x, self.fc1) if is_op_enabled("mlp_fc1", b) else self.fc1(x) + x = sc_linear_forward(x, self.fc1, op="mlp_fc1", block_idx=b) if is_op_enabled("mlp_fc1", b) else self.fc1(x) x = self.act(x) x = self.drop1(x) - x = sc_linear_forward(x, self.fc2) if is_op_enabled("mlp_fc2", b) else self.fc2(x) + x = sc_linear_forward(x, self.fc2, op="mlp_fc2", block_idx=b) if is_op_enabled("mlp_fc2", b) else self.fc2(x) x = self.drop2(x) return x diff --git a/results/block_gamma.npz b/results/block_gamma.npz new file mode 100644 index 0000000..f3da637 Binary files /dev/null and b/results/block_gamma.npz differ diff --git a/results/diverse_10.json b/results/diverse_10.json new file mode 100644 index 0000000..a659daf --- /dev/null +++ b/results/diverse_10.json @@ -0,0 +1 @@ +["1148_0_0", "2478_0_0", "1326_0_0", "833_0_0", "747_0_0", "980_0_0", "954_0_0", "1568_0_0", "3105_0_0", "1741_0_0"] \ No newline at end of file diff --git a/results/diverse_100.json b/results/diverse_100.json new file mode 100644 index 0000000..5ba2c8b --- /dev/null +++ b/results/diverse_100.json @@ -0,0 +1 @@ +["1148_0_0", "2478_0_0", "1326_0_0", "833_0_0", "747_0_0", "980_0_0", "954_0_0", "1568_0_0", "3105_0_0", "1741_0_0", "1590_0_0", "281_0_0", "1341_0_0", "475_0_0", "1406_0_0", "2329_0_0", "3234_0_0", "344_0_0", "2471_0_0", "2095_0_0", "1835_0_0", "626_0_0", "1146_0_0", "1049_0_0", "2458_0_0", "2615_0_0", "3140_0_0", "2905_0_0", "1395_0_0", "3106_0_0", "57_0_0", "261_0_0", "3436_0_0", "516_0_0", "271_0_0", "2723_0_0", "3443_0_0", "1320_0_0", "2965_0_0", "3347_0_0", "1978_0_0", "3108_0_0", "2649_0_0", "2072_0_0", "1850_0_0", "686_0_0", "137_0_0", "3402_0_0", "526_0_0", "3030_0_0", "2536_0_0", "2321_0_0", "3150_0_0", "3440_0_0", "193_0_0", "959_0_0", "1505_0_0", "780_0_0", "435_0_0", "2594_0_0", "2045_0_0", "627_0_0", "283_0_0", "509_0_0", "134_0_0", "2705_0_0", "2946_0_0", "364_0_0", "2632_0_0", "2998_0_0", "1283_0_0", "1386_0_0", "425_0_0", "1769_0_0", "537_0_0", "476_0_0", "3141_0_0", "2787_0_0", "332_0_0", "1702_0_0", "1378_0_0", "1576_0_0", "672_0_0", "1443_0_0", "554_0_0", "1510_0_0", "2569_0_0", "306_0_0", "708_0_0", "186_0_0", "1839_0_0", "1911_0_0", "699_0_0", "2449_0_0", "2515_0_0", "3266_0_0", "1478_0_0", "238_0_0", "2204_0_0", "635_0_0"] \ No newline at end of file diff --git a/results/diverse_300.json b/results/diverse_300.json new file mode 100644 index 0000000..e17f8ed --- /dev/null +++ b/results/diverse_300.json @@ -0,0 +1,302 @@ +[ + "1148_0_0", + "2478_0_0", + "1326_0_0", + "833_0_0", + "747_0_0", + "980_0_0", + "954_0_0", + "1568_0_0", + "3105_0_0", + "1741_0_0", + "1590_0_0", + "281_0_0", + "1341_0_0", + "475_0_0", + "1406_0_0", + "2329_0_0", + "3234_0_0", + "344_0_0", + "2471_0_0", + "2095_0_0", + "1835_0_0", + "626_0_0", + "1146_0_0", + "1049_0_0", + "2458_0_0", + "2615_0_0", + "3140_0_0", + "2905_0_0", + "1395_0_0", + "3106_0_0", + "57_0_0", + "261_0_0", + "3436_0_0", + "516_0_0", + "271_0_0", + "2723_0_0", + "3443_0_0", + "1320_0_0", + "2965_0_0", + "3347_0_0", + "1978_0_0", + "3108_0_0", + "2649_0_0", + "2072_0_0", + "1850_0_0", + "686_0_0", + "137_0_0", + "3402_0_0", + "526_0_0", + "3030_0_0", + "2536_0_0", + "2321_0_0", + "3150_0_0", + "3440_0_0", + "193_0_0", + "959_0_0", + "1505_0_0", + "780_0_0", + "435_0_0", + "2594_0_0", + "2045_0_0", + "627_0_0", + "283_0_0", + "509_0_0", + "134_0_0", + "2705_0_0", + "2946_0_0", + "364_0_0", + "2632_0_0", + "2998_0_0", + "1283_0_0", + "1386_0_0", + "425_0_0", + "1769_0_0", + "537_0_0", + "476_0_0", + "3141_0_0", + "2787_0_0", + "332_0_0", + "1702_0_0", + "1378_0_0", + "1576_0_0", + "672_0_0", + "1443_0_0", + "554_0_0", + "1510_0_0", + "2569_0_0", + "306_0_0", + "708_0_0", + "186_0_0", + "1839_0_0", + "1911_0_0", + "699_0_0", + "2449_0_0", + "2515_0_0", + "3266_0_0", + "1478_0_0", + "238_0_0", + "2204_0_0", + "635_0_0", + "3123_0_0", + "1028_0_0", + "109_0_0", + "563_0_0", + "3026_0_0", + "2055_0_0", + "1728_0_0", + "1492_0_0", + "368_0_0", + "1563_0_0", + "561_0_0", + "242_0_0", + "3092_0_0", + "405_0_0", + "2192_0_0", + "2021_0_0", + "706_0_0", + "688_0_0", + "719_0_0", + "2007_0_0", + "592_0_0", + "123_0_0", + "492_0_0", + "1523_0_0", + "2590_0_0", + "722_0_0", + "1342_0_0", + "2737_0_0", + "3027_0_0", + "1901_0_0", + "2964_0_0", + "3220_0_0", + "1260_0_0", + "1432_0_0", + "2396_0_0", + "2105_0_0", + "2408_0_0", + "1450_0_0", + "1416_0_0", + "2080_0_0", + "3116_0_0", + "2303_0_0", + "3020_0_0", + "1654_0_0", + "2344_0_0", + "2819_0_0", + "3330_0_0", + "2035_0_0", + "1921_0_0", + "348_0_0", + "254_0_0", + "3152_0_0", + "2046_0_0", + "2753_0_0", + "933_0_0", + "389_0_0", + "474_0_0", + "1152_0_0", + "1960_0_0", + "3142_0_0", + "3465_0_0", + "1315_0_0", + "2025_0_0", + "1233_0_0", + "2694_0_0", + "241_0_0", + "541_0_0", + "1970_0_0", + "376_0_0", + "2584_0_0", + "1795_0_0", + "3407_0_0", + "3168_0_0", + "696_0_0", + "2031_0_0", + "775_0_0", + "351_0_0", + "442_0_0", + "2932_0_0", + "1942_0_0", + "1503_0_0", + "2899_0_0", + "1656_0_0", + "423_0_0", + "3_0_0", + "3292_0_0", + "2688_0_0", + "3172_0_0", + "2424_0_0", + "2729_0_0", + "1632_0_0", + "3318_0_0", + "2342_0_0", + "270_0_0", + "944_0_0", + "2065_0_0", + "1484_0_0", + "3156_0_0", + "593_0_0", + "710_0_0", + "800_0_0", + "3460_0_0", + "2671_0_0", + "75_0_0", + "1500_0_0", + "3119_0_0", + "2848_0_0", + "779_0_0", + "3225_0_0", + "649_0_0", + "3423_0_0", + "2498_0_0", + "139_0_0", + "953_0_0", + "118_0_0", + "1161_0_0", + "1626_0_0", + "387_0_0", + "1143_0_0", + "1819_0_0", + "2019_0_0", + "663_0_0", + "1776_0_0", + "1021_0_0", + "2450_0_0", + "1469_0_0", + "2117_0_0", + "1435_0_0", + "161_0_0", + "720_0_0", + "2310_0_0", + "106_0_0", + "66_0_0", + "329_0_0", + "1515_0_0", + "2934_0_0", + "2977_0_0", + "2605_0_0", + "1876_0_0", + "1799_0_0", + "2410_0_0", + "3137_0_0", + "2840_0_0", + "1864_0_0", + "2512_0_0", + "1981_0_0", + "742_0_0", + "3454_0_0", + "1466_0_0", + "545_0_0", + "3455_0_0", + "3296_0_0", + "448_0_0", + "605_0_0", + "214_0_0", + "2741_0_0", + "756_0_0", + "1328_0_0", + "2577_0_0", + "1369_0_0", + "2684_0_0", + "2764_0_0", + "1442_0_0", + "817_0_0", + "74_0_0", + "2617_0_0", + "3392_0_0", + "549_0_0", + "3452_0_0", + "666_0_0", + "1129_0_0", + "2416_0_0", + "2494_0_0", + "2405_0_0", + "3194_0_0", + "2990_0_0", + "2937_0_0", + "1027_0_0", + "539_0_0", + "1346_0_0", + "1422_0_0", + "921_0_0", + "1780_0_0", + "1000_0_0", + "714_0_0", + "255_0_0", + "412_0_0", + "536_0_0", + "2435_0_0", + "2402_0_0", + "1975_0_0", + "2314_0_0", + "1078_0_0", + "2259_0_0", + "3169_0_0", + "1781_0_0", + "3113_0_0", + "3008_0_0", + "1299_0_0", + "3425_0_0" +] \ No newline at end of file diff --git a/results/final_sc_recipe.json b/results/final_sc_recipe.json new file mode 100644 index 0000000..f22f42a --- /dev/null +++ b/results/final_sc_recipe.json @@ -0,0 +1,23 @@ +{ + "env": { + "SC_LINEAR_GRANULARITY": "per_row", + "SC_HALVE": "1", + "SC_SMOOTH_SCALES": "/home/qiuyid/scmp_worldmodel/results/smoothquant_scales.pt" + }, + "skip": "mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25,27", + "decision_table": { + "sq=False,skip=True": [ + 23.91, + -0.1725 + ], + "sq=True,skip=True": [ + 24.243, + -0.1693 + ] + }, + "chosen": { + "sq": true, + "skip": true, + "psnr": 24.243 + } +} \ No newline at end of file diff --git a/results/mp_error_grid_sq2.npz b/results/mp_error_grid_sq2.npz new file mode 100644 index 0000000..2a1e522 Binary files /dev/null and b/results/mp_error_grid_sq2.npz differ diff --git a/results/mp_fractions_sc_g600.json b/results/mp_fractions_sc_g600.json new file mode 100644 index 0000000..ba2f16b --- /dev/null +++ b/results/mp_fractions_sc_g600.json @@ -0,0 +1,2623 @@ +{ + "config_name": "sc_g600", + "sc_prec": 8, + "stoc_len_levels": [ + 128, + 120, + 112, + 104, + 96, + 88, + 80, + 72, + 64, + 56, + 48, + 40, + 32, + 28, + 24, + 20, + 16 + ], + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "target_avg_cycles": 32.0, + "achieved_avg_cycles": 32.0, + "source": "Gamma+delta_sigma2, cliff floor L>=32, budget 32", + "per_module_fractions": { + "blocks.0.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.6.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.6.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.6.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.6.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.8.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.8.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.8.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.8.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.10.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.10.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.10.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.10.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.12.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.12.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.12.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.12.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.13.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.13.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.13.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.13.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.14.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.14.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.14.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.14.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.15.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.15.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.15.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.15.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.16.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.16.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.16.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.16.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.18.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.18.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.18.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.18.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.19.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.19.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.19.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.19.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.20.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.20.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.20.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.20.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.21.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.21.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.21.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.21.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.22.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.22.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.22.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.22.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.23.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.23.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.23.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.23.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.24.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.24.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.24.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.24.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.25.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.25.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.25.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.25.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.26.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.26.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.26.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.26.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + } + } +} \ No newline at end of file diff --git a/results/mp_fractions_sc_g632.json b/results/mp_fractions_sc_g632.json new file mode 100644 index 0000000..4849cd7 --- /dev/null +++ b/results/mp_fractions_sc_g632.json @@ -0,0 +1,2623 @@ +{ + "config_name": "sc_g632", + "sc_prec": 8, + "stoc_len_levels": [ + 128, + 120, + 112, + 104, + 96, + 88, + 80, + 72, + 64, + 56, + 48, + 40, + 32, + 28, + 24, + 20, + 16 + ], + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0357, + 0.3214, + 0.25, + 0.3929, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "target_avg_cycles": 40.0, + "achieved_avg_cycles": 40.0, + "source": "Gamma+delta_sigma2, cliff floor L>=32, budget 40", + "per_module_fractions": { + "blocks.0.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.6.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.6.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.6.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.6.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.7.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.7.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.8.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.8.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.8.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.8.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.9.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.9.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.10.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.10.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.10.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.10.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.11.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.11.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.12.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.12.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.12.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.12.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.13.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.13.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.13.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.13.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.14.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.14.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.14.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.14.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.15.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.15.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.15.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.15.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.16.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.16.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.16.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.16.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.17.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.17.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.18.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.18.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.18.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.18.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.19.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.19.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.19.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.19.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.20.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.20.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.20.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.20.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.21.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.21.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.21.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.21.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.22.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.23.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.23.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.23.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.23.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.24.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.24.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.24.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.24.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.25.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.25.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.25.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.25.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.26.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.26.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.26.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.26.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.27.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.27.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + } + } +} \ No newline at end of file diff --git a/results/mp_fractions_sc_g658.json b/results/mp_fractions_sc_g658.json new file mode 100644 index 0000000..15c3e56 --- /dev/null +++ b/results/mp_fractions_sc_g658.json @@ -0,0 +1,2623 @@ +{ + "config_name": "sc_g658", + "sc_prec": 8, + "stoc_len_levels": [ + 128, + 120, + 112, + 104, + 96, + 88, + 80, + 72, + 64, + 56, + 48, + 40, + 32, + 28, + 24, + 20, + 16 + ], + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0357, + 0.3214, + 0.4286, + 0.0357, + 0.1786, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "target_avg_cycles": 48.0, + "achieved_avg_cycles": 48.0, + "source": "Gamma+delta_sigma2, cliff floor L>=32, budget 48", + "per_module_fractions": { + "blocks.0.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.0.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.1.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.2.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.3.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.4.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 32.0, + "invert": false + }, + "blocks.5.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.5.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.5.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.5.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 40.0, + "invert": false + }, + "blocks.6.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.6.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.6.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.6.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.7.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.7.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.7.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.7.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.8.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.8.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.8.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.8.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.9.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.9.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.9.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.9.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.10.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.10.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.10.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.10.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.11.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.11.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.11.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.11.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.12.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.12.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.12.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.12.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.13.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.13.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.13.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.13.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.14.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.14.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.14.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.14.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.15.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.15.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.15.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.15.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.16.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.16.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.16.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.16.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.17.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.17.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.17.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.17.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.18.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.18.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.18.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.18.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.19.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.19.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.19.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.19.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.20.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.20.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.20.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.20.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.21.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.21.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.21.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.21.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.22.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.23.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.23.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.23.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.23.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.24.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 64.0, + "invert": false + }, + "blocks.24.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 64.0, + "invert": false + }, + "blocks.24.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 64.0, + "invert": false + }, + "blocks.24.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 64.0, + "invert": false + }, + "blocks.25.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.25.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.25.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.25.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.26.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.26.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.26.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.26.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.27.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.27.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.27.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.27.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + } + } +} \ No newline at end of file diff --git a/results/mp_fractions_sc_g758.json b/results/mp_fractions_sc_g758.json new file mode 100644 index 0000000..ff12c38 --- /dev/null +++ b/results/mp_fractions_sc_g758.json @@ -0,0 +1,2623 @@ +{ + "config_name": "sc_g758", + "sc_prec": 8, + "stoc_len_levels": [ + 128, + 120, + 112, + 104, + 96, + 88, + 80, + 72, + 64, + 56, + 48, + 40, + 32, + 28, + 24, + 20, + 16 + ], + "level_fractions": [ + 0.1429, + 0.0714, + 0.2143, + 0.0, + 0.2858, + 0.1071, + 0.0, + 0.0, + 0.0, + 0.1071, + 0.0357, + 0.0, + 0.0, + 0.0357, + 0.0, + 0.0, + 0.0 + ], + "target_avg_cycles": 96.0, + "achieved_avg_cycles": 96.43, + "source": "Gamma-weighted per-block, budget 96", + "per_module_fractions": { + "blocks.0.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.0.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.0.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.0.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.1.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.1.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.1.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.1.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 48.0, + "invert": false + }, + "blocks.2.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.2.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.2.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.2.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.3.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 28.0, + "invert": false + }, + "blocks.3.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 28.0, + "invert": false + }, + "blocks.3.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 28.0, + "invert": false + }, + "blocks.3.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 28.0, + "invert": false + }, + "blocks.4.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.4.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.4.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.4.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 56.0, + "invert": false + }, + "blocks.5.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.5.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.5.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.5.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.6.attn.qkv": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.6.attn.proj": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.6.mlp.fc1": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.6.mlp.fc2": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.7.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.7.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.7.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.7.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.8.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.8.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.8.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.8.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.9.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.9.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.9.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.9.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 88.0, + "invert": false + }, + "blocks.10.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.10.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.10.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.10.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.11.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.11.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.11.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.11.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.12.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.12.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.12.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.12.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.13.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.13.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.13.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.13.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.14.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.14.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.14.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.14.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.15.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.15.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.15.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.15.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.16.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.16.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.16.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.16.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.17.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.17.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.17.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.17.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.18.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.18.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.18.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.18.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.19.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.19.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.19.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.19.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.20.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.20.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.20.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.20.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.21.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.21.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.21.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.21.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 112.0, + "invert": false + }, + "blocks.22.attn.qkv": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.22.attn.proj": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.22.mlp.fc1": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.22.mlp.fc2": { + "level_fractions": [ + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 96.0, + "invert": false + }, + "blocks.23.attn.qkv": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.23.attn.proj": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.23.mlp.fc1": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.23.mlp.fc2": { + "level_fractions": [ + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 120.0, + "invert": false + }, + "blocks.24.attn.qkv": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.24.attn.proj": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.24.mlp.fc1": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.24.mlp.fc2": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.25.attn.qkv": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.25.attn.proj": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.25.mlp.fc1": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.25.mlp.fc2": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.26.attn.qkv": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.26.attn.proj": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.26.mlp.fc1": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.26.mlp.fc2": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.27.attn.qkv": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.27.attn.proj": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.27.mlp.fc1": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + }, + "blocks.27.mlp.fc2": { + "level_fractions": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "avg_cycles": 128.0, + "invert": false + } + } +} \ No newline at end of file diff --git a/results/smoothquant_scales.pt b/results/smoothquant_scales.pt new file mode 100644 index 0000000..ff85747 Binary files /dev/null and b/results/smoothquant_scales.pt differ diff --git a/results/step_sched_Wt.json b/results/step_sched_Wt.json new file mode 100644 index 0000000..22816c1 --- /dev/null +++ b/results/step_sched_Wt.json @@ -0,0 +1 @@ +[128, 128, 128, 128, 128, 128, 128, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 128, 128, 128, 128, 128, 128, 48, 32, 32, 32, 32, 32, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128] \ No newline at end of file diff --git a/sample/pipeline_trajectory2videogen.py b/sample/pipeline_trajectory2videogen.py index 50a8afc..cac97a4 100755 --- a/sample/pipeline_trajectory2videogen.py +++ b/sample/pipeline_trajectory2videogen.py @@ -405,6 +405,11 @@ def __call__( with self.progress_bar(total=num_inference_steps) as progress_bar: for i, t in enumerate(timesteps): + try: + from models.sc_integration.sc_controller import set_current_step + set_current_step(i, len(timesteps)) + except Exception: + pass latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents # latent_model_input = latents latent_model_input = self.scheduler.scale_model_input(latent_model_input, t) diff --git a/scripts/check_kernel_update.sh b/scripts/check_kernel_update.sh new file mode 100755 index 0000000..d653019 --- /dev/null +++ b/scripts/check_kernel_update.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Daily check for scmp_kernels updates. Appends status to ~/scmp_kernel_update.log. +# Installed in crontab; also safe to run by hand. +set -u +REPO=/home/qiuyid/scmp_worldmodel/kernels +LOG=/home/qiuyid/scmp_kernel_update.log +cd "$REPO" || { echo "$(date '+%F %T') ERROR: repo not found" >> "$LOG"; exit 1; } + +git fetch origin -q 2>>"$LOG" +L=$(git rev-parse HEAD) +R=$(git rev-parse origin/main) +TS=$(date '+%F %T') + +if [ "$L" != "$R" ]; then + { + echo "$TS UPDATE_AVAILABLE local=$(git rev-parse --short HEAD) remote=$(git rev-parse --short origin/main)" + git log --oneline "HEAD..origin/main" + # flag README/quant/sc changes that most likely need worldmodel re-alignment + git diff --stat "HEAD..origin/main" -- README.md scmp_kernels/sc scmp_kernels/quant | sed 's/^/ /' + echo " -> pull with: git -C $REPO pull origin main then re-check models/sc_integration alignment" + } >> "$LOG" +else + echo "$TS up-to-date ($(git rev-parse --short HEAD))" >> "$LOG" +fi diff --git a/scripts/finish_bridge.sh b/scripts/finish_bridge.sh new file mode 100755 index 0000000..2bad34d --- /dev/null +++ b/scripts/finish_bridge.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Bridge finalization: FVD for both full lines (FID already computed), plus a +# naive-int8 300-clip run to attribute how much of the FID gap is SC noise vs +# plain int8 quantization. Rebuilds results/BRIDGE_FINAL_TABLE.json at the end. +cd /home/qiuyid/scmp_worldmodel +export PYTHONPATH=.:pytorch-fid/src +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/local_n_eval +PY=/home/qiuyid/.conda/envs/scmp/bin/python + +echo "[1/4] FVD: FP line" +CUDA_VISIBLE_DEVICES=6 $PY evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/final_fp_full/videos \ + --out results/fidfvd_final_fp_full.json --fid_precomputed 4.985 2>&1 | grep -E "^FID|^FVD|skipped|pred=" + +echo "[2/4] FVD: SC line" +CUDA_VISIBLE_DEVICES=6 $PY evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/final_sc_full/videos \ + --out results/fidfvd_final_sc_full.json --fid_precomputed 10.852 2>&1 | grep -E "^FID|^FVD|skipped|pred=" + +echo "[3/4] naive int8 x300 (FID attribution)" +CUDA_VISIBLE_DEVICES=6 $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --naive_int8 \ + --tag naive_int8_300 --num_samples 300 2>&1 | grep -E "DONE" | tail -1 + +echo "[4/4] FID/FVD for naive int8 + rebuild table" +CUDA_VISIBLE_DEVICES=6 $PY evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/naive_int8_300/videos \ + --out results/fidfvd_naive300.json 2>&1 | grep -E "^FID|^FVD|pred=" + +$PY - <<'PYEOF' +import json, glob, os +def agg(tag): + ms=[json.load(open(f)) for f in glob.glob(f"results/local_n_eval/{tag}/metrics/*.json")] + ok=[m for m in ms if m.get("psnr")]; n=len(ok) + r={"n":n,"latent_l2":round(sum(m['latent_l2'] for m in ok)/n,4), + "psnr":round(sum(m['psnr'] for m in ok)/n,2),"ssim":round(sum(m['ssim'] for m in ok)/n,3)} + f=f"results/fidfvd_{tag}.json" + if os.path.exists(f): + d=json.load(open(f)); r["fid"]=d.get("fid"); r["fvd"]=d.get("fvd") + return r +rec=json.load(open("results/final_sc_recipe.json")) +t={"dataset":"bridge test 2946, PNDM50", + "FP_baseline":agg("final_fp_full"), + "SC_final_recipe":agg("final_sc_full"), + "recipe":rec["env"]|{"skip":rec["skip"]}} +if os.path.exists("results/local_n_eval/naive_int8_300/metrics"): + t["naive_int8_300_attribution"]=agg("naive_int8_300") +json.dump(t,open("results/BRIDGE_FINAL_TABLE.json","w"),indent=2,ensure_ascii=False) +print(json.dumps(t,indent=2,ensure_ascii=False)) +PYEOF +echo "BRIDGE_FINISH_ALL_DONE" diff --git a/scripts/fvd_only.sh b/scripts/fvd_only.sh new file mode 100755 index 0000000..5af13d8 --- /dev/null +++ b/scripts/fvd_only.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# FVD for both full lines + naive-int8 attribution run (FID reused from json). +cd /home/qiuyid/scmp_worldmodel +export PYTHONPATH=.:pytorch-fid/src +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +PY=/home/qiuyid/.conda/envs/scmp/bin/python + +run() { # tag fid + echo "=== FVD: $1 ===" + CUDA_VISIBLE_DEVICES=6 $PY evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/$1/videos \ + --out results/fidfvd_$1.json --fid_precomputed $2 2>&1 \ + | grep -E "^FID|^FVD|skipped|pred=|\[gt\]|\[pred\]|Error|Traceback" +} +run final_fp_full 4.985 +run final_sc_full 10.852 +run naive_int8_300 21.586 + +$PY - <<'PYEOF' +import json, glob, os +def agg(tag): + ms=[json.load(open(f)) for f in glob.glob(f"results/local_n_eval/{tag}/metrics/*.json")] + ok=[m for m in ms if m.get("psnr")]; n=len(ok) + r={"n":n,"latent_l2":round(sum(m['latent_l2'] for m in ok)/n,4), + "psnr":round(sum(m['psnr'] for m in ok)/n,2),"ssim":round(sum(m['ssim'] for m in ok)/n,3)} + f=f"results/fidfvd_{tag}.json" + if os.path.exists(f): + d=json.load(open(f)); r["fid"]=d.get("fid"); r["fvd"]=d.get("fvd") + return r +rec=json.load(open("results/final_sc_recipe.json")) +t={"dataset":"bridge test 2946, PNDM50", + "FP_baseline":agg("final_fp_full"), + "SC_final_recipe":agg("final_sc_full"), + "naive_int8_300_attribution":agg("naive_int8_300"), + "recipe":rec["env"]|{"skip":rec["skip"]}} +json.dump(t,open("results/BRIDGE_FINAL_TABLE.json","w"),indent=2,ensure_ascii=False) +print(json.dumps(t,indent=2,ensure_ascii=False)) +PYEOF +echo "FVD_ALL_DONE" diff --git a/scripts/install.sh b/scripts/install.sh index 3dd69c3..ac89268 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -2,6 +2,12 @@ # https://pytorch.org/get-started/locally/ # install torch pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 -pip3 install timm diffusers[torch]==0.24.0 einops transformers scikit-image decord pandas imageio-ffmpeg omegaconf huggingface_hub nvitop deepspeed matplotlib opencv-python wandb rotary_embedding_torch einops_exts tensorflow tensorflow_datasets +pip3 install timm diffusers[torch]==0.24.0 einops transformers scikit-image decord pandas imageio-ffmpeg omegaconf huggingface_hub nvitop deepspeed matplotlib opencv-python wandb rotary_embedding_torch einops_exts tensorflow tensorflow_datasets # Optionally -# pip3 install flash-attn --no-build-isolation \ No newline at end of file +# pip3 install flash-attn --no-build-isolation + +# Stochastic-computing (SC) Triton kernels — shared submodule at kernels/. +# Make sure the submodule is checked out, then install it editable so SC +# kernel updates (git submodule update --remote kernels) flow straight in. +git submodule update --init --recursive +pip3 install -e ./kernels # provides the `scmp_kernels` package (needs a CUDA GPU + triton) \ No newline at end of file diff --git a/scripts/mp_pipeline.sh b/scripts/mp_pipeline.sh new file mode 100755 index 0000000..9b7e873 --- /dev/null +++ b/scripts/mp_pipeline.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# MP (heterogeneous SC) pipeline on bridge: +# 1) calibrate fractions for the remaining HPCA configs +# 2) probe each config (n=8, DPM10) to sanity-check quality + measure speed +# Full-test runs are launched separately once probes look sane. +cd /home/qiuyid/scmp_worldmodel +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/line_eval +export PYTHONPATH=. +PY=/home/qiuyid/.conda/envs/scmp/bin/python +SKIP="mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25,27" +SQ=/home/qiuyid/scmp_worldmodel/results/smoothquant_scales.pt + +# ---- 1) calibrate the three remaining configs (GPU 7, sequential) ---- +for cfg in sc_int7 sc_avg96 sc_int6; do + f=results/mp_fractions_${cfg}.json + [ -f "$f" ] && { echo "[calib] $cfg already done"; continue; } + echo "[calib] $cfg ..." + CUDA_VISIBLE_DEVICES=7 $PY evaluate/calibrate_mp_fractions.py \ + --config_name $cfg --out $f 2>&1 | grep -E "achieved_avg|level_fractions|Error" | tail -3 +done + +# ---- 2) probe every calibrated config (n=8) ---- +for cfg in sc_avg192 sc_int7 sc_avg96 sc_int6; do + f=results/mp_fractions_${cfg}.json + [ -f "$f" ] || { echo "[probe] $cfg: no calibration, skip"; continue; } + [ -f results/line_eval/mp_${cfg}/summary_shard_0.json ] && { echo "[probe] $cfg done"; continue; } + MPJ=$($PY -c "import json;d=json.load(open('$f'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']}))") + PREC=$($PY -c "import json;print(json.load(open('$f'))['sc_prec'])") + echo "[probe] $cfg prec=$PREC mp=$MPJ" + t0=$(date +%s) + CUDA_VISIBLE_DEVICES=7 SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 \ + SC_PREC=$PREC SC_SMOOTH_SCALES=$SQ SC_MP_CONFIG="$MPJ" \ + $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag mp_${cfg} --num_samples 8 --inference_steps 10 --scheduler DPM 2>&1 | grep -E "DONE" | tail -1 + echo " elapsed $(( $(date +%s) - t0 ))s" +done +echo "MP_PIPELINE_DONE" diff --git a/scripts/mp_probe_rest.sh b/scripts/mp_probe_rest.sh new file mode 100755 index 0000000..db6e416 --- /dev/null +++ b/scripts/mp_probe_rest.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Probe the remaining MP configs (int7, int6) at n=8, then print the 5-config table. +cd /home/qiuyid/scmp_worldmodel +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/line_eval +export PYTHONPATH=. +PY=/home/qiuyid/.conda/envs/scmp/bin/python +SKIP="mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25,27" +SQ=/home/qiuyid/scmp_worldmodel/results/smoothquant_scales.pt + +for cfg in sc_int7 sc_int6; do + [ -f results/line_eval/mp_${cfg}/summary_shard_0.json ] && { echo "$cfg done"; continue; } + MPJ=$($PY -c "import json;d=json.load(open('results/mp_fractions_${cfg}.json'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']}))") + echo "[probe] $cfg mp=$MPJ" + CUDA_VISIBLE_DEVICES=7 SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 \ + SC_PREC=8 SC_SMOOTH_SCALES=$SQ SC_MP_CONFIG="$MPJ" \ + $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag mp_${cfg} --num_samples 8 --inference_steps 10 --scheduler DPM 2>&1 | grep -E "DONE" | tail -1 +done + +$PY - <<'PYEOF' +import json, os +rows=[("sc_int8","(uniform 128)"),("sc_avg192","96 cyc"),("sc_int7","64 cyc"),("sc_avg96","48 cyc"),("sc_int6","32 cyc")] +print(f"\n{'config':<12}{'note':<14}{'PSNR':>7}{'SSIM':>7}{'L2':>8}") +for cfg,note in rows: + f=f"results/line_eval/mp_{cfg}/summary_shard_0.json" + # sc_int8 uniform baseline reuses q_perrow_halve + if cfg=="sc_int8": f="results/line_eval/q_perrow_halve/summary_shard_0.json" + if os.path.exists(f): + d=json.load(open(f)); print(f"{cfg:<12}{note:<14}{d['mean_psnr']:>7.2f}{d['mean_ssim']:>7.3f}{d['mean_l2']:>8.3f}") + else: print(f"{cfg:<12}{note:<14}{'--pending--':>22}") +PYEOF +echo "MP_PROBE_REST_DONE" diff --git a/scripts/naive_full.sh b/scripts/naive_full.sh new file mode 100755 index 0000000..6cb92f5 --- /dev/null +++ b/scripts/naive_full.sh @@ -0,0 +1,33 @@ +#!/bin/bash +cd /home/qiuyid/scmp_worldmodel +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/local_n_eval PYTHONPATH=. +PY=/home/qiuyid/.conda/envs/scmp/bin/python +# 24 shard, 抢空闲卡(排除 0/1/7),每卡一个,断点续传 +declare -A running +NS=24 +while :; do + done_all=1 + for s in $(seq 0 $((NS-1))); do + # 该 shard 是否完成: 粗略用 metrics 数近似(精确判断靠脚本内 resume) + [ -f /edrive2/qiuyid/naivef_s${s}.done ] && continue + done_all=0 + # 找空闲卡 + for g in 2 3 4 5 6; do + [ -n "${running[$g]}" ] && kill -0 ${running[$g]} 2>/dev/null && continue + free=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits -i $g) + util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits -i $g) + if [ "$free" -ge 20000 ] && [ "$util" -le 40 ]; then + ( CUDA_VISIBLE_DEVICES=$g $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --naive_int8 \ + --tag naive_int8_full --num_samples 2946 --shard $s --num_shards $NS \ + >/edrive2/qiuyid/naivef_s${s}.log 2>&1 && touch /edrive2/qiuyid/naivef_s${s}.done ) & + running[$g]=$! + break + fi + done + done + [ $done_all -eq 1 ] && break + sleep 60 +done +echo "NAIVE_FULL_DONE: $(ls results/local_n_eval/naive_int8_full/metrics 2>/dev/null | wc -l)/2946" diff --git a/scripts/rigorous_bridge.sh b/scripts/rigorous_bridge.sh new file mode 100644 index 0000000..1d2f375 --- /dev/null +++ b/scripts/rigorous_bridge.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# Rigorous bridge finalization: +# 1) naive int8 -> full 2946 (fair sample-size parity with FP/SC for FID/FVD) +# 2) official StyleGAN-V FVD cross-check on FP & SC (our streaming FVD is suspect) +cd /home/qiuyid/scmp_worldmodel +export PYTHONPATH=.:pytorch-fid/src +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/local_n_eval +PY=/home/qiuyid/.conda/envs/scmp/bin/python + +echo "=== [1] naive int8 -> full 2946 (24 shards over free GPUs) ===" +# reuse the final scheduler pattern but for a single naive-int8 line +for s in $(seq 0 23); do + # round-robin the free GPUs 2,3,4,5,6 (skip 0,1,7 per contention rules) + gpu=$(( 2 + (s % 5) )); [ $gpu -eq 7 ] && gpu=6 + CUDA_VISIBLE_DEVICES=$gpu $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --naive_int8 \ + --tag naive_int8_full --num_samples 2946 --shard $s --num_shards 24 \ + >/edrive2/qiuyid/naive_full_s$s.log 2>&1 & + # cap concurrency at 5 + while [ "$(jobs -r | wc -l)" -ge 5 ]; do sleep 30; done +done +wait +echo "naive_int8_full done: $(ls results/local_n_eval/naive_int8_full/metrics | wc -l)/2946" + +echo "=== [2] streaming FVD for naive_int8_full ===" +CUDA_VISIBLE_DEVICES=6 $PY evaluate/compute_fid_fvd_stream.py \ + --pred_dir results/local_n_eval/naive_int8_full/videos \ + --out results/fidfvd_naive_int8_full.json --fid_precomputed -1 2>&1 | grep -E "^FID|^FVD|pred=" + +echo "ALL_RIGOROUS_DONE" diff --git a/scripts/run_mp_ladder.sh b/scripts/run_mp_ladder.sh new file mode 100644 index 0000000..e026d6b --- /dev/null +++ b/scripts/run_mp_ladder.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# Run the two MP configs (avg192, avg96) + backfill any uniform gaps. +# Uses explicit `export` (not `env VAR=...`) so the compact MP JSON is passed +# as a single argument and never word-split. +cd /home/qiuyid/scmp_worldmodel +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/local_n_eval +export PYTHONPATH=. +PY=/home/qiuyid/.conda/envs/scmp/bin/python +SKIP="mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25,27" +export SC_SMOOTH_SCALES=/home/qiuyid/scmp_worldmodel/results/smoothquant_scales.pt +export SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 SC_PREC=8 +KEYS=results/diverse_300.json +N=$($PY -c "import json;print(len(json.load(open('$KEYS'))))") +NS=12 + +run_shard() { # cfg gpu shard (env for SC path already exported by caller) + local cfg=$1 g=$2 s=$3 + CUDA_VISIBLE_DEVICES=$g $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag ladder_${cfg} --keys_file $KEYS --num_samples $N \ + --shard $s --num_shards $NS >/edrive2/qiuyid/ladder_${cfg}_s${s}.log 2>&1 \ + && touch /edrive2/qiuyid/ladder_${cfg}_s${s}.done +} + +declare -A pid +for cfg in sc_int7 sc_avg192 sc_avg96; do + # set the SC-path env for this config in the current shell (exported → children inherit) + unset SC_UNIFORM_STOC_LEN SC_MP_CONFIG + if [ "$cfg" = "sc_int7" ]; then + export SC_UNIFORM_STOC_LEN=64 + else + export SC_MP_CONFIG=$($PY -c "import json;d=json.load(open('results/mp_fractions_${cfg}.json'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']},separators=(',',':')))") + fi + echo "[$cfg] SC_UNIFORM_STOC_LEN=${SC_UNIFORM_STOC_LEN:-unset} SC_MP_CONFIG=${SC_MP_CONFIG:-unset}" + for s in $(seq 0 $((NS-1))); do + [ -f /edrive2/qiuyid/ladder_${cfg}_s${s}.done ] && continue + # wait for a free allowed GPU (2,3,4,5,6) + while :; do + launched=0 + for g in 2 3 4 5 6; do + [ -n "${pid[$g]}" ] && kill -0 ${pid[$g]} 2>/dev/null && continue + free=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits -i $g) + util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits -i $g) + if [ "$free" -ge 20000 ] && [ "$util" -le 45 ]; then + run_shard $cfg $g $s & pid[$g]=$!; launched=1; break + fi + done + [ $launched -eq 1 ] && break + sleep 45 + done + done + wait # finish this config before switching env for the next +done +echo "MP_LADDER_ALL_DONE" diff --git a/scripts/run_sc_ladder.sh b/scripts/run_sc_ladder.sh new file mode 100755 index 0000000..75367fb --- /dev/null +++ b/scripts/run_sc_ladder.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# The 5-config SC precision ladder on bridge, n=300 diverse samples, PNDM50. +# int8/int7/int6 = uniform (fixed stoc_len); avg192/avg96 = MP (calibrated). +# All share the deployed recipe: per_row + halve + SmoothQuant + top-17 skip. +# GPU auto-grab over 2,3,4,5,6 (skip 0,1,7 per contention rules); per-sample resume. +cd /home/qiuyid/scmp_worldmodel +export BRIDGE_ROOT=/home/qiuyid/scmp_worldmodel/robotdata/opensource_robotdata/bridge +export EVAL_OUT_ROOT=/home/qiuyid/scmp_worldmodel/results/local_n_eval +export PYTHONPATH=. +PY=/home/qiuyid/.conda/envs/scmp/bin/python +SKIP="mlp_fc1=4,25,26,27;mlp_fc2=0,2,4,5,6,7,10,13;qkv=3,6,7,25,27" +SQ=/home/qiuyid/scmp_worldmodel/results/smoothquant_scales.pt +KEYS=results/diverse_300.json +N=$($PY -c "import json;print(len(json.load(open('$KEYS'))))") + +# config -> env for the SC path (uniform via SC_UNIFORM_STOC_LEN, MP via SC_MP_CONFIG) +env_for() { + case "$1" in + sc_int8) echo "SC_UNIFORM_STOC_LEN=128" ;; + sc_int7) echo "SC_UNIFORM_STOC_LEN=64" ;; + sc_int6) echo "SC_UNIFORM_STOC_LEN=32" ;; + sc_avg192|sc_avg96) + MPJ=$($PY -c "import json;d=json.load(open('results/mp_fractions_$1.json'));print(json.dumps({'stoc_len_levels':d['stoc_len_levels'],'level_fractions':d['level_fractions']},separators=(',',':')))") + echo "SC_MP_CONFIG=$MPJ" ;; + esac +} + +CONFIGS="sc_int8 sc_int7 sc_int6 sc_avg192 sc_avg96" +NS=12 # shards per config +declare -A pid +for cfg in $CONFIGS; do + extra=$(env_for $cfg) + for s in $(seq 0 $((NS-1))); do + flag=/edrive2/qiuyid/ladder_${cfg}_s${s}.done + [ -f "$flag" ] && continue + # wait for a free allowed GPU + while :; do + launched=0 + for g in 2 3 4 5 6; do + [ -n "${pid[$g]}" ] && kill -0 ${pid[$g]} 2>/dev/null && continue + free=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits -i $g) + util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits -i $g) + if [ "$free" -ge 20000 ] && [ "$util" -le 45 ]; then + ( CUDA_VISIBLE_DEVICES=$g SC_LINEAR_GRANULARITY=per_row SC_HALVE=1 SC_MP_FIXED_PREC=1 SC_PREC=8 \ + SC_SMOOTH_SCALES=$SQ env $extra \ + $PY evaluate/eval_local_n_samples.py \ + --config configs/evaluation/bridge/frame_ada_sc_full.yaml --skip "$SKIP" \ + --tag ladder_${cfg} --keys_file $KEYS --num_samples $N \ + --shard $s --num_shards $NS >/edrive2/qiuyid/ladder_${cfg}_s${s}.log 2>&1 \ + && touch $flag ) & + pid[$g]=$!; launched=1; break + fi + done + [ $launched -eq 1 ] && break + sleep 45 + done + done +done +wait +echo "SC_LADDER_ALL_DONE"