DGFF / SPIC /benchmark.py
abbaab's picture
Upload folder using huggingface_hub (part 22)
af3f769 verified
Raw History Blame Contribute Delete
5.07 kB
import time
import torch
import torch.nn as nn
from ultralytics import YOLO
from thop import profile
from models import LLEN, DGFFModule
torch.manual_seed(0)
IMG_SIZE = 256 # matches training crop size in the paper
N_WARMUP = 5
N_TIMED = 30
device = torch.device('cpu')
print("=" * 70)
print("1. PARAMETER COUNTS")
print("=" * 70)
llen = LLEN(base_ch=32).to(device).eval()
dgff = DGFFModule(yolo_weights='yolov8n.pt', llen_base_ch=32, freeze_backbone=True).to(device).eval()
llen_params = sum(p.numel() for p in llen.parameters())
dgff_total, dgff_trainable = dgff.count_parameters()
backbone_params = sum(p.numel() for p in dgff.backbone.parameters())
adapter_params = dgff_total - backbone_params
print(f"LLEN total params : {llen_params:,}")
print(f"DGFF backbone (frozen) params: {backbone_params:,}")
print(f"DGFF adapter (trainable) params: {adapter_params:,}")
print(f"DGFF module total params : {dgff_total:,}")
# Full YOLOv8n detector (backbone+neck+head) for actual detection inference
yolo_full = YOLO('yolov8n.pt')
yolo_det_params = sum(p.numel() for p in yolo_full.model.parameters())
print(f"Full YOLOv8n detector params : {yolo_det_params:,}")
print()
print("=" * 70)
print("2. FLOPs (thop, single image, {}x{})".format(IMG_SIZE, IMG_SIZE))
print("=" * 70)
dummy = torch.rand(1, 3, IMG_SIZE, IMG_SIZE)
# LLEN alone (Pass-1-equivalent / inference-time enhancement)
macs_llen, params_llen = profile(llen, inputs=(dummy,), verbose=False)
print(f"LLEN forward : {macs_llen/1e9:.3f} GMACs ({2*macs_llen/1e9:.3f} GFLOPs)")
# DGFF module alone (backbone truncated to 10 layers + 3 adapters) -- TRAINING ONLY
macs_dgff, params_dgff = profile(dgff, inputs=(dummy,), verbose=False)
print(f"DGFF module forward (train-only): {macs_dgff/1e9:.3f} GMACs ({2*macs_dgff/1e9:.3f} GFLOPs)")
# Full YOLOv8n detector alone (inference-time detection step)
yolo_model = yolo_full.model.to(device).eval()
macs_yolo, params_yolo = profile(yolo_model, inputs=(dummy,), verbose=False)
print(f"Full YOLOv8n detector forward : {macs_yolo/1e9:.3f} GMACs ({2*macs_yolo/1e9:.3f} GFLOPs)")
print()
print("Pipeline totals:")
raw_flops = 2 * macs_yolo
llen_only_flops = 2 * macs_llen + 2 * macs_yolo
dgff_train_flops = 2 * macs_llen + 2 * macs_dgff + 2 * macs_llen + 2 * macs_yolo # pass1 LLEN + DGFF + pass2 LLEN + detect
dgff_infer_flops = llen_only_flops # DGFF discarded at inference -> identical to LLEN-only
print(f" Raw -> Detect : {raw_flops/1e9:.3f} GFLOPs")
print(f" LLEN-only -> Detect (inference) : {llen_only_flops/1e9:.3f} GFLOPs")
print(f" DGFF TRAINING (2-pass + adapters) : {dgff_train_flops/1e9:.3f} GFLOPs")
print(f" DGFF INFERENCE (adapters discarded) : {dgff_infer_flops/1e9:.3f} GFLOPs (identical arch. to LLEN-only)")
print()
print("=" * 70)
print("3. CPU LATENCY (single-core sandbox CPU -- relative comparison only)")
print("=" * 70)
def time_forward(fn, n_warmup=N_WARMUP, n_timed=N_TIMED):
with torch.no_grad():
for _ in range(n_warmup):
fn()
times = []
for _ in range(n_timed):
t0 = time.perf_counter()
fn()
times.append(time.perf_counter() - t0)
times.sort()
return sum(times) / len(times), times[len(times) // 2]
mean_llen, med_llen = time_forward(lambda: llen(dummy))
mean_yolo, med_yolo = time_forward(lambda: yolo_model(dummy))
mean_dgff, med_dgff = time_forward(lambda: dgff(dummy))
print(f"LLEN forward : mean {mean_llen*1000:.2f} ms | median {med_llen*1000:.2f} ms")
print(f"Full YOLOv8n forward : mean {mean_yolo*1000:.2f} ms | median {med_yolo*1000:.2f} ms")
print(f"DGFF module forward (train-only) : mean {mean_dgff*1000:.2f} ms | median {med_dgff*1000:.2f} ms")
raw_latency = mean_yolo
llen_only_latency = mean_llen + mean_yolo
dgff_infer_latency = llen_only_latency # identical arch at inference
dgff_train_latency = 2 * mean_llen + mean_dgff + mean_yolo # 2-pass LLEN + DGFF extraction/adapters + detect
print()
print("Pipeline latency (mean, ms/image):")
print(f" Raw -> Detect : {raw_latency*1000:.2f} ms ({1/raw_latency:.1f} FPS)")
print(f" LLEN-only -> Detect (inference) : {llen_only_latency*1000:.2f} ms ({1/llen_only_latency:.1f} FPS)")
print(f" DGFF INFERENCE (adapters discarded): {dgff_infer_latency*1000:.2f} ms ({1/dgff_infer_latency:.1f} FPS)")
print(f" DGFF TRAINING (2-pass, for ref.) : {dgff_train_latency*1000:.2f} ms ({1/dgff_train_latency:.1f} FPS)")
print()
print("=" * 70)
print("4. SANITY CHECK vs paper-reported parameter counts")
print("=" * 70)
print(f"Paper claims LLEN = 4,844,803 | measured = {llen_params:,} | match={llen_params==4844803}")
print(f"Paper claims DGFF total = 1,359,120 | measured = {dgff_total:,} | match={dgff_total==1359120}")
print(f"Paper claims adapters = 86,464 | measured = {adapter_params:,} | match={adapter_params==86464}")
print(f"Paper claims backbone = 1,272,656 | measured = {backbone_params:,} | match={backbone_params==1272656}")