旅游类网站建设教案淘宝引流推广平台
-
🍨 本文为🔗365天深度学习训练营 中的学习记录博客
-
🍦 参考文章地址: 365天深度学习训练营-第J2周:ResNet-50V2算法实战与解析
-
🍖 作者:K同学啊
一、ResNetV2与ResNet结构对比
改进点
(a)original 表示原始的 ResNet 的残差结构,(b)proposed 表示新的 ResNet 的残差结构。主要差别就是(a)结构先卷积后进行 BN 和激活函数计算,最后执行 addition 后再进行ReLU 计算; (b)结构先进行 BN 和激活函数计算后卷积,把 addition 后的 ReLU 计算放到了残差结构内部。
改进结果
作者使用这两种不同的结构在 CIFAR-10 数据集上做测试,模型用的是 1001层的 ResNet 模型。从图中结果我们可以看出,(b)proposed 的测试集错误率明显更低一些,达到了 4.92%的错误率,(a)original 的测试集错误率是 7.61%
二、模型实现
2.1 残差结构
''' Residual Block '''
class Block2(nn.Module):def __init__(self, in_channel, filters, kernel_size=3, stride=1, conv_shortcut=False):super(Block2, self).__init__()self.preact = nn.Sequential(nn.BatchNorm2d(in_channel),nn.ReLU(True))self.shortcut = conv_shortcutif self.shortcut:self.short = nn.Conv2d(in_channel, 4*filters, 1, stride=stride, padding=0, bias=False)elif stride>1:self.short = nn.MaxPool2d(kernel_size=1, stride=stride, padding=0)else:self.short = nn.Identity()self.conv1 = nn.Sequential(nn.Conv2d(in_channel, filters, 1, stride=1, bias=False),nn.BatchNorm2d(filters),nn.ReLU(True))self.conv2 = nn.Sequential(nn.Conv2d(filters, filters, kernel_size, stride=stride, padding=1, bias=False),nn.BatchNorm2d(filters),nn.ReLU(True))self.conv3 = nn.Conv2d(filters, 4*filters, 1, stride=1, bias=False)def forward(self, x):x1 = self.preact(x)if self.shortcut:x2 = self.short(x1)else:x2 = self.short(x)x1 = self.conv1(x1)x1 = self.conv2(x1)x1 = self.conv3(x1)x = x1 + x2return x
2.2 模块构建
class Stack2(nn.Module):def __init__(self, in_channel, filters, blocks, stride=2):super(Stack2, self).__init__()self.conv = nn.Sequential()self.conv.add_module(str(0), Block2(in_channel, filters, conv_shortcut=True))for i in range(1, blocks-1):self.conv.add_module(str(i), Block2(4*filters, filters))self.conv.add_module(str(blocks-1), Block2(4*filters, filters, stride=stride))def forward(self, x):x = self.conv(x)return x
2.3 网络构建
''' 构建ResNet50V2 '''
class ResNet50V2(nn.Module):def __init__(self,include_top=True, # 是否包含位于网络顶部的全链接层preact=True, # 是否使用预激活use_bias=True, # 是否对卷积层使用偏置input_shape=[224, 224, 3],classes=1000,pooling=None): # 用于分类图像的可选类数super(ResNet50V2, self).__init__()self.conv1 = nn.Sequential()self.conv1.add_module('conv', nn.Conv2d(3, 64, 7, stride=2, padding=3, bias=use_bias, padding_mode='zeros'))if not preact:self.conv1.add_module('bn', nn.BatchNorm2d(64))self.conv1.add_module('relu', nn.ReLU())self.conv1.add_module('max_pool', nn.MaxPool2d(kernel_size=3, stride=2, padding=1))self.conv2 = Stack2(64, 64, 3)self.conv3 = Stack2(256, 128, 4)self.conv4 = Stack2(512, 256, 6)self.conv5 = Stack2(1024, 512, 3, stride=1)self.post = nn.Sequential()if preact:self.post.add_module('bn', nn.BatchNorm2d(2048))self.post.add_module('relu', nn.ReLU())if include_top:self.post.add_module('avg_pool', nn.AdaptiveAvgPool2d((1, 1)))self.post.add_module('flatten', nn.Flatten())self.post.add_module('fc', nn.Linear(2048, classes))else:if pooling=='avg':self.post.add_module('avg_pool', nn.AdaptiveAvgPool2d((1, 1)))elif pooling=='max':self.post.add_module('max_pool', nn.AdaptiveMaxPool2d((1, 1)))def forward(self, x):x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)x = self.conv4(x)x = self.conv5(x)x = self.post(x)return x
三、鸟类数据集效果
数据集可视化:
后三个epoch:
Epoch:18, Train_acc:92.9%, Train_loss:0.210, Test_acc:84.1%,Test_loss:0.538 Epoch:19, Train_acc:94.9%, Train_loss:0.160, Test_acc:89.4%,Test_loss:0.484 Epoch:20, Train_acc:92.7%, Train_loss:0.270, Test_acc:82.3%,Test_loss:0.700 Done best_acc: 0.9491150442477876
Loss与Accuracy图:
指定图片预测: