YOLO11 改进 – 主干网络_ RevCol可逆列网络:轻量级多列设计破解特征信息丢失难题,提升小目标与密集目标感知精度
前言
本文介绍了将可逆列网络(RevCol)与YOLOv11相结合的方法。RevCol由子网副本(列)组成,采用多级可逆连接,在前向传播时特征逐渐解耦且保留整体信息。该架构在图像分类、目标检测和语义分割等任务中表现出色,在多个数据集上取得优异成绩,还可引入到Transformer等网络中。我们将RevCol引入YOLOv11,对相关代码进行修改和注册,并配置了yolov11 - RevCol.yaml文件。通过实验脚本进行训练,结果显示该结合方式在目标检测任务中展现出一定效果。
文章目录: YOLOv11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总
专栏链接: YOLOv11改进专栏
文章目录
[TOC]
介绍
摘要
我们提出了一种新的神经网络设计范式——可逆列网络(Reversible Column Network,简称RevCol)。RevCol的主体由多个子网络的副本组成,分别称为列(columns),列之间采用多层级的可逆连接。这种架构使RevCol的行为与传统网络截然不同:在前向传播过程中,RevCol中的特征在通过每一列时逐渐被解耦,而整体信息得以保留,而不是像其他网络那样被压缩或丢弃。我们的实验表明,CNN风格的RevCol模型在多个计算机视觉任务中(如图像分类、目标检测和语义分割)表现出非常有竞争力的性能,尤其是在较大参数预算和大数据集条件下。例如,在ImageNet-22K上进行预训练后,RevCol-XL在ImageNet-1K上达到了88.2%的准确率。在使用更多预训练数据的情况下,我们最大的模型RevCol-H在ImageNet-1K上达到了90.0%的准确率,在COCO检测minival集上获得63.8%的APbox,在ADE20k分割任务上达到61.0%的mIoU。我们所知,这是纯CNN(静态)模型在COCO检测和ADE20k分割任务上的最佳结果。此外,作为一种通用的大架构模式,RevCol也可以引入到Transformer或其他神经网络中,证明其在计算机视觉和自然语言处理任务中均能提升性能。我们在 https://github.com/megvii-research/RevCol 发布了代码和模型。
文章链接
论文地址: 论文地址
代码地址: 代码地址
基本原理
RevCol 由子网的多个副本组成,分别命名为列,在这些副本之间采用多级可逆连接。RevCol coud 是计算机视觉中各种任务的基础模型主干,包括分类、检测和分割。
核心代码
class RevCol(BaseModule):
def __init__(self, channels=[32, 64, 96, 128], layers=[2, 3, 6, 3], num_subnet=5, kernel_size = 3, num_classes=1000, drop_path = 0.0, save_memory=True, single_head=True, out_indices=[0, 1, 2, 3], init_cfg=None) -> None:
super().__init__(init_cfg)
self.num_subnet = num_subnet
self.single_head = single_head
self.out_indices = out_indices
self.init_cfg = init_cfg
self.stem = nn.Sequential(
nn.Conv2d(3, channels[0], kernel_size=4, stride=4),
LayerNorm(channels[0], eps=1e-6, data_format="channels_first")
)
# dp_rate = self.cal_dp_rate(sum(layers), num_subnet, drop_path)
dp_rate = [x.item() for x in torch.linspace(0, drop_path, sum(layers))]
for i in range(num_subnet):
first_col = True if i == 0 else False
self.add_module(f'subnet{str(i)}', SubNet(
channels,layers, kernel_size, first_col, dp_rates=dp_rate, save_memory=save_memory))
def init_weights(self):
logger = get_root_logger()
if self.init_cfg is None:
logger.warn(f'No pre-trained weights for '
f'{self.__class__.__name__}, '
f'training start from scratch')
for m in self.modules():
if isinstance(m, nn.Linear):
trunc_normal_init(m, std=.02, bias=0.)
elif isinstance(m, nn.LayerNorm):
constant_init(m, 1.0)
else:
assert 'checkpoint' in self.init_cfg, f'Only support ' \
f'specify `Pretrained` in ' \
f'`init_cfg` in ' \
f'{self.__class__.__name__} '
ckpt = _load_checkpoint(
self.init_cfg.checkpoint, logger=logger, map_location='cpu')
if 'state_dict' in ckpt:
_state_dict = ckpt['state_dict']
elif 'model' in ckpt:
_state_dict = ckpt['model']
else:
_state_dict = ckpt
state_dict = _state_dict
# print(state_dict.keys())
# strip prefix of state_dict
if list(state_dict.keys())[0].startswith('module.'):
state_dict = {k[7:]: v for k, v in state_dict.items()}
# load state_dict
self.load_state_dict(state_dict, False)
def forward(self, x):
x = self.stem(x)
c0, c1, c2, c3 = 0, 0, 0, 0
for i in range(self.num_subnet):
# c0, c1, c2, c3 = checkpoint(getattr(self, f'subnet{str(i)}'), x, c0, c1, c2, c3 )
c0, c1, c2, c3 = getattr(self, f'subnet{str(i)}')(x, c0, c1, c2, c3)
return c0, c1, c2, c3
def cal_dp_rate(self, depth, num_subnet, drop_path):
dp = np.zeros((depth, num_subnet))
dp[:,0]=np.linspace(0, depth-1, depth)
dp[0,:]=np.linspace(0, num_subnet-1, num_subnet)
for i in range(1, depth):
for j in range(1, num_subnet):
dp[i][j] = min(dp[i][j-1], dp[i-1][j])+1
ratio = dp[-1][-1]/drop_path
dp_matrix = dp/ratio
return dp_matrix
实验
脚本
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
# 修改为自己的配置文件地址
model = YOLO('/root/ultralytics-main/ultralytics/cfg/models/11/yolov11-RevCol.yaml')
# 修改为自己的数据集地址
model.train(data='/root/ultralytics-main/ultralytics/cfg/datasets/coco8.yaml',
cache=False,
imgsz=640,
epochs=10,
single_cls=False, # 是否是单类别检测
batch=8,
close_mosaic=10,
workers=0,
optimizer='SGD',
amp=True,
project='runs/train',
name='RevCol',
)