RRDBNet β Low-Light Denoising + 4x Super-Resolution (DLP 26T2 NPPE3)
An RRDBNet (ESRGAN/Real-ESRGAN generator family) checkpoint trained end-to-end to jointly denoise low-light images and upscale them 4x, as part of the DLP 26T2 NPPE3 course competition (scored by PSNR).
Model description
- Architecture: RRDBNet β a stack of Residual-in-Residual Dense Blocks (RRDB) followed by 2 pixel-shuffle upsampling stages (2x each, for a total of 4x).
- Config:
nf=64feature channels,nb=23RRDB blocks,gc=32growth channels per dense block,scale=4. - Input / output: RGB image in
[0, 1]β RGB image in[0, 1], upscaled 4x in each spatial dimension. Fully convolutional β accepts any input resolution. - Loss: Charbonnier loss (a smooth, robust L1 variant), chosen over plain L1/MSE since it tolerates residual sensor noise in the targets better.
- Framework: implemented from scratch in PyTorch (no
basicsrdependency), trained with a PyTorch Lightning training loop (Adam optimizer, cosine LR schedule, mixed precision, best-checkpoint selection by validation PSNR).
Intended uses & limitations
- Intended for restoring low-light, noisy images from the DLP 26T2 NPPE3 dataset distribution (LR β 256Γ160 β HR β 1024Γ640) and similar low-light noisy photos.
- Trained for a PSNR-oriented objective only β no adversarial/perceptual loss was used, so outputs prioritize pixel-accurate reconstruction over perceptual sharpness (edges may look slightly soft compared to GAN-based SR models).
- Not evaluated on natural images far outside the training distribution (e.g. well-lit photos, non-photographic content, extreme upscale factors).
Training data
Paired low-resolution/noisy and high-resolution/clean images from the DLP 26T2
NPPE3 competition dataset (train/low + train/gt, validated against val/low
val/gt). Training used random 128Γ128 LR patches (512Γ512 HR) with random flip/rotation augmentation.
How to use
import torch
from rrdbnet import RRDBNet # your model definition module
model = RRDBNet(scale=4, nf=64, nb=23, gc=32)
# Checkpoint is a PyTorch Lightning .ckpt β state dict keys are prefixed with "model."
ckpt = torch.load("best.ckpt", map_location="cpu")
state_dict = {k.removeprefix("model."): v for k, v in ckpt["state_dict"].items()}
model.load_state_dict(state_dict)
model.eval()
# inference
from PIL import Image
import torchvision.transforms.functional as TF
lr_img = Image.open("input.png").convert("RGB")
lr_tensor = TF.to_tensor(lr_img).unsqueeze(0)
with torch.no_grad():
hr_tensor = model(lr_tensor)
hr_img = TF.to_pil_image(hr_tensor.squeeze(0).clamp(0, 1))
hr_img.save("output.png")
Evaluation
Validated by PSNR (dB) on the held-out val split of the DLP 26T2 NPPE3 dataset
during training; best checkpoint selected by peak validation PSNR.
Limitations
- No GAN/perceptual fine-tuning stage β if perceptual sharpness matters more than PSNR for your use case, consider fine-tuning further with an adversarial loss.
- Performance on inputs with noise characteristics or lighting conditions very different from the training set is untested.
Citation
If you use this checkpoint, please cite the RRDBNet/ESRGAN architecture it's based on:
Wang, X., et al. "ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks." ECCV Workshops, 2018.