skills/cv/efficientdet-headnet-swap/SKILL.md
Load EfficientDet pretrained on COCO with the original 90-class head, then swap in a fresh HeadNet with your own num_classes — keeps the BiFPN feature pyramid pretrained and only retrains the classification head, the canonical transfer-learning recipe for the effdet PyTorch port
npx skillsauth add wenmin-wu/ds-skills cv-efficientdet-headnet-swapInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The default effdet PyTorch package loads EfficientDet checkpoints assuming COCO's 90 classes. If you instantiate with num_classes=2 directly, the state dict load fails because the head shapes don't match. The right pattern is the reverse: instantiate with the original config, load the COCO weights, then mutate config.num_classes and replace net.class_net with a fresh HeadNet. The BiFPN and backbone keep their pretrained weights, the classification head re-initializes for your task, and DetBenchTrain wraps everything in the loss-computing forward pass. This is the canonical 4-line recipe for fine-tuning EfficientDet on any custom detection dataset.
import torch
from effdet import get_efficientdet_config, EfficientDet, DetBenchTrain
from effdet.efficientdet import HeadNet
def get_net(num_classes=2, image_size=512, ckpt='efficientdet_d5-ef44aea8.pth'):
config = get_efficientdet_config('tf_efficientdet_d5')
net = EfficientDet(config, pretrained_backbone=False)
checkpoint = torch.load(ckpt, map_location='cpu')
net.load_state_dict(checkpoint) # load with original 90 classes
config.num_classes = num_classes
config.image_size = image_size
net.class_net = HeadNet(
config,
num_outputs=config.num_classes,
norm_kwargs=dict(eps=1e-3, momentum=0.01),
)
return DetBenchTrain(net, config)
get_efficientdet_config('tf_efficientdet_d5') and instantiate the model with the original COCO classesload_state_dict(checkpoint) — must happen before mutating num_classes, otherwise shapes mismatchconfig.num_classes and config.image_size to your task's valuesnet.class_net with a freshly-initialized HeadNet of the new shapeDetBenchTrain for training (adds the loss heads) or DetBenchPredict for inferencepretrained_backbone=False: the backbone weights are inside the COCO checkpoint already; setting True double-loads and slows init.norm_kwargs=dict(eps=1e-3, momentum=0.01): matches the BatchNorm config the original COCO weights expect; default torch BN values cause silent train/eval mismatch.box_net: only the classification head depends on num_classes; the regression head is class-agnostic.config.image_size: EfficientDet anchors are precomputed for the configured size; mismatched sizes produce empty positives.data-ai
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
data-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF