【ICLR 2023】可逆列网络(RevCol)
文章目录
- 一、论文信息
- 二、论文概要
- 三、实验动机
- 四、创新之处
- 五、实验分析
- 六、核心代码
- 原代码
- 注释版本
- 七、实验总结
一、论文信息
- 论文题目: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_subnetself.channels = channelsself.layers = layersself.stem = Conv(3, channels[0], k=4, s=4, p=0)for i in range(num_subnet):first_col = True if i == 0 else Falseself.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, 0x = 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 nnclass 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): 子网络(列)的数量,默认为5save_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 Falseself.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还具有良好的内存优化特性,能够支持大规模模型的训练。