conv+bn+relu组合详解代码示例

卷积神经网络(Convolutional Neural Network,CNN)是深度学习中最常用的一种网络模型,常常用于图像和视频分类任务。在CNN中,卷积层(convolutional layer)是最重要的一个模块,而在卷积层的基础上,通常还会加入批量归一化层(batch normalization layer)和激活层(activation layer)。这三层组合在一起,可以有效地提高模型的性能和训练速度。

conv层

卷积层是CNN中最基本的层之一,主要用于提取图像中的特征。卷积层的输入是一个三维张量,通常表示为(样本数,通道数,高度,宽度)。卷积层的核(kernel)也是一个三维张量,通常表示为(输出通道数,输入通道数,卷积核高度,卷积核宽度)。对于每一个输出通道,卷积层都会使用一个相同的卷积核,该卷积核对输入张量进行卷积操作,生成一个输出张量。卷积层的输出形状取决于卷积核大小、步幅(stride)和填充(padding)等超参数的设置。

以下是一个卷积层的代码示例,该卷积层使用3x3大小的卷积核,步幅为1,填充为1,输入通道数为3,输出通道数为16:

import torch.nn as nn

conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

bn层

批量归一化层是一种用于神经网络中的归一化方法,旨在加速训练过程和提高模型的性能。BN层的输入是一个四维张量,通常表示为(样本数,通道数,高度,宽度)。BN层的输出也是一个四维张量,形状与输入相同。BN层通过对输入张量的每个通道进行归一化操作,抑制了训练过程中的内部协变量偏移问题,从而加速了模型的训练。

以下是一个批量归一化层的代码示例:

bn = nn.BatchNorm2d(num_features=16)

relu层

ReLU激活函数是一种常用的非线性激活函数,可以增强模型的非线性表达能力。ReLU层的输入和输出形状与卷积层和BN层相同。

以下是一个ReLU层的代码示例:

relu = nn.ReLU()

conv+bn+relu组合

将卷积层、BN层和ReLU层组合在一起,可以形成一种常见的网络结构。以下是一个conv+bn+relu组合的代码示例:

import torch.nn as nn

conv_bn_relu = nn.Sequential(
    nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1),
    nn.BatchNorm2d(num_features=16),
    nn.ReLU()
)

上述代码将卷积层、BN层和ReLU层依次组合在一起,形成了一个三层的卷积神经网络模型,该模型输入为一个(样本数,3,高度,宽度)的四维张量,输出为一个(样本数,16,高度,宽度)的四维张量。

解释每一句class RepVggBlock(nn.Layer): def init(self, ch_in, ch_out, act='relu', alpha=False): super(RepVggBlock, self).init() self.ch_in = ch_in self.ch_out = ch_out self.conv1 = ConvBNLayer( ch_in, ch_out, 3, stride=1, padding=1, act=None) self.conv2 = ConvBNLayer( ch_in, ch_out, 1, stride=1, padding=0, act=None) self.act = get_act_fn(act) if act is None or isinstance(act, ( str, dict)) else act if alpha: self.alpha = self.create_parameter( shape=[1], attr=ParamAttr(initializer=Constant(value=1.)), dtype="float32") else: self.alpha = None def forward(self, x): if hasattr(self, 'conv'): y = self.conv(x) else: if self.alpha: y = self.conv1(x) + self.alpha * self.conv2(x) else: y = self.conv1(x) + self.conv2(x) y = self.act(y) return y def convert_to_deploy(self): if not hasattr(self, 'conv'): self.conv = nn.Conv2D( in_channels=self.ch_in, out_channels=self.ch_out, kernel_size=3, stride=1, padding=1, groups=1) kernel, bias = self.get_equivalent_kernel_bias() self.conv.weight.set_value(kernel) self.conv.bias.set_value(bias) self.delattr('conv1') self.delattr('conv2') def get_equivalent_kernel_bias(self): kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1) kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2) if self.alpha: return kernel3x3 + self.alpha * self._pad_1x1_to_3x3_tensor( kernel1x1), bias3x3 + self.alpha * bias1x1 else: return kernel3x3 + self._pad_1x1_to_3x3_tensor( kernel1x1), bias3x3 + bias1x1 def _pad_1x1_to_3x3_tensor(self, kernel1x1): if kernel1x1 is None: return 0 else: return nn.functional.pad(kernel1x1, [1, 1, 1, 1]) def _fuse_bn_tensor(self, branch): if branch is None: return 0, 0 kernel = branch.conv.weight running_mean = branch.bn._mean running_var = branch.bn._variance gamma = branch.bn.weight beta = branch.bn.bias eps = branch.bn._epsilon std = (running_var + eps).sqrt() t = (gamma / std).reshape((-1, 1, 1, 1)) return kernel * t, beta - running_mean * gamma / std
05-15
这段代码定义了一个名为 RepVggBlock 的类,它继承自 nn.Layer 类。这个类用于实现 RepVGG 网络中的基本块。RepVGG 是一种轻量级的卷积神经网络,它的主要思想是将常规的卷积操作替换为由卷积和 Batch Normalization(BN)操作组成的基本块,从而在不损失精度的情况下减少网络参数的数量。 在这个类中,__init__ 方法定义了类的初始化函数,它接受三个参数:ch_in、ch_out 和 act。其中,ch_in 和 ch_out 分别表示输入通道数和输出通道数,act 表示激活函数的类型。在初始化函数中,首先调用父类的初始化函数 super(RepVggBlock, self).__init__() 来初始化父类的属性。然后,将输入和输出通道数保存到 self.ch_in 和 self.ch_out 中。接着,使用 ConvBNLayer 类创建两个卷积层:self.conv1 和 self.conv2。这两个卷积层分别使用 3x3 和 1x1 的卷积核进行卷积操作,并且没有使用激活函数。最后,根据输入的激活函数类型,使用 get_act_fn 函数获取激活函数,并保存到 self.act 中。如果激活函数为 None 或者是字符串或字典类型,则 self.act 直接保存激活函数类型,否则就保存激活函数的实例。 接着,forward 方法定义了类的前向传播函数。它接受一个输入张量 x,根据是否已经初始化了 self.conv 属性来判断使用哪个卷积操作。如果已经初始化了 self.conv 属性,则使用 self.conv 对输入进行卷积操作;否则,分别对输入使用 self.conv1 和 self.conv2 进行卷积操作,并将它们相加。如果类的 alpha 属性存在,则使用 alpha 值对 self.conv2 的输出进行缩放,然后再将两个卷积层的输出相加。最后,对输出进行激活函数处理,并返回输出。 convert_to_deploy 方法用于将训练好的模型转换为部署模型。它首先检查类中是否已经初始化了 self.conv 属性,如果没有,则创建一个新的 Conv2D 层,并将其权重和偏置设置为等效的卷积和 BN 层的权重和偏置。然后,删除 self.conv1 和 self.conv2 属性。 get_equivalent_kernel_bias 方法用于计算等效的卷积和 BN 层的权重和偏置。它首先将 self.conv1 和 self.conv2 层的权重和偏置分别融合到 kernel3x3 和 bias3x3 变量中,并使用 _pad_1x1_to_3x3_tensor 函数将 kernel1x1 变量的尺寸从 1x1 扩展到 3x3。如果类的 alpha 属性存在,则将 kernel1x1 加权缩放后再加到 kernel3x3 中。最后,将偏置项也进行融合,并返回等效的权重和偏置。 _pad_1x1_to_3x3_tensor 方法用于将 1x1 的卷积核扩展到 3x3。 _fuse_bn_tensor 方法用于将卷积和 BN 层进行融合并返回等效的权重和偏置。它首先获取卷积层的权重、BN 层的运行均值、方差、缩放因子和偏置项。然后,根据 BN 层的参数计算标准差,并将缩放因子 reshape 成与权重相同的形状。最后,根据融合公式计算等效的权重和偏置,并返回。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值