Part 1: 视频学习
一、卷积神经网络的结构
- 卷积层:卷积层也叫特征提取层,使用卷积核来提取图像中的特征。
例如:二维卷积:卷积核(F*F*x)是一个矩阵,以一定步长移动
卷积核:一个卷积核有x个权重矩阵,x=原图像通道数
步长:卷积核每次移动几个格子
感受野:卷积核进行一次卷积时输入图像(N*N*x)所对应的区域
特征图:卷积后输出的结果
特征图大小(N-F)/步长+1
特征图大小(N+pedding*2-F)/步长+1
Depth/channel:特征图的深度/个数(和卷积核的个数保持一致)
pedding:如果原图像在卷积的过程中出现一部分不够一次卷积,则在图像四周都补0
参数量=(F*F+1)*channel
二、池化层
- 保留主要特征的同时减少参数和计算量,防止过拟合,提高模型泛化能力
- 它一般处于卷积层与卷积层之间,全连接层与全连接层之间
- 池化核,步长
- 类型:
Max polling:最大值池化——分类任务中更倾向
Average polling:平均池化
池化层用处:
1.特征不变性2.特征降维(下采样)3.在一定程度上防止过拟合,更方便优化。
4.实现非线性。5.扩大感受野。
三、全连接层:
全连接层,是每一个结点都与上一层的所有结点相连,用来把前边提取到的特征综合起来。由于其全相连的特性,一般全连接层的参数也是最多的。全连接层的目的是将网络学习到的特征映射到样本的标记空间中。全连接层会把卷积输出的二维特征图转化成一个一维的向量。
- 两层之间的所有神经元都有权重链接
- 通常全连接层在卷积神经网络尾部
- 全连接层参数量通常最大
全连接:通常全连接层在卷积神经网络尾部。
小结:
一个典型的卷积网络是由卷积层、池化层、全连接层交叉堆叠而成;
未加padding时输出特征图大小:(N-F)/stride+1;
有padding时输出的特征图大小:(N+padding*2-F)/stride+1;
Pooling的类型:Maxing pooling:最大值池化,Average pooling:平均池化;
全连接:通常全连接层在卷积神经网络尾部。
AlexNet:
Alexnet共有8层结构,前5层为卷积层,后三层为全连接层。
AlexNet成功的原因在于:
大数据训练:百万级ImageNet图像数据
非线性激活函数:ReLU
防止过拟合:Dropout, Data augmentation
其他:双GPU实现
ReLU函数:
解决了梯度消失的问题(在正区间)
计算速度特别快,只需要判断输入是否大于0,大于0就不用算了
收敛速度远快于sigmoid
DropOut(随机失活)
训练时随机关闭部分神经元。测试时整合所有神经元
进行每一层的分析:
ZFNet
网络结构与AlexNet相同
将卷积层1中的感受野大小由11*11改为7*7,步长由4改为2
卷积层3,4,5中的滤波器个数由384,384,256改为512,512,1024
2013年ImageNet图像分类竞赛的冠军 ImageNet top 5 error: 16.4% -> 14.8%
VGG
VGG是一个更深网络
8 layers (AlexNet) -> 16 – 19 (VGG),先训练前面的11层,把网络固定住,再训练后面的
ILSVRC top 5 错误率从11.7% -> 7.3%
GoogleNet
不止是在深度上加深,在结构上也做了改进,2014年ImageNet图像分类竞赛的冠军,ImageNet top 5 error: 11.7% -> 6.7%
网络总体结构:
网络包含22个带参数的层(如果考虑pooling层就是27层),独立成块的层总共有约有100个;
参数量大概是Alexnet的1/12
没有FC层
Naive Inception
初衷:多卷积核增加特征多样性
在同一层用了三个不同的卷积核,对不同卷积核的输出在深度上进行串联,用padding让输出的前两维大小保持一致
channel的个数很大,随着模型的加深,chennel的个数一直不断增多,计算复杂度过高
Inception V2
解决思路:插入1*1卷积核进行降维
Inception V3
Inception V3 进一步对v2的参数数量进行降低。用小的卷积核替代大的卷积核,一次5*5卷积和两次3*3卷积对应的卷积核大小一样
降低参数量
增加非线性激活函数:增加非线性激活函数使网络产生更多独立特(disentangled
feature),表征能力更强,训练更快。
GoogleNet
Stem部分(stem network):卷积 – 池化 – 卷积 –卷积 – 池化
中间部分:多个Inception结构堆叠
输出:没有额外的全连接层(除了最后的类别输出层)
辅助分类器:解决由于模型深度过深导致的梯度消失的问题。
ResNet
残差学习网络(deep residuallearning network),2015年ILSVRC竞赛冠军, top 5 错
误率从6.7% -> 3.57%。深度有152层
残差的思想: 传统结构是一个连乘的形式,残差多了加和,不会存在梯度消失的问题。去掉相同的主体部分,从而突出微小的变化。
可以被用来训练非常深的网络
Part 2:代码练习
一、MNIST 数据集分类
1. 加载数据 (MNIST)
显示数据集中的部分图像
2. 创建网络
3. 在小型全连接网络上训练
4. 在卷积神经网络上训练
5. 打乱像素顺序再次在两个网络上训练与测试
下面代码展示随机打乱像素顺序后,图像的形态:
重新定义训练与测试函数
在全连接网络上训练与测试:
在卷积神经网络上训练与测试:
从打乱像素顺序的实验结果来看,全连接网络的性能基本上没有发生变化,但是 卷积神经网络的性能明显下降。
这是因为对于卷积神经网络,会利用像素的局部关系,但是打乱顺序以后,这些像素间的关系将无法得到利用。
二、CIFAR10数据集分类
CIFAR10数据集包含10个类别,图像尺寸为33232,可以使用torchsivion加载,torchvision数据集的输出范围是[0,1]的PILImage,使用前需要先进行归一化操作,转换为[-1,1]的张量。
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# 使用GPU训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])
# 训练的shuffle是True,打乱顺序增加样本多样性,测试的shuffle是false
trainset = torchvision.datasets.CIFAR10(root='./data',train=True,download=True,transform=transform)
trainloader = torch.utils.data.DataLoader(trainset,batch_size=64,shuffle=True,num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader = torch.utils.data.DataLoader(testset,batch_size=8,shuffle=False,num_workers=2)
classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
def imshow(img):
plt.figure(figsize=(8,8))
img = img/2+0.5 # 转换为[0,1]
npimg = img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
# 得到一组图像
images,labels = iter(trainloader).next()
# 展示图像
imshow(torchvision.utils.make_grid(images))
# 展示第一行图像的标签
for j in range(8):
print(classes[labels[j]])
接下来定义网络,损失函数和优化器:
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
# 网络放到GPU上
net = Net().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
训练网络:
for epoch in range(10): # 重复多轮训练
for i, (inputs, labels) in enumerate(trainloader):
inputs = inputs.to(device)
labels = labels.to(device)
# 优化器梯度归零
optimizer.zero_grad()
# 正向传播 + 反向传播 + 优化
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# 输出统计信息
if i % 100 == 0:
print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
print('Finished Training')
现在我们从测试集中取出8张图片:
# 得到一组图像
images, labels = iter(testloader).next()
# 展示图像
imshow(torchvision.utils.make_grid(images))
# 展示图像的标签
for j in range(8):
print(classes[labels[j]])
我们把图片输入模型,看看CNN把这些图片识别成什么:
outputs = net(images.to(device))
_, predicted = torch.max(outputs, 1)
# 展示预测的结果
for j in range(8):
print(classes[predicted[j]])
可以看到,有几个都识别错了~~~ 让我们看看网络在整个数据集上的表现:
correct = 0
total = 0
for data in testloader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
三、使用 VGG16 对 CIFAR10 分类
VGG是由Simonyan 和Zisserman在文献《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷积神经网络模型,其名称来源于作者所在的牛津大学视觉几何组(Visual Geometry Group)的缩写。
该模型参加2014年的 ImageNet图像分类与定位挑战赛,取得了优异成绩:在分类任务上排名第二,在定位任务上排名第一。
VGG16的网络结构如下图所示:
6层网络的结节信息如下:
- 01:Convolution using 64 filters
- 02: Convolution using 64 filters + Max pooling
- 03: Convolution using 128 filters
- 04: Convolution using 128 filters + Max pooling
- 05: Convolution using 256 filters
- 06: Convolution using 256 filters
- 07: Convolution using 256 filters + Max pooling
- 08: Convolution using 512 filters
- 09: Convolution using 512 filters
- 10: Convolution using 512 filters + Max pooling
- 11: Convolution using 512 filters
- 12: Convolution using 512 filters
- 13: Convolution using 512 filters + Max pooling
- 14: Fully connected with 4096 nodes
- 15: Fully connected with 4096 nodes
- 16: Softmax
1. 定义 dataloader
2. VGG 网络定义
下面定义VGG网络,参数太多,我手动改简单了些~~~
现在的结构基本上是:
64 conv, maxpooling,
128 conv, maxpooling,
256 conv, 256 conv, maxpooling,
512 conv, 512 conv, maxpooling,
512 conv, 512 conv, maxpooling,
softmax
下面是模型的实现代码:
初始化网络,根据实际需要,修改分类层。
3. 网络训练
注意:两个矩阵的行列相乘需匹配,故将2048改为512
4. 测试验证准确率
可以看到,使用一个简化版的 VGG 网络,就能够显著地将准确率提升到83.47%
Part 3:问题解答
1. dataloader 里面 shuffle 取不同值有什么区别?
DataLoader中的shuffer=False表示不打乱数据的顺序,然后以batch为单位从头到尾按顺序取用数据。DataLoader中的shuffer=True表示在每一次epoch中都打乱数据顺序,然后以batch为单位从头到尾按顺序取用数据
2、transform 里,取了不同值,这个有什么区别?
transforms.ToTensor()函数的作用是将原始的PILImage格式或者numpy.array格式的数据格式化为可被pytorch快速处理的张量类型。
transforms.Normalize()是数据标准化函数,可以逐channel的对图像进行标准化(均值变为0,标准差变为1),可以加快模型的收敛。
3、epoch 和 batch 的区别?
Batch大小是在更新模型之前处理的多个样本。Epoch数是通过训练数据集的完整传递次数。
当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一次epoch。
将整个训练样本分成若干个部分,并称为Batch。
Epoch由一个或多个Batch组成
4、1x1的卷积和 FC 有什么区别?主要起什么作用?
区别:1*1的卷积核是输入map大小不固定的,而全连接是固定的。卷积层使得网络可以接受任意的输入,因为卷积作用在一个局部的区域,而全连接则对于整个输入而言。
1*1卷积的作用:
- 如果当前层与下一层层数均非1,则可以起到跨通道聚合的作用,从而改变维度,进而达到减少参数的作用。
- 可以用于调节通道数,对不同的通道上的像素点进行线性组合,然后进行非线性化操作,灵活控制特征图的深度
- 改变维度的操作就是通道间信息的线性组合变化,即通道间的信息交互。1*1卷积可以在保持feature map尺度不变的前提下大幅增加非线性特性,把网络做的很深,增加非线性特性。
Fc的作用:
- 在整个卷积神经网络中起到”分类器“的作用,即将学到的“分布式特征表示”映射到样本标记空间的作用
- FC可在模型表示能力迁移过程中充当“防火墙”的作用。
5. residual leanring 为什么能够提升准确率?
通过支路的设计在传递时加上本身,形成了Y=F(x)+x的结构,这样一来,无论经过多少层求导,梯度始终不会小于1,解决了梯度消失的问题,因此能够增加网络深度来提高准确率。
6、代码练习二里,网络和1989年 Lecun 提出的 LeNet 有什么区别?
激活函数不同:LeNet网络使用的是sigmoid激活函数,而AlexNet使用的是ReLU函数。ReLU函数可以有效避免梯度消失的问题
7、代码练习二里,卷积以后feature map 尺寸会变小,如何应用 Residual Learning?
可以利用1x1卷积改变channel个数,从而达成一致
8、有什么方法可以进一步提升准确率?
(1)对于residual leanring,可以增加深度与节点数
(2)增加训练轮数
(3)丰富数据集中的数据
(4)优化网络结构