A lightweight, production-ready image deblurring model designed to meet all NTIRE 2026 challenge constraints.
| Constraint | Limit | Model |
|---|---|---|
| Parameters | ≤ 5M | ~2.5M ✅ |
| Compute | ≤ 200 GMACs | ~100 GMACs ✅ |
| FHD Inference | < 1s | < 200ms GPU ✅ |
EfficientDeblurNet is a 3-level U-Net encoder-decoder built from efficient blocks:
- SimpleGate — zero-parameter activation (element-wise product of split channels)
- DWConvBlock — depthwise-separable conv + LayerNorm + SimpleGate + residual
- ChannelAttentionLite — GAP + 1×1 × 2 + Sigmoid (no MLP overhead)
- PixelShuffleUp — checkerboard-free 2× upsampling
- StrideDown — learned strided DW-conv downsampling
Input(3ch) → Stem(32ch)
Encoder: [32→64→128→256ch] with StrideDown
Bottleneck: 4× EfficientBlock @ 256ch
Decoder: [256→128→64→32ch] with PixelShuffleUp + skip-cat
Head: LayerNorm → Conv3×3 → +input_residual
deblur_ntire2026/
├── models/
│ ├── blocks.py # DWConvBlock, SimpleGate, ChannelAttentionLite, EfficientBlock
│ └── deblur_net.py # EfficientDeblurNet, build_model()
├── dataset/
│ ├── rsblur_dataset.py # RSBlur, GoPro, RealBlur, PairedImageDataset loaders
│ └── augmentations.py # PairedAugment, ValTransform
├── training/
│ ├── losses.py # CharbonnierLoss, PerceptualLoss, FFTLoss, CombinedLoss
│ ├── trainer.py # Trainer (AMP, AdamW, cosine LR, grad clip, TensorBoard)
│ ├── scheduler.py # build_scheduler (cosine_warmup, step)
│ └── distillation.py # DistillationLoss, DistillationTrainer (bonus)
├── evaluation/
│ ├── metrics.py # compute_psnr, compute_ssim, LPIPSMetric
│ └── evaluate.py # Batch evaluation script
├── inference/
│ ├── infer.py # Tiled + direct inference, wall-clock timing
│ ├── export.py # TorchScript + ONNX export
│ └── tta.py # 4-flip / 8-rot test-time augmentation (bonus)
├── utils/
│ ├── config.py # YAML config loader
│ ├── logger.py # Python logging + TensorBoard writer
│ ├── efficiency.py # thop FLOPs/params counter
│ └── pruning.py # L1 unstructured pruning hooks (bonus)
├── configs/
│ ├── train_config.yaml # Full training hyperparameters
│ └── model_config.yaml # Model architecture config
├── train.py # Training entry point
├── eval.py # Evaluation entry point
├── infer_single.py # Single/batch inference with timing
└── efficiency_check.py # Parameter & FLOP compliance checker
pip install -r requirements.txtKey dependencies: PyTorch ≥ 2.1, torchvision ≥ 0.16, PyYAML, thop, lpips, tensorboard
data/rsblur/
train/input/ # blurry PNGs
train/target/ # sharp PNGs
val/input/
val/target/
data/gopro/
train/GOPR0xxx/blur_gamma/*.png
train/GOPR0xxx/sharp/*.png
test/...
Update configs/train_config.yaml:
data:
dataset: rsblur # or gopro / generic
root: data/rsblur# Standard training (300 epochs, cosine LR warmup)
python train.py --config configs/train_config.yaml
# Resume from checkpoint
python train.py --config configs/train_config.yaml --resume checkpoints/epoch_0100.pth
# Debug smoke test (2 iterations, 1 epoch)
python train.py --config configs/train_config.yaml --debug
# TensorBoard monitoring
tensorboard --logdir logs/Training defaults:
- Optimizer: AdamW (lr=2e-4, wd=1e-4, β=(0.9, 0.9))
- LR schedule: Cosine annealing with 5-epoch warmup
- Loss: Charbonnier (1.0) + Perceptual/VGG (0.05) + FFT (0.1)
- Mixed precision: FP16 (torch.cuda.amp)
- Grad clipping: max_norm=1.0
- Batch size: 8 × 256×256 crops
python eval.py \
--config configs/train_config.yaml \
--checkpoint checkpoints/best.pth \
--data_dir data/rsblur/val \
--device cudaOutputs: mean PSNR (dB), SSIM, LPIPS per image and aggregated.
python infer_single.py \
--input data/test/blur.png \
--output results/sharp.png \
--checkpoint checkpoints/best.pth \
--config configs/train_config.yaml \
--device cudapython infer_single.py \
--input_dir data/test/blur/ \
--output_dir results/ \
--checkpoint checkpoints/best.pth \
--device cudapython infer_single.py --input blur.png --output sharp.png \
--checkpoint checkpoints/best.pth --tta flip4Tiled inference is enabled by default (tile=512, overlap=32) to handle FHD on low-VRAM GPUs.
# Check params, GMACs and FHD timing
python efficiency_check.py --device cuda
# CPU timing (for reproducibility)
python efficiency_check.py --device cpuExpected output:
Parameters : 2.50M ✅ [limit: 5.00M]
GMACs (FHD) : ~100 ✅ [limit: 200]
Inference : ~180ms ✅ [limit: 1000ms]
python inference/export.py \
--checkpoint checkpoints/best.pth \
--format torchscript \
--output model_ts.ptpython inference/export.py \
--checkpoint checkpoints/best.pth \
--format onnx \
--output model.onnxBoth modes verify the exported model reproduces the same output (max error < 1e-4).
Use a larger teacher model (e.g., NAFNet) to boost student quality:
# In train_config.yaml
distillation:
enabled: true
teacher_checkpoint: path/to/teacher.pth
distill_weight: 0.5from utils.pruning import prune_model, remove_pruning
prune_model(model, amount=0.3) # 30% L1 unstructured pruning
remove_pruning(model) # make pruning permanentThis code is intended for the NTIRE 2026 challenge. See challenge rules for usage terms.