import torch
训练误差:在训练集上的误差(train_loss)
泛化误差:在测试集上的误差(test_loss)
验证集:一个用来评估模型好坏的数据集
例如拿出50%的训练数据
不要和训练集混在一起
一定程度上能反映出模型超参数的好坏
测试集:只用一次的数据集。例如
未来的考试
我出价的房子的实际成交价
kaggle私有排行榜的数据集
K-则交叉验证
算法:
常用:K=5或10
简单数据、复杂模型 -》 过拟合
复杂数据、简单模型 -》 欠拟合
模型容量:
估计模型容量
多个重要因素
控制模型容量:
优化的是最小损失函数
常用的:使用《均方范数》作为柔性限制
超参数λ控制了正则项的重要程度
其中η是学习率
总结
Tips
动机
无偏差的加入噪音
即期望不变。
Dropout通常用在隐藏全连接层的输出上
Dropout本质上是一个正则项,只在训练中使用,它们影响模型参数的更新(model.eval())
在推理过程中,Dropout直接返回输入 h = Dropout(h)
这样也能保证确定性的输出
总结
Tips
带来的两个问题
让训练更加稳定
权重初始化
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])
用于 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])
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的思想就是完全不要全连接层
NiN块
总结