DGFF / mps_probe.py
abbaab's picture
Upload folder using huggingface_hub (part 5)
d610c9f verified
Raw History Blame Contribute Delete
3.82 kB
"""
mps_probe.py β€” answers ONE question: will the Table 6 ablation
(real_ablation_cell.py, which trains LLEN+DGFFModule directly, NOT via
Ultralytics) run on MPS or fall back to CPU on this machine/environment?
This does NOT test Ultralytics detector training (that's a separate code
path and separate question, already known to be slow on this setup).
This tests the actual custom training loop the ablation uses.
Strictly time-bounded: 10 iterations only, so this finishes in well under
a minute even in the worst case. Needs models.py in the same directory.
"""
import time
import torch
print(f"torch version: {torch.__version__}")
print(f"MPS built: {torch.backends.mps.is_built()}")
print(f"MPS available: {torch.backends.mps.is_available()}")
if not torch.backends.mps.is_available():
print("\nMPS is NOT available in this environment. The ablation will run "
"on CPU. Given today's CPU timings for a much smaller model were "
"already very slow, expect the ablation to be impractically slow "
"too -- don't start it blind. Consider a different conda env/torch "
"build (this one is on Python 3.14.2 / torch 2.10.0, both very new "
"-- an older, more established torch build may have better MPS "
"support) before committing to a long run.")
raise SystemExit
device = torch.device('mps')
print(f"\nUsing device: {device}")
from models import LLEN, DGFFModule # same file used for benchmark.py earlier
BATCH = 4 # matches paper's Phase 1 batch size
CROP = 256 # matches paper's Phase 1 crop size
N_ITERS = 10
print(f"\nBuilding LLEN + DGFFModule on {device}...")
llen = LLEN(base_ch=32).to(device)
dgff = DGFFModule(yolo_weights='yolov8n.pt', llen_base_ch=32, freeze_backbone=True).to(device)
trainable = list(llen.parameters()) + list(dgff.adapter_p3.parameters()) + \
list(dgff.adapter_p4.parameters()) + list(dgff.adapter_p5.parameters())
optimiser = torch.optim.Adam(trainable, lr=1e-4)
l1 = torch.nn.L1Loss()
dummy_low = torch.rand(BATCH, 3, CROP, CROP, device=device)
dummy_high = torch.rand(BATCH, 3, CROP, CROP, device=device)
print(f"Running {N_ITERS} timed training iterations "
f"(batch={BATCH}, crop={CROP}x{CROP}, matches paper's Phase 1 settings)...")
# warmup (first MPS call compiles kernels -- don't count this)
enhanced = llen(dummy_low)
p4, p5, p3 = dgff(enhanced)
guided = llen(dummy_low, dgff_p5=p5, dgff_p4=p4, dgff_p3=p3)
loss = l1(guided, dummy_high)
loss.backward()
torch.mps.synchronize()
times = []
for i in range(N_ITERS):
torch.mps.synchronize()
t0 = time.perf_counter()
optimiser.zero_grad()
enhanced = llen(dummy_low)
p4, p5, p3 = dgff(enhanced)
guided = llen(dummy_low, dgff_p5=p5, dgff_p4=p4, dgff_p3=p3)
loss = l1(guided, dummy_high)
loss.backward()
optimiser.step()
torch.mps.synchronize()
dt = time.perf_counter() - t0
times.append(dt)
print(f" iter {i+1}/{N_ITERS}: {dt:.3f}s")
mean_iter = sum(times) / len(times)
print(f"\nMean time/iteration: {mean_iter:.3f}s")
# ── extrapolate to full ablation cost ──
TRAIN_PAIRS = 485 # paper's LOL train set size
iters_per_epoch = TRAIN_PAIRS / BATCH
ablation_epochs = 50
n_configs = 4
total_iters = iters_per_epoch * ablation_epochs * n_configs
est_seconds = total_iters * mean_iter
print(f"\n=== Extrapolated full ablation cost (4 configs x {ablation_epochs} epochs) ===")
print(f" ~{iters_per_epoch:.0f} iterations/epoch x {ablation_epochs} epochs x {n_configs} configs "
f"= {total_iters:.0f} total iterations")
print(f" Estimated total time: {est_seconds/3600:.1f} hours")
print(f" (paper's Phase 1: 200 epochs, single config, reported as 7.6h on MPS -- "
f"this is a rough sanity cross-check on the estimate above)")