【2020暑假学习】第三次作业:卷积神经网络 part2

久未见 提交于 2020-08-10 09:25:49

问题总结

  • 当模型准确率已经较高时,如何判断自己的改动是否提升了性能。因为可能每一次准确率变化都不太大,而且每次训练的模型最后准确率也会有波动,多运行几次取准确率平均值做比较吗?
  • 在想要提高性能的改进过程中,有很多改变可能都对性能的提升有些许的帮助。这个过程是一种一种方法的尝试,不断累积提升了性能的改变吗。比如先改了batch_size,找到了一个合适的大小,然后就固定使用这个大小,再调整优化器损失函数之类的?在调整的时候总有一种虽然当前的尝试没有提高性能,但说不定和别的组合在一起可能会变好的想法,简直要进行排列组合。

代码练习

MobileNet V1

  • 如何判断nn.Conv2d(3, 3)是做的图一运算而不是图二?

    通过Conv2d函数中的groups参数区别。groups取值范围为1 - in_channels。groups=1时做图二运算,groups=3时做图一运算。

    若groups=x,则将输入通道分为x份,输出通道分为x份,对应每份分别做全卷积。

    举例:nn.Conv2d(in_channels=6, out_channels=6, kernel_size=1, groups=3)

    卷积核大小为torch.Size([6, 2, 1, 1])

参考:卷积层中的 group 参数理解

pytorch的conv2d函数groups分组卷积使用及理解

MobileNet V2

  • “MobileNet V1 的主要问题: Depthwise Conv确实是大大降低了计算量,但实际中,发现不少训练出来的kernel是空的。”

    因为Depthwise每个kernel dim 相对于vanilla conv要小得多, 过小的kernel dim, 加上ReLU的激活影响下, 使得神经元输出很容易变为0, 所以就学废了。ReLU对于0的输出的梯度为0, 所以一旦陷入了0输出, 就没法恢复了。

HybridSN

class HybridSN(nn.Module):
    def __init__(self):
        super(HybridSN, self).__init__()
        self.conv1 = nn.Conv3d(1, 8, (7, 3, 3), stride=1, padding=0)
        self.conv2 = nn.Conv3d(8, 16, (5, 3, 3), stride=1, padding=0)
        self.conv3 = nn.Conv3d(16, 32, (3, 3, 3), stride=1, padding=0)
        self.conv4 = nn.Conv2d(576, 64, kernel_size=3, stride=1, padding=0)
        self.bn1 = nn.BatchNorm2d(64)
        self.fc1 = nn.Linear(18496, 256)
        self.dropout1 = nn.Dropout(p=0.4)
        self.fc2 = nn.Linear(256, 128)
        self.dropout2 = nn.Dropout(p=0.4)
        self.fc3 = nn.Linear(128, class_num)

    def forward(self, x):
        out = self.conv1(x)
        out = self.conv2(out)
        out = self.conv3(out)
        #print(batch)
        out = out.reshape(batch, 576, 19, 19)
        out = self.conv4(out)
        out = self.bn1(out)
        out = F.relu(out)
        out = out.view(-1, 64 * 17 * 17)
        out = self.fc1(out)
        out = F.relu(out)
        out = self.dropout1(out)
        out = self.fc2(out)
        out = F.relu(out)
        out = self.dropout2(out)
        out = self.fc3(out)
        return out
  • 每次分类的结果都不一样

    在model(test)之前,需要加上model.eval(),其作用是为了固定BN和dropout层,使得偏置参数不随着发生变化。否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有batch normalization层所带来的的性质。

    BN的作用主要是对网络中间的每层进行归一化处理,并且使用变换重构Batch Normalization Transform保证每层提取的特征分布不会被破坏。

    训练时是针对每个mini-batch的,但是测试是针对单张图片的,即不存在batch的概念。在做one classification的时候,训练集和测试集的样本分布是不一样的。

    Dropout在train时随机选择神经元而predict要使用全部神经元并且要乘一个补偿系数。

    BN在train时每个batch做了不同的归一化因此也对应了不同的参数,相应predict时实际用的参数是每个batch下参数的移动平均。

    加上model.eval()后准确率不再变化,但第一次测试分类准确率会变,因为model.eval()固定了dropout层,使用全部神经元而不是随机选择,所以准确率会发生一次变化。

  • 进一步提升高光谱图像的分类性能

    • HybridSN准确率 95.28% 98.05% 97.75%

    • 二维卷积层改为深度可分离卷积 98.76% 98.59% 98.71%

    • 转为二维+三维 98.07% 98.48% 98.30%

    #二维卷积层改为深度可分离卷积
    class HybridSN(nn.Module):
        def __init__(self):
            super(HybridSN, self).__init__()
            self.conv1 = nn.Conv3d(1, 8, (7, 3, 3), stride=1, padding=0)
            self.conv2 = nn.Conv3d(8, 16, (5, 3, 3), stride=1, padding=0)
            self.conv3 = nn.Conv3d(16, 32, (3, 3, 3), stride=1, padding=0)
    
            # Depthwise 卷积,3*3 的卷积核,分为 in_planes,即各层单独进行卷积
            self.conv4 = nn.Conv2d(576, 576, kernel_size=3, stride=1, padding=0, groups=576, bias=False)
            self.bn1 = nn.BatchNorm2d(576)
            # Pointwise 卷积,1*1 的卷积核
            self.conv5 = nn.Conv2d(576, 64, kernel_size=1, stride=1, padding=0, bias=False)
            self.bn2 = nn.BatchNorm2d(64)
    
            self.fc1 = nn.Linear(18496, 256)
            self.dropout1 = nn.Dropout(p=0.4)
            self.fc2 = nn.Linear(256, 128)
            self.dropout2 = nn.Dropout(p=0.4)
            self.fc3 = nn.Linear(128, class_num)
    
        def forward(self, x):
            out = F.relu(self.conv1(x))
            out = F.relu(self.conv2(out))
            out = F.relu(self.conv3(out))
            out = out.reshape(batch, 576, 19, 19)
            
            out = F.relu(self.bn1(self.conv4(out)))
            out = F.relu(self.bn2(self.conv5(out)))
            
            out = out.view(-1, 64 * 17 * 17)
            out = self.fc1(out)
            out = F.relu(out)
            out = self.dropout1(out)
            out = self.fc2(out)
            out = F.relu(out)
            out = self.dropout2(out)
            out = self.fc3(out)
            return out
    
    #转为二维+三维
    class HybridSN(nn.Module):
        def __init__(self):
            super(HybridSN, self).__init__()
            self.conv4 = nn.Conv2d(30, 64, kernel_size=3, stride=1, padding=0)
            self.bn1 = nn.BatchNorm2d(64)
            self.conv1 = nn.Conv3d(1, 8, (7, 3, 3), stride=1, padding=0)
            self.conv2 = nn.Conv3d(8, 16, (5, 3, 3), stride=1, padding=0)
            self.conv3 = nn.Conv3d(16, 32, (3, 3, 3), stride=1, padding=0)
            self.fc1 = nn.Linear(480896, 256)
            self.dropout1 = nn.Dropout(p=0.4)
            self.fc2 = nn.Linear(256, 128)
            self.dropout2 = nn.Dropout(p=0.4)
            self.fc3 = nn.Linear(128, class_num)
    
        def forward(self, x):
            out = x.reshape(batch, 30, 25, 25)
            out = self.conv4(out)
            out = self.bn1(out)
            out = F.relu(out)
            
            out = out.reshape(batch, 1, 64, 23, 23)
            out = F.relu(self.conv1(out))
            out = F.relu(self.conv2(out))
            out = F.relu(self.conv3(out))
            
            out = out.view(-1, 32 * 52 * 17 * 17)
            out = self.fc1(out)
            out = F.relu(out)
            out = self.dropout1(out)
            out = self.fc2(out)
            out = F.relu(out)
            out = self.dropout2(out)
            out = self.fc3(out)
            return out
    

论文笔记

DnCNN

第一次用深度学习来做图像去噪。

残差学习:拟合H(x),由于网络退化问题难以训练出来,转为训练F(x),F(x)=H(x)-x,F(x)称为残差,然后H(x)=F(x)+x。

根据ResNet中的理论,当残差为0时,堆积层之间等价于恒等映射,而恒等映射是非常容易训练优化的。作者注意到在图像复原领域(尤其是在噪音程度较小的情况下),噪音图片与纯净图片的残差非常小,所以理论上残差学习非常适合运用到图像复原上。

DnCNN是将网络的输出直接改成residual image(残差图片),设纯净图片为x,带噪音图片为y,假设y=x+v,则v是残差图片。即DnCNN的优化目标不是真实图片与网络输出之间的MSE(均方误差),而是真实残差图片与网络输出之间的MSE。

SENet

解决了什么问题:注意力机制

对各个特征图赋予权重,不再是简单的相加,而是加权求和。强调重要的部分,忽略不重要的部分。

还可以用于哪些地方:可以把C抬平,强调在不同位置上的重要性。

SE模块首先对卷积得到的特征图进行Squeeze操作,采用global average pooling来实现,然后对全局特征进行Excitation操作,学习各个channel间的关系,得到不同channel的权重,最后乘以原来的特征图得到最终特征。

深度监督跨模态检索(DSCMR)

跨模态检索是指在不同模态数据之间的检索,比如通过一张图片检索与之相关的文本、音视频等数据,或者通过一段文本检索与之相关的图片等数据。

解决跨模态检索的主要方法有两种,一种是学习不同模态数据的实值表示,通过距离度量(如余弦距离、欧氏距离等)进行相关度排序的方法;另一种是学习不同模态数据的二值哈希码,通过度量汉明距离进行相关度排序的方法,这种方法又称为跨模态哈希,由于汉明距离计算的高效性,跨模态哈希在大规模跨模态检索中运用十分广泛,而利用深度学习进行的跨模态哈希,即为深度跨模态哈希。

  • 如何度量不同类型数据之间的内容相似性。

    深度监督跨模态检索(DSCMR):目的是找到一个共同的表示空间,在这个空间中可以直接比较来自不同模式的样本。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!