【深度学习】计算机视觉 更新中

import torch

模型选择

训练误差:在训练集上的误差(train_loss)

泛化误差:在测试集上的误差(test_loss)

验证集:一个用来评估模型好坏的数据集
例如拿出50%的训练数据
不要和训练集混在一起
一定程度上能反映出模型超参数的好坏

测试集:只用一次的数据集。例如
未来的考试
我出价的房子的实际成交价
kaggle私有排行榜的数据集

K-则交叉验证

算法:

  • 将数据分成K块
    For i 1,…, K
    使用第i块作为验证数据集,其余作为训练集
    报告K个验证集误差的平均

常用:K=5或10

过拟合、欠拟合

简单数据、复杂模型 -》 过拟合

复杂数据、简单模型 -》 欠拟合

模型容量:

  • 拟合各种函数的能力
  • 低容量的模型难以拟合训练数据
  • 高容量的模型可以记住所有的训练数据

估计模型容量

  • 难以在不同种类的算法之间比较
  • 给定一个模型种类,将有两个主要因素
    • 参数个数
    • 参数值的选择范围

数据复杂度

多个重要因素

  • 样本个数
  • 每个样本的元素个数
  • 时间、空间结构
  • 多样性

权重衰退 最常见的处理过拟合的方法 (weight Decay)

控制模型容量:

  • 减少模型参数
  • 使模型参数范围变小(权重衰退)

优化的是最小损失函数

  • 加入正则项 ||W||² < θ(硬性限制,用的不多)
  • 通常不限制bias(限制与否差距不大)
  • 小的θ意味着更强的正则项

常用的:使用《均方范数》作为柔性限制

在这里插入图片描述

超参数λ控制了正则项的重要程度

  • λ = 0: 无作用
  • λ 趋近正无穷: w* 趋近 0

在这里插入图片描述

其中η是学习率

总结

  • 权重衰退通过L2正则项使得模型参数不会过大,从而控制模型复杂度
  • 正则项权重是控制模型复杂度的超参

Tips

  • 权重衰退值一般是.1, .01, .001
  • 效果其实不会太好

Dropout

动机

  • 一个好的模型需要对输入数据的扰动鲁棒
  • 使用有噪音的数据等价于Tikhonov正则
  • Dropout:在层之间加入噪音

无偏差的加入噪音

在这里插入图片描述

即期望不变。

Dropout通常用在隐藏全连接层的输出上

在这里插入图片描述

Dropout本质上是一个正则项,只在训练中使用,它们影响模型参数的更新(model.eval())

在推理过程中,Dropout直接返回输入 h = Dropout(h)

这样也能保证确定性的输出

总结

  • 丢弃法将一些输出项随机置为0来控制模型复杂度
  • 常作用在多层感知机(MLP)的隐藏层输出上
  • 丢弃概率p是控制模型复杂度的超参数

Tips

  • 被dropout后,梯度也置0,权重也不更新
  • 提出时,认为是“训练多个小神经网络,再求平均”,但后续实验认为应解释为“正则项”
  • 每迭代一次,dropout一次

数值稳定性

带来的两个问题

  • 梯度爆炸
    • 使用ReLU作为激活函数
    • 带来的问题:
      • 值超过值域,对于16位浮点数尤为严重
    • 学习率敏感
      • 学习率太大 -> 大参数 -> 更大的梯度
      • 学习率太小 -> 训练无进展
      • 可能需要在训练中不断调整学习率
  • 梯度消失
    • 使用sigmoid作为激活函数
    • 带来的问题:
      • 梯度值变为0,对16位浮点数尤其严重
      • 训练没有进展,无论如何选择学习率
      • 对于底层尤其严重。即顶部较好,但无法使神经网络更深。

激活函数

让训练更加稳定

  • 目标:让梯度值在合理的范围内
  • 将乘法变为加法
    • ResNet、Lstm
  • 归一化
    • 梯度归一化、梯度裁剪
  • 合理的权重初始和激活函数

权重初始化

  • 在合理区间内随机初始参数
  • 训练开始时容易有数值不稳定
    • 原理最优解的地方损失函数表面可能很复杂
    • 最优解附近表面会比较平
  • 使用N(0, 0.01)来初始化可能对小网络没问题,但不能保证深度神经网络

LeNet

主要用于手写数字的识别
卷积神经网络之父
在这里插入图片描述

LeNet = torch.nn.Sequential(
        torch.nn.Conv2d(1, 6, kernel_size=5, padding=2, stride=1),
        torch.nn.Sigmoid(),
        torch.nn.AvgPool2d(kernel_size=2, stride=2),
        torch.nn.Conv2d(6, 16, kernel_size=5),
        torch.nn.Sigmoid(),
        torch.nn.AvgPool2d(2),
        torch.nn.Flatten(),
        torch.nn.Linear(16 * 5 * 5, 120),
        torch.nn.Sigmoid(),
        torch.nn.Linear(120, 84),
        torch.nn.Sigmoid(),
        torch.nn.Linear(84, 10)
    )
X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
for layer in LeNet:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:', X.shape)
Conv2d output shape: torch.Size([1, 6, 28, 28])
Sigmoid output shape: torch.Size([1, 6, 28, 28])
AvgPool2d output shape: torch.Size([1, 6, 14, 14])
Conv2d output shape: torch.Size([1, 16, 10, 10])
Sigmoid output shape: torch.Size([1, 16, 10, 10])
AvgPool2d output shape: torch.Size([1, 16, 5, 5])
Flatten output shape: torch.Size([1, 400])
Linear output shape: torch.Size([1, 120])
Sigmoid output shape: torch.Size([1, 120])
Linear output shape: torch.Size([1, 84])
Sigmoid output shape: torch.Size([1, 84])
Linear output shape: torch.Size([1, 10])

AlexNet

在这里插入图片描述

用于 ImageNet 数据集

赢得2012年ImageNet竞赛

更大更深的LeNet

主要改进:

Dropout
ReLu
MaxPooling
数据增强

计算机视觉方法论的改变

传统
    Dataset -> 人工特征提取(特征工程)(opencv)(专家) -> SVM(传统机器学习分类)
人工智能
    Dataset -> CNN学习特征 -> Softmax回归
AlexNet = torch.nn.Sequential(
    torch.nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=2), torch.nn.ReLU(),
    torch.nn.MaxPool2d(kernel_size=3, stride=2),  #
    torch.nn.Conv2d(96, 128 * 2, kernel_size=5, padding=2), torch.nn.ReLU(),
    torch.nn.MaxPool2d(kernel_size=3, stride=2),
    torch.nn.Conv2d(128 * 2, 192 * 2, kernel_size=3, padding=1), torch.nn.ReLU(),
    torch.nn.Conv2d(192 * 2, 192 * 2, kernel_size=3, padding=1), torch.nn.ReLU(),
    torch.nn.Conv2d(192 * 2, 128 * 2, kernel_size=3, padding=1), torch.nn.ReLU(),
    torch.nn.MaxPool2d(kernel_size=3, stride=2),  # 6*6*256
    torch.nn.Flatten(),
    torch.nn.Linear(6 * 6 * 256, 2048 * 2), torch.nn.ReLU(), torch.nn.Dropout(p=0.5),
    torch.nn.Linear(2048 * 2, 2048 * 2), torch.nn.ReLU(), torch.nn.Dropout(p=0.5),
    torch.nn.Linear(2048 * 2, 1000), torch.nn.ReLU(),
)
X = torch.rand(size=(1, 1, 224, 224), dtype=torch.float32)
for layer in AlexNet:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:', X.shape)
Conv2d output shape: torch.Size([1, 96, 55, 55])
ReLU output shape: torch.Size([1, 96, 55, 55])
MaxPool2d output shape: torch.Size([1, 96, 27, 27])
Conv2d output shape: torch.Size([1, 256, 27, 27])
ReLU output shape: torch.Size([1, 256, 27, 27])
MaxPool2d output shape: torch.Size([1, 256, 13, 13])
Conv2d output shape: torch.Size([1, 384, 13, 13])
ReLU output shape: torch.Size([1, 384, 13, 13])
Conv2d output shape: torch.Size([1, 384, 13, 13])
ReLU output shape: torch.Size([1, 384, 13, 13])
Conv2d output shape: torch.Size([1, 256, 13, 13])
ReLU output shape: torch.Size([1, 256, 13, 13])
MaxPool2d output shape: torch.Size([1, 256, 6, 6])
Flatten output shape: torch.Size([1, 9216])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 1000])
ReLU output shape: torch.Size([1, 1000])

VGG 使用块的网络

在这里插入图片描述

13年的冠军

“更深、更大、效果更好”

卷积块的思想
VGG块: 用大量的块堆积起来
3 * 3 卷积 更深
5 * 5 卷积 浅
深但窄 效果更好

对于给定的感受野(与输出有关的输入图片的局部大小),采用堆积的小卷积核是优于采用大的卷积核,因为多层非线性层可以增加网络深度来保证学习更复杂的模式,而且代价还比较小(参数更少)。

不同次数的重复块得到:
VGG-16
VGG-19

VGG 更占内存,更慢,精度更高

使用重复的卷积块来构建深度卷积神经网络

不同的卷积块个数和超参数可以得到不同复杂度的变种

VGG的亮点

1.小卷积核组。作者通过堆叠多个33的卷积核(少数使用11)来替代大的卷积核,以减少所需参数;

2.小池化核。相比较于AlexNet使用的33的卷积核,VGG全部为22的卷积核;

3.网络更深特征图更宽。卷积核专注于扩大通道数,池化专注于缩小高和宽,使得模型更深更宽的同时,计算量的增加不断放缓;

4.将卷积核替代全连接。作者在测试阶段将三个全连接层替换为三个卷积,使得测试得到的模型结构可以接收任意高度或宽度的输入。

5.多尺度。作者从多尺度训练可以提升性能受到启发,训练和测试时使用整张图片的不同尺度的图像,以提高模型的性能。

6.去掉了LRN层。作者发现深度网络中LRN(Local Response Normalization,局部响应归一化)层作用不明显。

在这里插入图片描述

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        layers.append(torch.nn.ReLU())
        in_channels = out_channels
    layers.append(torch.nn.MaxPool2d(kernel_size=2, stride=2))
    return torch.nn.Sequential(*layers)

def vgg(conv_arch):
    conv_blcks = []
    in_channels = 1
    for (num_convs, out_channels) in conv_arch:
        conv_blcks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels
    return torch.nn.Sequential(
        *conv_blcks, torch.nn.Flatten(),
        torch.nn.Linear(out_channels * 7 * 7, 4096), torch.nn.ReLU(),
        torch.nn.Dropout(0.5), torch.nn.Linear(4096, 4096), torch.nn.ReLU(),
        torch.nn.Dropout(0.5), torch.nn.Linear(4096, 10)
    )
conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))
VGG = vgg(conv_arch)
X = torch.rand(size=(1, 1, 224, 224), dtype=torch.float32)
for layer in VGG:
    X = layer(X)
    print(layer.__class__.__name__, 'output shape:', X.shape)
Sequential output shape: torch.Size([1, 64, 112, 112])
Sequential output shape: torch.Size([1, 128, 56, 56])
Sequential output shape: torch.Size([1, 256, 28, 28])
Sequential output shape: torch.Size([1, 512, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
Flatten output shape: torch.Size([1, 25088])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])

NiN 网络中的网络

全连接层的问题

  • 卷积层需要较少的参数 ci * co * k²
  • 但卷积层后的第一个全连接层的参数非常多

NiN的思想就是完全不要全连接层

NiN块

  • 一个卷积层后跟两个全连接层
    • 步幅1,无填充,输出形状和卷积层输出一样
    • 起到全连接层的作用
      NiN架构
  • 无全连接层
  • 交替使用NiN块和步幅为2的最大池化层
    • 逐步减小高宽和增大通道数
  • 最后使用全局平均池化层得到输出
    • 其输入通道数为类别数

总结

  • NiN块使用卷积层加两个1 * 1卷积层,后者对每个像素增加了非线性性
  • NiN使用全局平均池化层来替代Vgg和AlexNet中的全连接层,不容易过拟合,更少的参数个数
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赤赤赤赤赤赤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值