首页 > 编程知识 正文

深度残差网络提出者(python残差神经网络)

时间:2023-05-05 04:06:03 阅读:1068 作者:3385

ResNet是什么?这个项目向你介绍残余网络ResNet。

ResNet是一个残差网络,所以我们可以先简单看一下ResNet的结构,然后再详细介绍它的结构。

从图中可以看出,残差网络是由多个结构相似的块堆叠而成的,这样的块是残差网络的基本单元(称为残差块),ResNet是由多个这样的残差块堆叠而成的。剩余块长度如下:

然后可能会有小伙伴的疑问。为什么一定要用残块来建这么深的网络?为什么不直接把网络和卷积层叠加起来呢?

00-1010我们知道,网络越深,我们能获得的信息就越多,功能也就越丰富。但是根据实验,随着网络的深入,优化效果变差,测试数据和训练数据的准确性下降。这是因为网络的加深会造成梯度爆炸和梯度消失的问题。

网络深化时的测试错误率和训练错误率表明,目前有一种解决这种现象的方法:将输入数据和中间层的数据归一化。该方法可以保证网络在反向传播时采用随机梯度下降(SGD),使网络收敛。然而,这种方法只对几十层网络有用。当网络越深入,这种方法就没用了。

为了在更深层次的网络中训练出更好的效果,wxdxz提出了一种新的网络结构——ResNet。这种网络结构的思想主要来自VLAD(剩余的思想来源)和公路网(跳跃连接的思想来源)。

00-1010再次播放ResNet结构图。要知道我们要介绍的核心就是这张图!(resnet块有两种,一种是两层结构,一种是三层结构)两种resnet块(代码给出了两种剩余块供选择)。我们要求解的映射是:H(x)。现在我们把这个问题转化为求解网络的剩余映射函数,即F(x)=h (x)-x。

残差:观察值和输入值之间的差值。这里,H(x)是观察值,x是输入值(即先前ResNet输出的特征映射)。我们一般称之为X恒等式函数,是一种跳跃连接;F(x)称为残差映射ResNet函数。

那么我们要解决的问题就变成了h (x)=f (x) x。

有些朋友可能会疑惑,为什么我们在解H(x)之前一定要经过F(x)?X的跳转连接有什么好处?因为如果采用一般的卷积神经网络,我们最初要求的是H(x)=F(x)的值,对吗?ResNet相当于改变学习目标,而不是学习一个完整的输出H(x),它只是输出和输入H(x)-x的差值,也就是残差。学一个小波动F(x)不是比学一个整x容易吗?X-jump连接不仅为网络学习奠定了基础,而且在发生梯度反向传播时可以更直接地传输到上一层。该块的剩余残差块通过跳转连接快捷连接实现,该块的输入输出通过快捷方式逐点元素叠加。这种简单的加法不会给网络增加额外的参数和计算量,但同时可以大大提高训练速度,提高模型的训练效果,这种简单的结构可以很好地解决模型层数加深时的退化问题。注:如果残差映射(F(x))的结果的维数与跳转连接(x)的结果的维数不同,那么我们就不能把它们相加。我们必须在X上做冷钻石运算,这样它们只有在尺寸相同时才能计算出来。冷钻有两种方法:1。用0填充;2.采用1*1的卷积。一般采用1*1卷积。

#以下是代码:

#导入库

导入火炬

将torch.nn导入为nn

导入torch.nn .功能为F

来自torch.autograd导入变量

#定义剩余块(基本块是小剩余块,瓶颈是大剩余块)

Classblock (nn。模块): #定义块

膨胀=1

def __init__(self,in _ channels,channel,stride=1,下采样=

None):#输入通道,输出通道,stride,下采样 super(BasicBlock, self).__init__() self.conv1 = conv3x3(in_channels, channels, stride) self.bn1 = nn.BatchNorm2d(channels) self.relu = F.relu(inplace=True) self.conv2 = conv3x3(channels, channels) self.bn2 = nn.BatchNorm2d(channels) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: residual = self.downsample(x) out += residual out = self.relu(out) return out#block输出 class Bottleneck(nn.Module): expansion = 4 def __init__(self, in_planes, planes, stride=1): super(Bottleneck, self).__init__() self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(self.expansion*planes) self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion*planes: self.shortcut = nn.Sequential( nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(self.expansion*planes) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = F.relu(self.bn2(self.conv2(out))) out = self.bn3(self.conv3(out)) out += self.shortcut(x) out = F.relu(out) return out #定义残差网络 class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=9,embedding_size=256): super(ResNet, self).__init__() self.in_planes = 64 self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) self.avg_pool = nn.AdaptiveAvgPool2d([4, 1]) self.fc=nn.Linear(512*4, embedding_size) self.linear = nn.Linear(embedding_size, num_classes) def _make_layer(self, block, planes, num_blocks, stride): strides = [stride] + [1]*(num_blocks-1) layers = [] for stride in strides: layers.append(block(self.in_planes, planes, stride)) self.in_planes = planes * block.expansion return nn.Sequential(*layers) def forward(self, x): x = torch.tensor(x, dtype=torch.float32) out = F.relu(self.bn1(self.conv1(x))) out = self.layer1(out) out = self.layer2(out) out = self.layer3(out) out = self.layer4(out) out =self.avg_pool(out) out = out.view(out.size(0), -1) embedding=self.fc(out) out = self.linear(embedding) return out,embedding #从18层的到101层的,可以根据自己需要选择网络大小,大的网络选用了大的残差块, #第一个参数指明用哪个残差块,第二个参数是一个列表,指明残差块的数量。 def ResNet18(): return ResNet(BasicBlock, [2,2,2,2]) def ResNet34(): return ResNet(BasicBlock, [3,4,6,3]) def ResNet50(): return ResNet(Bottleneck, [3,4,6,3]) def ResNet101(): return ResNet(Bottleneck, [3,4,23,3]) def ResNet152(): return ResNet(Bottleneck, [3,8,36,3])

总结:在使用了ResNet的结构后,可以发现层数不断加深导致的训练集上误差增大的现象被消除了,ResNet网络的训练误差会随着层数增加而逐渐减少,并且在测试集上的表现也会变好。原因在于,Resnet学习的是残差函数F(x) = H(x) - x, 这里如果F(x) = 0, 那么就是上面提到的恒等映射。事实上,resnet是“shortcut connections”的,在connections是在恒等映射下的特殊情况,学到的残差为0时,它没有引入额外的参数和计算复杂度,且不会降低精度。 在优化目标函数是逼近一个恒等映射 identity mapping, 而学习的残差不为0时, 那么学习找到对恒等映射的扰动会比重新学习一个映射函数要更容易。参考论文: Deep Residual Learning for Image Recognition

残差网络有两个版本,ResNet_v1和ResNet_v2,这两者有何区别,为啥大多用的是ResNet_v2,它有什么优良的性质呢,下一篇残差网络深度解析为您解答。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。