Self-DACE++: Robust Low-Light Enhancement via Efficient Adaptive Curve Estimation
This repository hosts the Self-DACE++ model weights and code β an unsupervised, lightweight two-stage framework for Low-Light Image Enhancement (LLIE). It builds upon the original Self-DACE (arXiv:2308.08197) with enhanced Adaptive Adjustment Curves (AAC), a physics-grounded Retinex objective, and a randomized-order training strategy for efficient real-time inference.
Model Description
Overview
Self-DACE++ addresses the fundamental challenge of enhancing images captured in poor lighting conditions, without requiring any paired (dark / normal-light) training data. It is composed of two cascaded networks:
| Stage | Network | Role |
|---|---|---|
| Stage 1 | Light Enhancement Net | Adaptive Adjustment Curve (AAC) estimation for luminance recovery |
| Stage 2 | Denoising Net | Physics-grounded noise removal for dark-region artifacts |
Stage 1 β Light Enhancement Network
The core of Stage 1 is a lightweight CNN that learns per-pixel Adaptive Adjustment Curves (AAC). For each pixel at each layer, the network predicts an amplitude and a beta parameter, and applies the following iterative curve mapping:
x_i+1 = x_i + amplitude Β· sigmoid(-15Β·(-x_i + beta - 0.1)) Β· x_i Β· (beta - x_i) / beta
Key properties:
- Architecture: Lightweight CNN, ~200K parameters (small variant)
- Layers: 12 convolutional layers split into low-frequency (11 layers, brightness) and high-frequency (1 layer, detail/highlight) branches
- Input/Output: RGB image β enhanced RGB image + amplitude map + beta map
- Randomized-order training: Layer processing order is randomized at training time for robustness, then fused at inference for efficiency
Stage 2 β Denoising Network
After luminance enhancement, amplified sensor noise becomes visible. Stage 2 applies a residual CNN denoiser:
- Architecture: 19-layer ResNet-style network (64 channels)
- Training: Synthetic noise injection (Ο β [0.001, 0.009]) with L1 + SSIM + gradient losses
- Joint training: Alternates between optimizing the light network and the denoising network
Checkpoints in This Repository
| File | Stage | Description |
|---|---|---|
stage_1_lit/snapshots_light/pre_train_1.pth |
Stage 1 | Pre-trained Stage 1 backbone (standard size) |
stage_1_lit/snapshots_light/Epoch70.pth |
Stage 1 | Stage 1 fine-tuned checkpoint at Epoch 70 |
stage_1_small_lit/snapshots_light/Epoch100.pth |
Stage 1 | Lightweight Stage 1 checkpoint at Epoch 100 |
stage_2_denoising/snapshots_denoise/pre_train_2.pth |
Stage 2 | Pre-trained Stage 2 denoiser |
stage_2_denoising/snapshots_denoise/litEpoch10.pth |
Stage 2 | Joint Stage 1+2 fine-tuned checkpoint at Epoch 10 |
Intended Uses & Limitations
Primary Use Cases
- Low-light image enhancement for photography, surveillance, and autonomous driving
- Preprocessing for downstream vision tasks (detection, segmentation) in dark conditions
- Research baseline for unsupervised LLIE methods
Evaluated Downstream Tasks
- Dark face detection β DarkFace dataset via RetinaFace detector
- Low-light interactive segmentation β PiClick dataset
Limitations
- Designed for natural scene low-light; may not generalize to extreme over-exposure or non-natural illumination
- Performance may degrade for images with severe compression artifacts
- Real-time inference benchmarks were measured on a standard GPU; CPU inference is slower
How to Use
Installation
git clone https://github.com/John-Wendell/Self-DACE.git
cd Self-DACE/codes_SelfDACE
pip install -r requirements.txt
Inference β Stage 1 Only (Light Enhancement)
import torch
from stage_1_lit.model import LightNet # or stage_1_small_lit.model for lightweight
model = LightNet()
checkpoint = torch.load('stage_1_lit/snapshots_light/Epoch70.pth', map_location='cpu')
model.load_state_dict(checkpoint)
model.eval()
# img: normalized torch.Tensor of shape [1, 3, H, W] in [0, 1]
with torch.no_grad():
enhanced, amplitude, beta = model(img)
Inference β Full Two-Stage Pipeline
import torch
from stage_2_denoising.model import LightNet, DenoiseNet
# Load Stage 1
light_net = LightNet()
light_ckpt = torch.load('stage_2_denoising/snapshots_denoise/litEpoch10.pth', map_location='cpu')
light_net.load_state_dict(light_ckpt['light'])
light_net.eval()
# Load Stage 2
denoise_net = DenoiseNet()
denoise_net.load_state_dict(light_ckpt['denoise'])
denoise_net.eval()
with torch.no_grad():
enhanced, _, _ = light_net(img)
denoised = denoise_net(enhanced)
Testing via Command Line
# Stage 1 only
cd stage_1_lit
python test_1stage.py
# Full two-stage
cd stage_2_denoising
python test_2stage.py
Training Details
Stage 1 Training
| Hyperparameter | Value |
|---|---|
| Optimizer | Adam (lr=1e-4, weight_decay=1e-4) |
| Scheduler | StepLR (step=250, Ξ³=1.0) |
| Batch size | 8 |
| Total epochs | 1000 |
| Gradient clipping | norm = 0.1 |
| Input size | 256Γ256 |
Loss function:
| Loss term | Description |
|---|---|
| $\mathcal{L}_{SMO}$ | Smoothness regularization on AAC parameters |
| $\mathcal{L}_{exp}$ | Exposure control β mean patch luminance β 0.8 |
| $\mathcal{L}_{gcol}$ | Global color balance β RGB channels β uniform (1/3 each) |
| $\mathcal{L}_{locl}$ | Local color consistency via 4Γ4 pooled regions |
Stage 2 Training (Joint Fine-tuning)
| Hyperparameter | Value |
|---|---|
| Light net lr | 1e-6 |
| Denoise net lr | 1e-5 |
| Batch size | 8 |
| Training strategy | Alternating (every 500+ iters swap target network) |
| Noise injection | Ο β [0.001, 0.009] |
Denoising losses:
Datasets
| Dataset | Split | Purpose |
|---|---|---|
| SCIE | Train | Unsupervised training (no paired GT required) |
| LOL | Test | Low-light enhancement evaluation |
| SCIE | Test | Enhancement quality benchmark |
| DarkFace | Test | Dark face detection downstream task |
| PiClick | Test | Interactive segmentation downstream task |
Evaluation
Metrics: PSNR (dB), SSIM
The method is benchmarked on the LOL and SCIE test sets, evaluated with standard image restoration metrics. Self-DACE++ achieves superior enhancement quality with real-time inference capability, outperforming state-of-the-art unsupervised methods. See the papers for full quantitative comparisons.
Repository Structure
new_version/
βββ stage_1_lit/ # Standard-size Stage 1
β βββ model.py # LightNet: Adaptive Curve Estimation
β βββ train_1stage.py # Stage 1 training script
β βββ test_1stage.py # Stage 1 inference
β βββ Myloss.py # All loss functions
β βββ eval.py # PSNR / SSIM evaluation
β βββ dataloader.py
β βββ snapshots_light/
β βββ pre_train_1.pth β Pre-trained Stage 1
β βββ Epoch70.pth β Fine-tuned Stage 1
βββ stage_1_small_lit/ # Lightweight Stage 1 variant
β βββ model.py
β βββ train_1stage.py
β βββ snapshots_light/
β βββ Epoch100.pth β Lightweight checkpoint
βββ stage_2_denoising/ # Stage 2 + joint training
βββ model.py # DenoiseNet (19-layer ResNet)
βββ train_2stage.py # Alternating joint training
βββ test_2stage.py # Full pipeline inference
βββ eval.py
βββ snapshots_denoise/
βββ pre_train_2.pth β Pre-trained denoiser
βββ litEpoch10.pth β Joint Stage 1+2 checkpoint
Citation
If you find this work useful, please cite:
@article{wen2026selfdaceplusplus,
title = {Self-DACE++: Robust Low-Light Enhancement via Efficient Adaptive Curve Estimation},
author = {Wen, Jianyu and Xie, Jun and Chen, Feng and Wang, Zhepeng and Wu, Chenhao and Zhang, Tong and Yu, Yixuan and Swierczynski, Piotr},
journal = {arXiv preprint arXiv:2604.25367},
year = {2026}
}
@article{wen2023selfdace,
title = {Self-Reference Deep Adaptive Curve Estimation for Low-Light Image Enhancement},
author = {Wen, Jianyu and Wu, Chenhao and Zhang, Tong and Yu, Yixuan and Swierczynski, Piotr},
journal = {arXiv preprint arXiv:2308.08197},
year = {2023}
}
Acknowledgements
- ZeroDCE β inspiration for zero-reference curve estimation
- SCIE Dataset β training data
- LOL Dataset β evaluation benchmark
For issues, questions, or contributions, please visit the GitHub repository.