一、论文信息
- 论文题目:Reversible Column Networks (RevCol)
- 中文题目:可逆列网络(RevCol)
- 论文链接:点击跳转
- 代码链接:点击跳转
- 作者:Yuxuan Cai, Yizhuang Zhou, Qi Han, Jianjian Sun, Xiangwen Kong, Jun Li, Xiangyu Zhang(蔡宇轩、周义庄、韩琦、孙健健、孔祥文、李军、张祥雨)
- 单位: MEGVII Technology(旷视科技), Beijing Academy of Artificial Intelligence(北京智源研究院)
- 核心速览:提出一种可逆的多列神经网络结构,实现特征解耦与无损信息传播,在分类、检测、分割任务上达到SOTA。
二、论文概要
该论文提出了一种新的神经网络设计范式——可逆列网络(RevCol)。RevCol 由多个子网络(列)组成,每个列之间通过多级可逆连接进行联系。这种设计使得网络在前向传播过程中逐渐解开特征,使得所有的信息得以保持,而不是像传统网络那样被压缩或丢弃。该论文展示了RevCol在多个计算机视觉任务上的优秀性能,包括图像分类、物体检测和语义分割,特别是在大参数预算和大数据集下,RevCol模型的表现非常有竞争力。该方法还可以扩展到transformer等其他网络中,提升了多种计算机视觉和NLP任务的表现。
三、实验动机
传统单列网络在预训练(如ImageNet)时往往过度强调高层语义特征,而丢失低层细节信息,不利于下游任务(如检测、分割)。
可逆网络(如RevNet)虽能节省内存,但对特征维度有严格限制,且无法实现多尺度特征解耦。
受GLOM启发,希望设计一种既能保持信息无损、又能实现特征解耦的可扩展网络结构。
四、创新之处
可逆多列结构:提出一种广义的可逆变换公式,支持多尺度特征的无损传播。
特征解耦机制:不同列负责不同抽象层次的特征,最后一列输出解耦后的多级特征。
中间监督:引入重建损失和分类损失的中间监督,防止信息丢失,提升训练稳定性。
内存高效:由于可逆性,训练时仅需存储一列的激活值,内存占用为O(1)。
扩展性强:列数成为新的扩展维度,可与深度、宽度并列。
五、实验分析
RevCol在多个计算机视觉任务中表现优异,特别是在图像分类(ImageNet)、物体检测(COCO)和语义分割(ADE20K)任务上。实验结果表明,RevCol在大规模数据集和大模型训练中具有良好的扩展性。例如,RevCol-H模型在ImageNet-1K上达到90.0%的准确率,超越了许多先进的CNN和Transformer模型。
六、核心代码
原代码
class RevCol(nn.Module):
def __init__(self, kernel='C2f', channels=[32, 64, 96, 128], layers=[2, 3, 6, 3], num_subnet=5, save_memory=True) -> None:
super().__init__()
self.num_subnet = num_subnet
self.channels = channels
self.layers = layers
self.stem = Conv(3, channels[0], k=4, s=4, p=0)
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, first_col, save_memory=save_memory))
self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
def forward(self, x):
c0, c1, c2, c3 = 0, 0, 0, 0
x = self.stem(x)
for i in range(self.num_subnet):
c0, c1, c2, c3 = getattr(self, f'subnet{str(i)}')(x, c0, c1, c2, c3)
return [c0, c1, c2, c3]
注释版本
import torch
import torch.nn as nn
class RevCol(nn.Module):
def __init__(self, kernel='C2f', channels=[32, 64, 96, 128], layers=[2, 3, 6, 3], num_subnet=5, save_memory=True) -> None:
"""
Reversible Column Networks (RevCol) 主类
参数:
kernel (str): 使用的卷积核类型,默认为'C2f'
channels (list): 每层输出的通道数,默认为[32, 64, 96, 128]
layers (list): 每层的块数,默认为[2, 3, 6, 3]
num_subnet (int): 子网络(列)的数量,默认为5
save_memory (bool): 是否启用内存节省模式,默认为True
"""
super().__init__()
self.num_subnet = num_subnet # 子网络数量
self.channels = channels # 各层通道数配置
self.layers = layers # 各层块数配置
# 输入 stem: 将输入图像转换为特征图
# 使用4x4卷积,步长为4,无填充,实现16倍下采样
self.stem = Conv(3, channels[0], k=4, s=4, p=0)
# 创建多个子网络(列)
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, first_col, save_memory=save_memory))
# 前向传播一次以获取各层输出的通道数
# 这通常在模型初始化时用于确定后续层的输入尺寸
self.channel = [i.size(1) for i in self.forward(torch.randn(1, 3, 640, 640))]
def forward(self, x):
"""
前向传播函数
参数:
x (Tensor): 输入图像张量,形状为(B, 3, H, W)
返回:
list: 包含四个不同尺度特征图的列表 [c0, c1, c2, c3]
"""
# 初始化各层特征图为0(对于第一个子网络,这些值不会被使用)
c0, c1, c2, c3 = 0, 0, 0, 0
# 通过stem卷积处理输入图像
x = self.stem(x)
# 依次通过所有子网络
for i in range(self.num_subnet):
# 获取当前子网络并前向传播
# 每个子网络接收输入x和之前层的特征,输出更新后的各层特征
c0, c1, c2, c3 = getattr(self, f'subnet{str(i)}')(x, c0, c1, c2, c3)
# 返回最后一个子网络输出的多尺度特征
return [c0, c1, c2, c3]
七、实验总结
- RevCol通过多列可逆结构,在不丢失信息的情况下逐步解开特征,提升了模型在多个计算机视觉任务中的表现,尤其是在大规模数据集上的预训练表现。
- 此外,RevCol还具有良好的内存优化特性,能够支持大规模模型的训练。