【RepVGG网络】

13 篇文章 0 订阅
7 篇文章 0 订阅

RepVGG网络

RepVGG网络是2021年由清华大学、旷视科技与香港科技大学等机构的研究者提出的一种深度学习模型结构,其核心特点是通过“结构重参数化”(re-parameterization)技术,在训练阶段采用复杂的多分支结构以优化网络的训练过程,而在推理阶段则将这些分支融合成单一的卷积层,从而实现高效的前向推断。这一特性使得RepVGG在保证模型精度的同时显著提升了计算速度和内存效率。

RepVGG网络结构详解

  1. RepVGG Block:RepVGG模块通常包括一个3x3卷积层(带有ReLU激活函数),以及可选的1x1卷积层(用于通道变换和降维)和额外的3x3卷积层。在训练时,这些组件并行存在,形成一个多分支结构,类似于ResNet中的残差连接。但在推理时,通过特定的重参数化方法,这些分支会被合并为一个简单的3x3卷积层加上一个偏置项。
  2. 结构重参数化:该技术允许同一组参数在网络的不同阶段表现为不同的结构。具体到RepVGG中,训练时的多个卷积层会根据一定的线性关系被转换为单个卷积层,这样在不损失训练效果的前提下降低了推理时的复杂度。

PyTorch代码实现

虽然这里无法直接提供完整的代码实现,但可以描述其大致框架。在PyTorch中实现RepVGG时,通常会定义一个RepVGGBlock类,该类在构造函数中设置训练模式下的各个卷积层,并且包含一个fuse()方法,用于在模型部署或进行推理时将训练时的多分支结构融合为单个卷积层。

以下是一个简化的RepVGG Block示例代码:

import torch.nn as nn

class RepVGGBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, deploy=False):
        super(RepVGGBlock, self).__init__()
        self.deploy = deploy  # 标记是否处于部署/推理阶段

        # 训练阶段的多个卷积层
        if not self.deploy:
            self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=padding)
            self.bn1 = nn.BatchNorm2d(out_channels)
            self.relu = nn.ReLU(inplace=True)
            # 可能存在的附加卷积层
            self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=1, stride=1, padding=0)
            self.bn2 = nn.BatchNorm2d(out_channels)

        # 推理阶段的融合卷积层(初始化为空)
        self.fused_conv = None

    def forward(self, x):
        if not self.deploy:
            x = self.conv1(x)
            x = self.bn1(x)
            x = self.relu(x)
            x = self.conv2(x) if hasattr(self, 'conv2') else x
            x = self.bn2(x) if hasattr(self, 'bn2') else x
        else:
            assert self.fused_conv is not None, "需要先调用fuse()方法将训练结构融合为推理结构!"
            x = self.fused_conv(x)

        return x

    def fuse(self):
        if self.deploy:
            return
        # 在此处执行结构重参数化操作,将多个卷积和归一化层融合为单个卷积层
        fused_kernel = ...  # 根据训练分支计算融合后的卷积核权重
        fused_bias = ...  # 计算融合后的偏置项
        self.fused_conv = nn.Conv2d(self.conv1.in_channels, self.conv2.out_channels,
                                    kernel_size=self.conv1.kernel_size, stride=self.conv1.stride,
                                    padding=self.conv1.padding, bias=True)
        with torch.no_grad():
            self.fused_conv.weight.copy_(fused_kernel)
            self.fused_conv.bias.copy_(fused_bias)

        # 删除训练时使用的冗余层,以便在推理时仅使用融合后的卷积层
        delattr(self, 'conv1')
        delattr(self, 'bn1')
        delattr('relu', 'inplace')
        if hasattr(self, 'conv2'):
            delattr(self, 'conv2')
            delattr(self, 'bn2')

        self.deploy = True

要构建整个RepVGG模型,只需按照论文中的配置堆叠多个此类RepVGGBlock,并在模型部署之前调用每个块的fuse()方法来实现结构重参数化。具体的权重融合公式和细节可以在原论文《RepVGG: Making VGG-style ConvNets Great Again》中找到。

repvgg 二分类网络

RepVGG网络可以用于二分类任务,其主要流程与多分类任务相似,只是在最终输出层和损失函数的选择上有所不同。以下是一个简化的示例,说明如何使用PyTorch实现基于RepVGG的二分类模型:

# 假设已经实现了RepVGGBlock类
from repvgg_block import RepVGGBlock

class RepVGG(nn.Module):
    def __init__(self, num_blocks, in_channels, out_channels):
        super(RepVGG, self).__init__()
    
        # 定义RepVGG的多个块
        self.repvgg_layers = nn.Sequential(
            RepVGGBlock(in_channels, 64),
            *[RepVGGBlock(64, 64) for _ in range(num_blocks - 2)],
            RepVGGBlock(64, out_channels)
        )
    
        # 添加全局平均池化层和全连接层以适应二分类任务
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(out_channels, 2)  # 输出维度为2,对应两个类别

    def forward(self, x):
        x = self.repvgg_layers(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.fc(x)
        return x

接下来,构建二分类模型并训练:

import torch
import torch.optim as optim
from torch.nn import BCEWithLogitsLoss

# 初始化模型
model = RepVGG(num_blocks=4, in_channels=3, out_channels=512)

# 使用二元交叉熵损失函数
criterion = BCEWithLogitsLoss()

# 数据加载器假设已准备就绪
data_loader = ...

# 优化器设置
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 训练循环
num_epochs = 100
for epoch in range(num_epochs):
    for inputs, labels in data_loader:
        optimizer.zero_grad()
    
        # 前向传播
        outputs = model(inputs)
        # 将标签转换为二进制形式 (batch_size, 2),例如:[[0, 1], [1, 0], ...]
        binary_labels = labels.unsqueeze(1).float()
    
        # 计算损失
        loss = criterion(outputs, binary_labels)
    
        # 反向传播和优化
        loss.backward()
        optimizer.step()
  
    # 每个epoch后打印损失等信息
    print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}")

# 部署阶段融合模型结构
model.eval()
for module in model.modules():
    if isinstance(module, RepVGGBlock):
        module.fuse()

# 测试或预测时,模型将直接输出每类的概率值,可通过argmax获取预测类别
  • 在二分类任务中,通常选择Sigmoid激活函数配合二元交叉熵损失函数(BCEWithLogitsLoss),或者直接在最后一层使用带有Sigmoid激活函数的线性层;
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stsdddd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值