Instructions to use XXXpilar/Fastfill-test with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use XXXpilar/Fastfill-test with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
File size: 11,422 Bytes
e6f80f3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #!/bin/bash
# CPU-only test of the analysis scripts on the BASELINE artifacts (final = baseline placeholder); writes test/* and
# test/sample_report.html under runs/analysis. Usage: bash runs/analysis/make_sample.sh (~10 minutes, <= 8 threads)
# validation section: the head-output path of run_plan on 24 NEW validation rooms (16 small, 6 mid, 2 > 128 objects),
# baseline checkpoint, forward pass on the CPU (8 threads), spread and argmax decoded from the saved heads
# test section: the baseline's 10-07 GPU test reports (old data; spread and argmax by the same code)
set -euo pipefail
R=/home/jovyan/shanliantian/fastfill
cd $R/runs/analysis
export PYTHONPATH=$R PYTHONDONTWRITEBYTECODE=1 OMP_NUM_THREADS=1 CUDA_VISIBLE_DEVICES= TOKENIZERS_PARALLELISM=false \
HF_HOME=/home/jovyan/shanliantian/.huggingface
P=$R/env/bin/python; W=7; T=test; K=$T/cache; mkdir -p $T
BASE=$R/runs/main7-cell05-main-20261007b-e5/model-step-6357
B=$R/runs/test-main7-cell05-main-20261007b-e5 # baseline test: outcomes.jsonl = minimal, outcomes-full.jsonl = full
L=$R/runs/llmrows-main7-cell05-main-20261007b-e5 # baseline on the 300 LLM rows (full condition)
OLD=$R/data/main-20261007b
COHORT_OLD=$R/runs/autorun/validation-$(sha256sum $OLD/validation.jsonl | cut -c1-12)-all.jsonl # baseline select2
COHORT_OLD1=${COHORT_OLD%-all.jsonl}-3000.jsonl # baseline select1
# (0) run_plan's preflight on the live cards (read-only nvidia-smi queries): GPU 0 and every training card must be refused
eval "$(sed -n '/^idle() {/,/^}/p' run_plan.sh)"
for c in 0 1 2 3 4 5 6 7; do if idle $c; then echo "card $c idle"; else echo "card $c refused"; fi; done | tee $T/preflight.txt
# (1) 24 fixed NEW validation rooms (seeded), head outputs saved once (CPU forward, 8 threads), decoded twice by the
# same code; crosscheck of the online decode vs the CPU decode
pick_rows() { # $1 = output file: 8 small rooms with added objects + 8 small without (seed 0), 2 > 128 objects + 6 of 9-40 (seed 1)
$P - "$1" <<'PY'
import json, random, sys
from fastfill.v2.evaluate import project_minimal
mixed, plain, big, mid = [], [], [], []
for line in open("/home/jovyan/shanliantian/fastfill/data/main-20261008a/validation.jsonl"):
r = json.loads(line); k = len(r["condition"]["objects"])
if project_minimal(r) is None:
continue
rules = {(e or {}).get("selection_rule") or "frozen_prep" for e in r["provenance"].get("field_evidence") or []}
if k <= 8:
(mixed if len(rules) > 1 else plain).append(line)
if k > 128:
big.append(line)
elif 9 <= k <= 40:
mid.append(line)
rng = random.Random(0); rng.shuffle(mixed); rng.shuffle(plain)
small = mixed[:8] + plain[:8]; rng.shuffle(small)
rng = random.Random(1); rng.shuffle(big); rng.shuffle(mid)
rows = small + big[:2] + mid[:6]; rng.shuffle(rows)
open(sys.argv[1], "w").writelines(rows)
PY
}
[ -f $T/hv-rows.jsonl ] || pick_rows $T/hv-rows.jsonl
[ -e $T/hv-heads ] || OMP_NUM_THREADS=8 $P -m fastfill.v2.evaluate --checkpoint $BASE --data $T/hv-rows.jsonl --projection minimal full \
--device cpu --grid-decode spread --output $T/hv-online --save-head-outputs $T/hv-heads > $T/hv-online.log 2>&1
for d in spread argmax; do [ -e $T/hv-$d ] || echo "$P -m fastfill.v2.evaluate --from-head-outputs $T/hv-heads --data $T/hv-rows.jsonl --projection minimal full --grid-decode $d --output $T/hv-$d > $T/hv-$d.log 2>&1"; done \
| xargs -d '\n' -P 2 -I CMD bash -c CMD
$P crosscheck.py --pair "在线 spread(三字段)=$T/hv-online/outcomes.jsonl,$T/hv-spread/outcomes.jsonl" \
--pair "在线 spread(完整条件)=$T/hv-online/outcomes-full.jsonl,$T/hv-spread/outcomes-full.jsonl" \
--pair "缺文件示例=$T/none/outcomes.jsonl,$T/hv-spread/outcomes.jsonl" > $T/crosscheck.md
grep -q "| 在线 spread(三字段) | 24 | 24 |" $T/crosscheck.md && grep -q "| 在线 spread(完整条件) | 24 | 24 |" $T/crosscheck.md
# the code check refuses an online run against a head-output decode
if $P compare.py --a $T/hv-online --b $T/hv-argmax --out $T/refused.json 2> $T/refused.txt; then echo "NOT REFUSED"; exit 1; fi
grep -q "refused: the runs were not decoded by the same code" $T/refused.txt
# (2) stratify (every overall number must reproduce report.json exactly) — validation (heads) and test (10-07 reports)
S() { local out; out=$($P stratify.py --workers $W --cache $K "$@"); grep -q '"reproduces_report_exactly": true' <<< "$out" || { echo "NOT REPRODUCED: $*"; return 1; }; }
for d in spread argmax; do
S --eval-dir $T/hv-$d --out $T/val-minimal-$d.json
S --eval-dir $T/hv-$d --outcomes outcomes-full.jsonl --out $T/val-full-$d.json
done
S --eval-dir $B --rows $OLD/test.jsonl --out $T/baseline-test-minimal-spread.json
S --eval-dir $B-argmax --rows $OLD/test.jsonl --out $T/baseline-test-minimal-argmax.json
S --eval-dir $B --outcomes outcomes-full.jsonl --rows $OLD/test.jsonl --out $T/baseline-test-full-spread.json
[ -d $T/shift ] || $P selftest_shift.py --rows ablation-sample-500/new.jsonl --work $T/shift # rule attribution (asserts inside)
# (3) compare: placeholder final-vs-baseline (<= 128 objects) and spread-vs-argmax, as run_plan does
C() { $P compare.py --workers $W --cache $K "$@" > /dev/null; }
for proj in minimal full; do
o=outcomes.jsonl; [ $proj = minimal ] || o=outcomes-full.jsonl
for d in spread argmax; do
for sel in all "old rule=frozen_prep" "new rule=wall_anchor,support_inside_parent,support_on_added_parent"; do
set -- $sel
C --a $T/hv-$d --a-outcomes $o --b $T/hv-$d --b-outcomes $o --label-a "最终(占位=基线)" --label-b 基线 --max-objects 128 \
${2:+--where $2} --out $T/compare-val-$proj-$d-$1.json
done
done
C --a $T/hv-spread --a-outcomes $o --b $T/hv-argmax --b-outcomes $o --label-a spread --label-b argmax --out $T/decode-val-$proj.json
done
$P -c "import json; r=json.load(open('$T/compare-val-minimal-spread-all.json'))['rooms']; assert r['excluded_by_room_filter'] == 2, r"
C --a $B --b $B-argmax --label-a spread --label-b argmax --out $T/decode-test-minimal.json
for sel in "old rule=frozen_prep" "new rule=wall_anchor,support_inside_parent,support_on_added_parent"; do
set -- $sel
C --a $B --b $B --a-outcomes outcomes-full.jsonl --b-outcomes outcomes-full.jsonl --label-a "最终(占位=基线)" --label-b 基线 \
--max-objects 128 --where $2 --out $T/compare-test-full-spread-$1.json
done
# (4) FastFill vs the four LLM modes on the frozen 300 rows (failure causes from predictions.jsonl)
M=(); for m in prompt harness structured structured-harness; do
M+=(--method "LLM $m=$R/runs/llm-$m-300-eval-4125b82,$R/runs/llm-$m-300/summary.json"); done
# argmax latency from the online spread run, as run_plan does (a head-output decode observes none)
$P llm_compare.py --method "FastFill spread=$L" --method "FastFill argmax=$L-argmax,$L" "${M[@]}" \
--selection-cohort $COHORT_OLD --selection-cohort $COHORT_OLD1 --out $T/llm-compare-baseline.json --workers $W > /dev/null
$P - $T/llm-compare-baseline.json <<'PY'
import json, sys
c = {x["method"]: x for x in json.load(open(sys.argv[1]))["cost"]}
assert c["LLM prompt"]["failure_causes"] == {"IncompleteRead": 7}, c["LLM prompt"]
assert c["FastFill argmax"]["latency_grid_decode"] == "spread" and c["FastFill spread"]["latency_source"] == "this run"
for m, x in c.items():
assert x["kind"] != "llm" or abs(x["mean_latency_s"] - x["summary_mean_latency_s"]) < 1e-6, m
f = x["failed_rooms"]
print(m, "failed (objects, rank):", f and [(r["objects"], r["rank"]) for r in f["rooms"]], f and f["p_all_in_largest_if_size_independent"])
PY
# the ablation sample overlaps the selection cohort of the same scenes (report.py --ablation-sample flag)
$P -c "import json, report; s=json.load(open('ablation-sample-500/sample.json')); print('ablation sample in old cohort:', len(set(s['scene_ids']) & report.scene_ids('$COHORT_OLD')), '/', len(s['scene_ids']))"
# the selection-bias note's three cases; the final's select2 rows do not exist yet: stand-ins named like a cohort file
ln -sf hv-rows.jsonl $T/validation-$(sha256sum $R/data/main-20261008a/validation.jsonl | cut -c1-12)-standin.jsonl
[ -s $T/one-test-row.jsonl ] || head -1 $OLD/test.jsonl > $T/one-test-row.jsonl
$P - $T $COHORT_OLD <<'PY'
import glob, sys, report
t, old = sys.argv[1:]
ids, base = report.scene_ids(f"{t}/hv-rows.jsonl"), [("基线(select2)", old)]
both = report.bias_note("x", ids, base + [("最终(替身)", glob.glob(f"{t}/validation-*-standin.jsonl")[0])])
assert "方向无法确定" in both and "不同数据版本" in both and "只有最终的选择见过新对象" in both and "偏向" not in both, both
one = report.bias_note("x", ids, base + [("最终(替身:一行测试集)", f"{t}/one-test-row.jsonl")])
assert "只有基线的选择队列含这些场景" in one and "可能偏向基线" in one, one
assert "未提供最终的选择队列" in report.bias_note("x", ids, base)
print("bias note:", both, one, sep="\n")
PY
# (5) RoomGenBench reference check with the code on disk of the baseline's CPU export (best-round1, 2026-10-08 03:00)
mkdir -p $T/reference-base-round1
for room in bathroom bedroom gym livingroom restaurant; do
[ -f $T/reference-base-round1/$room.json ] || $P -m fastfill.v2.roomgenbench --reference-check $R/runs/roomgenbench/best-round1/$room.handoff \
--scene $R/RoomGenBench/bench/inputs/scenes/$room.json --output $T/reference-base-round1/$room.json > /dev/null
done
# (6) the sample report
V=(); for d in spread argmax; do for p in minimal full; do
n=三字段; [ $p = minimal ] || n=完整条件
V+=(--val-run "基线·$n·$d(24 房间,CPU 头输出)=$T/val-$p-$d.json")
for x in all:全部对象 old:旧对象 new:新对象; do V+=(--val-compare "最终 vs 基线·$n·$d·${x#*:}(≤128 物体,占位)=$T/compare-val-$p-$d-${x%%:*}.json"); done
done; done
$P report.py --out $T/sample_report.html --title "FastFill v2 评测报告(样例:最终=基线占位;验证集=24 个新验证房间的 CPU 头输出)" \
--summary $R/runs/autorun-baseline-20261007b/SUMMARY.md "${V[@]}" \
--val-decode "基线·三字段:spread vs argmax=$T/decode-val-minimal.json" --val-decode "基线·完整条件:spread vs argmax=$T/decode-val-full.json" \
--test-run "基线·三字段·spread=$T/baseline-test-minimal-spread.json" --test-run "基线·三字段·argmax=$T/baseline-test-minimal-argmax.json" \
--test-run "基线·完整条件·spread=$T/baseline-test-full-spread.json" \
--test-compare "最终 vs 基线·完整条件·spread·旧对象(占位)=$T/compare-test-full-spread-old.json" \
--test-compare "最终 vs 基线·完整条件·spread·新对象(占位,旧数据无新对象)=$T/compare-test-full-spread-new.json" \
--test-decode "基线·三字段:spread vs argmax=$T/decode-test-minimal.json" \
--llm $T/llm-compare-baseline.json \
--ablation "基线(diag/ablation500:旧验证集文件顺序前 500 行)=$R/runs/diag/ablation500/report.json" \
--selection-cohort "基线(select2,旧验证集全集)=$COHORT_OLD" --selection-cohort "基线(select1,旧验证集 3000 行)=$COHORT_OLD1" \
--reference "基线 best-round1(CPU 导出;当前代码检查)=$T/reference-base-round1" \
--walltime $T/walltime.tsv --notes $T/crosscheck.md
echo SAMPLE-DONE
|