一、SCINet光照增强网络
SCINet(自校正照明网络)是一种专为低光照图像增强设计的框架。它通过级联照明学习过程和权重共享机制来处理图像,优化了照明部分以提升图像质量。我将该网络集成在YOLOv8的主干上针对于图像的输入进行增强,同时该网络的并不会增加参数和计算量,基本和普通的网络结构保持一致,同时该结构支持自定义调节层数,来控制图像增强的效果。
论文地址:https://arxiv.org/pdf/2204.10137.pdf
SCINet(自校正照明网络)是一种专为低光照图像增强设计的框架。它通过级联照明学习过程和权重共享机制来处理图像,优化了照明部分以提升图像质量。SCINet引入了自校正模块,用于减少计算负担并提高结果的稳定性。此外,其无监督训练损失功能使得模型能够适应不同场景。SCINet还显示出对简单操作设置的稳定性能适应性,以及可以提升现有照明增强工作性能的普适性。
二、SCINet原理总结
SCINet的基本原理可以分为以下几个主要部分:
1. 级联照明学习与权重共享: SCINet采用了一个级联的照明学习过程,其中各个阶段共享权重。这种设计旨在优化照明组件,从而提升低光照图像的增强效果。
2. 自校正模块: 为了减少计算负担并提高暴露稳定性,SCINet构建了一个自校正模块。这个模块能够使每个阶段的结果收敛,从而在测试阶段仅需使用单个基础块。
3. 无监督训练损失: 作者定义了一种无监督训练损失来约束自校正模块下每个阶段的输出,使模型能够适应多种场景。
其主要的结构在于级联照明学习与权重共享,具体见下面。
2.1级联照明学习与权重共享
1. 级联过程:在级联照明学习中,模型由多个阶段组成,每个阶段都对输入图像的照明进行估计。这种多阶段的处理方式有助于逐步改善图像亮度,每个阶段都在前一个阶段的基础上进一步提升图像质量。
2. 权重共享:在这些阶段中,模型的参数(权重)是共享的。这意味着,尽管每个阶段都执行相似的任务,但它们使用相同的模型参数来执行这些任务。权重共享可以减少模型的整体参数数量,从而减少了模型的复杂性和过拟合的风险。
3. 自校正模块:在每个阶段之后,一个自校正模块被用来校正当前阶段的输出。这一校正确保了随着级联过程的进行,每个阶段的输出逐渐趋于稳定,并且最终输出的质量不会因为过多的处理步骤而退化。
4. 计算效率:由于使用了权重共享,模型在训练时可以有效地学习如何处理低光照图像。在测试阶段,只需使用单个照明估计模块,这大大简化了模型并提高了推理速度。
5. 性能提升:级联照明学习与权重共享的结合使得模型不仅在处理单一图像时表现出色,也能够适应不同的低光照条件和场景,提升了模型的泛化能力和实际应用价值。
该文效果展示可以见见图。此网络最主要的是不会带来额外的计算量,用以插入yolo改进的同学可以试一下
三、实现过程
3.1 SCINet代码
import torch
import torch.nn as nn
__all__ = ['SCINet']
class SCINet(nn.Module):
def __init__(self, channels=3, layers=3):
super(SCINet, self).__init__()
kernel_size = 3
dilation = 1
padding = int((kernel_size - 1) / 2) * dilation
self.in_conv = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=channels, kernel_size=kernel_size, stride=1, padding=padding),
nn.ReLU()
)
self.conv = nn.Sequential(
nn.Conv2d(in_channels=channels, out_channels=channels, kernel_size=kernel_size, stride=1, padding=padding),
nn.BatchNorm2d(channels),
nn.ReLU()
)
self.blocks = nn.ModuleList()
for i in range(layers):
self.blocks.append(self.conv)
self.out_conv = nn.Sequential(
nn.Conv2d(in_channels=channels, out_channels=3, kernel_size=3, stride=1, padding=1),
nn.Sigmoid()
)
def forward(self, input):
fea = self.in_conv(input)
for conv in self.blocks:
fea = fea + conv(fea)
fea = self.out_conv(fea)
illu = fea + input
illu = torch.clamp(illu, 0.0001, 1)
return illu
if __name__ == "__main__":
# Generating Sample image
image_size = (1, 3, 640, 640)
image = torch.rand(*image_size)
# Model
mobilenet_v1 = SCINet(3, 3)
out = mobilenet_v1(image)
print(out.size())
3.1 实现方式
将此代码注册入YOLO的过程如下,首先是加载位置(位于parser_model模块的加载模块位置内),其次是yaml写法。
elif m in {SCINet}:
args = [ch[f], *args]
yaml写法如下:
# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8-World object detection model with P3-P5 outputs. For details see https://docs.ultralytics.com/tasks/detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs
s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPs
m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, SCINet, [5]] # 0-P1/2
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2fAttn, [512, 256, 8]] # 12
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2fAttn, [256, 128, 4]] # 15 (P3/8-small)
- [[15, 12, 9], 1, ImagePoolingAttn, [256]] # 16 (P3/8-small)
- [15, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2fAttn, [512, 256, 8]] # 19 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2fAttn, [1024, 512, 16]] # 22 (P5/32-large)
- [[15, 19, 22], 1, WorldDetect, [nc, 512, False]] # Detect(P3, P4, P5)
根据此配置文件可自行迁移到其他模型中;加载方式大体相同。