23暑假深度学习 week2-卷积神经网络

一、minist分类

 

mnist是黑白手写数字数据集,定义了两种网络,只有全连接的网络和有卷积层的网络。

class FC2Layer(nn.Module):
    def __init__(self, input_size, n_hidden, output_size):
        # nn.Module子类的函数必须在构造函数中执行父类的构造函数
        # 下式等价于nn.Module.__init__(self)
        super(FC2Layer, self).__init__()
        self.input_size = input_size
        # 这里直接用 Sequential 就定义了网络,注意要和下面 CNN 的代码区分开
        self.network = nn.Sequential(
            nn.Linear(input_size, n_hidden),
            nn.ReLU(),
            nn.Linear(n_hidden, n_hidden),
            nn.ReLU(),
            nn.Linear(n_hidden, output_size),
            nn.LogSoftmax(dim=1)
        )
    def forward(self, x):
        x = x.view(-1, self.input_size)
        return self.network(x)



class CNN(nn.Module):
    def __init__(self, input_size, n_feature, output_size):
        # 执行父类的构造函数,所有的网络都要这么写
        super(CNN, self).__init__()
        # 下面是网络里典型结构的一些定义,一般就是卷积和全连接
        # 池化、ReLU一类的不用在这里定义
        self.n_feature = n_feature
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=n_feature, kernel_size=5)
        self.conv2 = nn.Conv2d(n_feature, n_feature, kernel_size=5)
        self.fc1 = nn.Linear(n_feature*4*4, 50)
        self.fc2 = nn.Linear(50, 10)

    # 下面的 forward 函数,定义了网络的结构,按照一定顺序,把上面构建的一些结构组织起来
    # 意思就是,conv1, conv2 等等的,可以多次重用
    def forward(self, x, verbose=False):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)
        x = x.view(-1, self.n_feature*4*4)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.log_softmax(x, dim=1)
        return x

CNN由两层卷积层和两层全连接层构成,使用ReLU激活函数,最大池化层将输出每个kernelsize*kernelsize大小内最大的元素,用于减小数据量、降低卷积对位置的敏感和提取特征。最后softmax输出每个类别的概率。

全连接网络和卷积网络训练后的结果如图,可见在训练数据上两者的损失都降到了较低的水平,但在测试集上CNN的准确度高了许多。

在将图片中的像素打乱后再训练,发现全连接网络的准确率几乎不变,而卷积网络的准确率大幅降低了,说明卷积操作确实会提取图像特征,对位置信息、像素关系等特征敏感。

二、CIFAR10 数据集分类

CIFAR10是一个有十类物体的彩色数据集,训练了两个卷积网络进行分类。结果如下。

网络1
VGG

 VGG在测试集上的准确率比网络1高的多,这些提升来自以下几点改进。

1.进行了不同的数据增强

网络1只进行了参数全为0.5的归一化,而VGG进行了随机裁剪、随机水平翻转和更符合数据集特征的归一化,这使训练数据更丰富可以提高模型的泛化性。

2.VGG网络更深更宽
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


class VGG(nn.Module):
    def __init__(self):
        super(VGG, self).__init__()
        self.cfg = [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M']
        self.features = self._make_layers(self.cfg)
        self.classifier = nn.Linear(512, 10)

    def forward(self, x):
        out = self.features(x)
        out = out.view(out.size(0), -1)
        out = self.classifier(out)
        return out

    def _make_layers(self, cfg):
        layers = []
        in_channels = 3
        for x in cfg:
            if x == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            else:
                layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
                           nn.BatchNorm2d(x),
                           nn.ReLU(inplace=True)]
                in_channels = x
        layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
        return nn.Sequential(*layers)

可见网络1只有2个卷积层且宽度最大只有16,而VGG有8个卷积层,且最大宽度达到了512,显然VGG更大的网络较适合CIFAR10分类任务。

3.VGG使用了批量归一化

VGG在网络中使用了批量归一化,使数据分布变平稳,可以加快训练速度使训练过程变平稳。

三、问题总结

1.dataloader 里面 shuffle 取不同值有什么区别?

shuffle表示是否要将数据打乱,一般在训练数据上要将数据打乱,为了增加数据的独立性,也有可能在数据集中相同标签的数据集中在某一区间,训练数据会更新权值,而一次更新中只有同一标签的数据不利于模型达到更好的效果,所以需要打乱。而测试数据不会更新权值所以不需要打乱。

2.transform 里,取了不同值,这个有什么区别?

transform里是对数据进行的处理,可以对训练数据进行不同的增强,如剪裁、旋转、缩放等,之后进行归一化,归一化中的参数是数据在三个通道上的均值和标准差。如对数据求出均值和标准差再进行归一化,那么处理后的数据分布会服从正态分布。如果简单全用0.5,则可将数据映射至【-1,1】,但不确定其分布。

3.epoch 和 batch 的区别?

所有数据都在网络上完成一次正向和反向传播为一个epoch,在这过程中每次都会取所有数据中batch大小的数据进行。

4.1x1的卷积和 FC 有什么区别?主要起什么作用?

1×1卷积主要用于通道融合,可以融合特征,输出规定通道数。全连接一般在模型的最后,用于将上层输出对应至类别。

5.residual leanring 为什么能够提升准确率?

首先残差结构相当于一个直连通道,将之前的特征跳跃的输入到之后的网络中,融合了不同尺度的特征,可以提升准确率。而且残差结构可以保持网络不变坏,如果一个卷积层没有对减小损失有贡献那么它就得不到梯度,最终的效果就是通过残差直接跳过这层,而不会使网络的性能变差。

7.代码练习二里,卷积以后feature map 尺寸会变小,如何应用 Residual Learning?

残差结构中使用1×1卷积来统一通道数,使用3×3等卷积来输出尺寸相同的特征图。

8.有什么方法可以进一步提升准确率?

可以进行数据增强,生成一些裁剪或拼接的图片。

可以使用dropout抑制过拟合,提高测试精度。

可以使用学习率调整策略,使模型收敛到一个更好点。

可以使用在大数据集上训练过的预训练模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值