Dog VS Cat
VGG网络
VGG 是一个卷积神经网络模型,是哈弗 Robotics Institute Visual Geometry Group 组的 Karen Simonyan 和 Andrew Zisserman 在2014年提出的。2014年在最大的图像识别竞赛 ILSVRC 中,这个模型获得第二名,第一名是 GoogleNet,VGG 模型在多个迁移学习任务中好于 GoogleNet。
VGG 是卷积神经网络的重大突破,在这些之后:
- LeNet-5 (1998)
- AlexNet (2012)
- ZFNet (2013)
- GoogleNet/Inception (2014)
注:AlexNet 的提出,使得大型卷积网络变得流行了起来。ZFNet 是基于 AlexNet 的一种模型改进。
VGG的特点
上图中,上面是AlexNet和下面VGG-16两种模型结构比较
AlexNet 包含有5个卷积层和3个全连接层,在第1、2和5卷积层使用了3个最大池化层
VGG-16 包含有13个卷积层,卷积核为3X3,3个全连接层
VGG-19包含了16个卷积层和3个全连接层
VGG 网络结构非常一致,从头到尾全部使用了 3X3 的卷积核和2X2的 max-pooling
VGG-16网络结构一镜到底:https://dgschwend.github.io/netscope/#/preset/vgg-16
VGG Dogs VS Cats
Description
本次作业实现使用预训练好的 VGG 模型,下载Imagenet 1000 个类的 JSON 文件。
VGG 模型网络组成元素:
- 卷积层(CONV)是发现图像中局部的 pattern
- 全连接层(FC)是在全局上建立特征的关联
- 池化(Pool)是给图像将维以提高特征的invariance
1 | import numpy as np |
1 | Using: gpu:True |
1 | # 下载数据并解压 |
数据处理
图片裁剪
转换为 tensor 格式
因为图片读入后为 numpy 格式,需要在 pytorch中进行处理,就需要转化为 tensor 的格式。
至于 tensor 的含义:
tensor:张量
是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。
—wikipedia
概念:能够用指标表示法表示的物理量,并且该物理量满足坐标变换关系。
- 0阶张量:无自由指标的量,与坐标系选取无关,如温度、质量、能量等标量
- 1阶张量(向量):有一个自由指标的量,如坐标 ,位移等矢量
- 2阶张量:有2个自由指标的量,如应力,应变等
- 3阶张量:如数据立方
在深度学习里,张量即为一个多维数组,其可以创建更高维度的矩阵
Tensor对象的3个属性:
- Rank: number of dimensions
- Shape: number of rows and columns
- Type: data type of tensor’s elements
归一化
- 不同的图片映射到同一坐标系,拥有相同的尺度
- 像素值大小不同的问题转化为具有相似特征分布的问题
- 一定程度上消除了因为过度曝光,质量不佳或者噪声等各种原因对模型权值更新的影响
1 | normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) #归一化每个通道的平均值和标准差 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 训练时 shuffle是true,当检验时则为False
loader_train = torch.utils.data.DataLoader(dsets['train'], batch_size=64, shuffle=True, num_workers=6)
loader_valid = torch.utils.data.DataLoader(dsets['valid'], batch_size=5, shuffle=False, num_workers=6)
'''
valid 数据一共有2000张图,每个batch是5张,因此,下面进行遍历一共会输出到 400
同时,把第一个 batch 保存到 inputs_try, labels_try,分别查看
'''
count = 1
for data in loader_valid:
print(count, end='\n')
if count == 1:
inputs_try,labels_try = data
count +=1
print(labels_try)
print(inputs_try.shape)
1 | # 训练时 shuffle是true,当检验时则为False |
1 | 1 |
模型下载 ,创建 VGG Model
1
!wget https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json
1 | !wget https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json |
1 | --2020-11-17 06:42:58-- https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json |
创建的是 VGG16 模型
1 | model_vgg = models.vgg16(pretrained=True) |
1 | Downloading: "https://download.pytorch.org/models/vgg16-397923af.pth" to /root/.cache/torch/hub/checkpoints/vgg16-397923af.pth |
修改模型
修改最后一层网络,冻结前面层的参数,使用预训练好的模型,需要把最后的 nn.Linear 层由 1000类替换为 2类。
为了在训练中冻结前面层的参数,需要设置 required_grad=False。这样,反向传播训练梯度时,前面层的权重就不会自动更新了,训练中,只会更新最后一层的参数。
1 | print(model_vgg) |
1 | VGG( |
训练并测试全连接层
三个步骤
- 创建损失函数和优化器
- 训练模型
- 测试模型
在这里,改用 Adam 替换 SGD 优化器
SGD (Stochastic Gradient Descent)朴素梯度下降,最为简单,没有动量的概念。
缺点在于:收敛速度慢,可能在鞍点(沿着某一个方向是稳定的另一个方向是不稳定的,物理含义即一个方向上是极大值,另一个方向上是极小值)处震荡。
为了跳出鞍点处,提出了动量的概念因此有了几种改进的优化器
Adam 简单说是一种添加了动量的梯度下降优化器,大大提高了收敛的速度。
缺点在于:可能越过全局最优解;某些情况可能不收敛
在这里设置一个最大精度值max_acc,每一个 epoch 都与之进行比较,当新的 epoch 精度更好时替换之,保存训练出的最好的模型和最后一个训练的模型。
1 | ''' |
(epochs 起初改为100,后来发现改为10,效果也已经不错了)
valid 数据模型测试
1 | def test_model(model,dataloader,size): |
1 | Testing: No. 5 process ... total: 2000 |
研习社 test 数据测试
1 | # 加载测试数据 |
将测试结果 dic 按顺序写入 csv 文件
1 | with open("result1.csv",'a+') as f: |
提交结果
最早的结果是训练 epoch 修改为100,SGD优化器时,训练 Acc 为0.99时获得的。
第二个是修改优化器为 Adam 时的结果, Acc 同样为0.99时获得的结果。
总结
增加 epoch 数量会提高训练的准确度
优化器改为 Adam 会提高训练时收敛的速度,但对于结果好像没有太大的提升
当修改了学习率时,发现对 Acc 有不错的影响,选择 epoch = 10, 测试了 0.001 学习率,和0.005学习率,发现0.005可以在一开始时就获得比较高的 Acc。
对于学习率的设置有:
学习率 | 大 | 小 |
---|---|---|
学习速度 | 快 | 慢 |
使用时间点 | 刚开始训练时 | 经过一定轮数后 |
副作用 | 1. 易损失值爆炸;2. 易震荡 | 1. 易过拟合;2. 收敛速度慢 |
- 设置一个最大精度值max_acc,每一个 epoch 的 Acc 都与之进行比较,当新的 epoch 精度更好时替换之,保存训练出的最好的模型。然后用最好的训练模型进行 valid 数据集测试和 test 数据集测试。