【OUC深度学习入门】第2周学习记录:卷积神经网络基础

目录

Part1 视频学习

1 传统神经网络vs卷积神经网络

2 基本组成结构

3 卷积神经网络典型结构

Part2 代码练习

1 MNIST数据集分类

2 CIFAR10数据集分类

3 使用VGG16对CIFAR10分类

Part3 问题思考

1 dataloader 里面 shuffle 取不同值有什么区别?

2 transform 里,取了不同值,这个有什么区别?

3 epoch和batch的区别?

4 1x1的卷积和FC有什么区别?主要起什么作用?

5 residual leanring为什么能够提升准确率?

6 代码练习二里,网络和1989年Lecun提出的LeNet有什么区别?

7 代码练习二里,卷积以后feature map 尺寸会变小,如何应用 Residual Learning?

8 有什么方法可以进一步提升准确率?


Part1 视频学习

1 传统神经网络vs卷积神经网络

卷积神经网络的基本应用:分类、检索、检测、分割、识别、图像生成、风格迁移、自动驾驶等

1.1 深度学习三部曲

  1. 搭建神经网络
  2. 选取合适的损失函数:交叉熵损失(cross entropy loss),均方误差(MSE)等
  3. 选取合适的优化函数来更新参数:反向传播(BP),随机梯度下降(SGD)等

1.2 损失函数

损失函数用于衡量预测结果和真实结果的吻合程度,能够帮助卷积神经网络调整参数/权重W,以达到更好的训练效果

1.3 二者比较

传统神经网络核卷积神经网络都采用了层级结构,但传统神经网络是全连接网络,几乎每个神经元都会和图片的全部像素信息进行连接,使得权重矩阵的参数过多,容易过拟合;而卷积网络通过局部关联、参数共享解决了这个问题,它的每个神经元只和图片中的某个区域进行连接,卷积核在滑动的过程中参数不变,这进一步减小了参数规模

2 基本组成结构

2.1 卷积

一维卷积:应用于信号处理中,用于计算信号的延迟累积

卷积:卷积是对两个实变函数的一种数学操作,在图像处理中,图像是以二维形式输入到神经网络的,因此需要二维卷积

卷积的相关概念

  • 基本形式:y=Wx+b,其中x是给定的图像,W是滤波器
  • 卷积核/滤波器(kernel/filter)
  • 权重(weight)
  • 感受野(receptive field):一次卷积操作对应的区域的范围大小
  • 特征图(activation map/feature map):进行卷积操作后得到的图,大小与卷积核大小、步长、图的大小有关(N+padding*2-F)/stride+1
  • 填充(padding):在图像的四周补0,使得卷积操作能兼顾图像边缘
  • 步长(stride):卷积核滑动一次的长度
  • 深度(depth/channel)

卷积的可视化:输出某一层的特征图,观察该层学习到了什么样的特征

2.2 池化

池化(Pooling):结构和操作与卷积相似,一般位于卷积层与卷积层之间,或者全连接层与全连接层之间,在保留主要特征的同时减少参数和计算量,防止过拟合,提高模型泛化能力

池化的类型

  • 最大值池化(max pooling):分类识别任务中比较常用
  • 平均池化(average pooling)

2.3 全连接

全连接层(FC layer):通常在卷积神经网络尾部,两层之间所有神经元都有权重连接,参数量很大

3 卷积神经网络典型结构

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第1张图片

3.1 AlexNet

模型结构CONV1+MAXPOOL1+NORM1+CONV2+MAXPOOL2+NORM2+CONV3+CONV4+CONV5+MAXPOOL3+FC6+FC7+FC8

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第2张图片

 模型特点

  • 大数据训练:ImageNet
  • 非线性激活函数:ReLU,解决了正区间梯度消失的问题,计算速度快,收敛速度比sigmoid快
  • 防止过拟合:Dropout(随机失活)+Data augmentation(数据增强,如平移,翻转,加高斯扰动)
  • 双GPU实现

逐层分析

  1. 卷积-ReLU-池化
  2. 卷积-ReLU-池化
  3. 卷积-ReLU
  4. 卷积-ReLU
  5. 卷积-ReLU-池化
  6. 全连接-ReLU-Dropout
  7. 全连接-ReLU-Dropout
  8. 全连接-SoftMax

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第3张图片

3.2 ZFNet

网络结构与AlexNet相同,将卷积层1中的感受野大小由11*11改为7*7,步长由4改为2;卷积层3,4,5中的滤波器个数由384,384,256改为512,512,1024

3.3 VGG

VGG是个更深的网络,AlexNet有8层,VGG有16-19层,迁移学习中常用VGG

网络结构:

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第4张图片

 16层网络的节点信息:

  • 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

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第5张图片

 

3.4 GoogleNet

网络总体结构:包含22个带参数的层(考虑pooling层就是27层),独立成块的层总共有约100个,参数量大约为AlexNet的一半,没有全连接层

Inception模块作用:多卷积核增加特征多样性

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第6张图片

Inception V2:插入1*1卷积进行降维,解决了深度加深参数数量增长过快的问题

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第7张图片

Inception V3:用小的卷积核替代大的卷积核,参数数量进一步降低;同时增加非线性激活函数使得网络产生更多独立特征,增强了表征能力,训练更快

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第8张图片

 Stem部分(stem network):卷积-池化-卷积-卷积-池化

3.5 ResNet

残差学习网络(deep residual learning network),除了输出层之外没有其他全连接层,结构灵活,可以训练非常深的网络

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第9张图片

 残差的思想:去掉相同的主体部分,突出微小的变化

Part2 代码练习

1 MNIST数据集分类

代码链接:(colab)MNIST数据集分类

深度卷积神经网络具有以下特性:

  • 很多层: compositionality
  • 卷积: locality + stationarity of images
  • 池化: Invariance of object class to translations

1.1 加载MNIST数据

PyTorch里包含了 MNIST, CIFAR10 等常用数据集,调用 torchvision.datasets 即可把这些数据由远程下载到本地,以MNIST的使用为例:

torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)

  • root:数据集下载到本地后的根目录,包括 training.pt 和 test.pt 文件
  • train:如果设置为True,从training.pt创建数据集,否则从test.pt创建
  • download:如果设置为True,从互联网下载数据并放到root文件夹下
  • transform:一种函数或变换,输入PIL图片,返回变换之后的数据
  • target_transform:一种函数或变换,输入目标,进行变换

DataLoader是一个比较重要的类,提供的常用操作有:

  • batch_size:每个batch的大小
  • shuffle:是否进行随机打乱顺序的操作
  • num_workers:加载数据的时候使用几个子进程
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
import matplotlib.pyplot as plt
import numpy

# 计算模型中有多少参数
def get_n_params(model):
    np=0
    for p in list(model.parameters()):
        np += p.nelement()
    return np

# 使用GPU训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
# out: cude:0

input_size = 28*28  # MNIST上的图像尺寸
output_size = 10  # 类别为0到9的数字

train_loader = torch.utils.data.DataLoader(datasets.MNIST('./data',train=True,download=True,
                      transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])),
                      batch_size=64,shuffle=True)

test_loader = torch.utils.data.DataLoader(datasets.MNIST('./data',train=False,
                      transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))])),
                      batch_size=1000,shuffle=True)

# 显示数据集中的部分图像
plt.figure(figsize=(8,5))
for i in range(20):
    plt.subplot(4,5,i+1)
    image,_ = train_loader.dataset.__getitem__(i)
    plt.imshow(image.squeeze().numpy(), 'gray')
    plt.axis('off');

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第10张图片

1.2 创建网络

定义网络时,需要继承nn.Module,并实现它的forward方法,把网络中具有可学习参数的层放在构造函数init中,只要在nn.Module的子类中定义了forward函数,backward函数就会自动被实现(利用autograd)

# 网络结构

class FC2Layer(nn.Module):
  def __init__(self,input_size,n_hidden,output_size):
    # nn.Module子类的函数必须在构造函数中执行父类的构造函数
    # 下式等价于nn.Module.__init__(self)        
    super(FC2Layer,self).__init__()
    self.input_size = input_size
    # 这里直接用Sequential定义网络,注意要和下面CNN的代码区分开
    self.network = nn.Sequential(
        nn.Linear(input_size,n_hidden), 
        nn.ReLU(), 
        nn.Linear(n_hidden,n_hidden), 
        nn.ReLU(), 
        nn.Linear(n_hidden,output_size), 
        nn.LogSoftmax(dim=1)
    )
  # forward函数用于指定网络的运行过程
  def forward(self,x):
    # view一般出现在model类的forward函数中,用于改变输入或输出的形状
    # 代码指定二维数据的列数为input_size=784,行数-1表示由电脑自己计算对应的数字
    # batch_size是64,所以x的行数是64
    x = x.view(-1,self.input_size) # 多维的数据展成二维
    # print(x.cpu().numpy().shape)  # 输出(64,784)
    return self.network(x)
    


class CNN(nn.Module):
  def __init__(self,input_size,n_feature,output_size):
    # 执行父类的构造函数
    super(CNN,self).__init__()
    # 池化、ReLU一类的不用在这里定义
    self.n_feature = n_feature
    self.conv1 = nn.Conv2d(in_channels=1,out_channels=n_feature,kernel_size=5)
    self.conv2 = nn.Conv2d(n_feature,n_feature,kernel_size=5)
    self.fc1 = nn.Linear(n_feature*4*4,50)
    self.fc2 = nn.Linear(50,10)    

  # 下面的forward函数定义了网络的结构
  # conv1,conv2等等可以多次重用
  def forward(self,x,verbose=False):
    x = self.conv1(x)
    x = F.relu(x)
    x = F.max_pool2d(x,kernel_size=2)
    x = self.conv2(x)
    x = F.relu(x)
    x = F.max_pool2d(x,kernel_size=2)
    x = x.view(-1,self.n_feature*4*4)
    x = self.fc1(x)
    x = F.relu(x)
    x = self.fc2(x)
    x = F.log_softmax(x,dim=1)
    return x

1.3 在小型全连接网络上训练

训练和测试函数:

# 训练函数
def train(model):
  model.train()
  # 从train_loader里,64个样本一个batch为单位提取样本进行训练
  for batch_idx,(data,target) in enumerate(train_loader):
    # 把数据送到GPU中
    data,target = data.to(device),target.to(device)

    optimizer.zero_grad()
    output = model(data)
    loss = F.nll_loss(output,target)
    loss.backward()
    optimizer.step()
    if batch_idx%100==0:
      print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
        batch_idx*len(data),len(train_loader.dataset),
        100.*batch_idx/len(train_loader),loss.item()))

# 测试函数
def test(model):
  model.eval()
  test_loss = 0
  correct = 0
  for data, target in test_loader:
    # 把数据送到GPU中
    data,target = data.to(device),target.to(device)
    # 把数据送入模型,得到预测结果
    output = model(data)
    # 计算本次batch的损失,并加到test_loss中
    test_loss += F.nll_loss(output,target,reduction='sum').item()
    # 值最大的那个即对应着分类结果,然后把分类结果保存在pred里
    pred = output.data.max(1,keepdim=True)[1]
    # 将pred与target相比,得到正确预测结果的数量,并加到correct中
    # view_as:把target变成维度和pred一样                                                
    correct += pred.eq(target.data.view_as(pred)).cpu().sum().item()

  test_loss /= len(test_loader.dataset)
  accuracy = 100.*correct/len(test_loader.dataset)
  print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
      test_loss,correct,len(test_loader.dataset),
      accuracy))
# 全连接层网络训练

n_hidden = 8 # number of hidden units

model_fnn = FC2Layer(input_size,n_hidden,output_size)
model_fnn.to(device)
optimizer = optim.SGD(model_fnn.parameters(),lr=0.01,momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_fnn)))

train(model_fnn)
test(model_fnn)

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第11张图片

1.4 在卷积神经网络上训练

# 卷积神经网络训练

# Training settings 
n_features = 6 # number of feature maps

model_cnn = CNN(input_size,n_features,output_size)
model_cnn.to(device)
optimizer = optim.SGD(model_cnn.parameters(),lr=0.01,momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_cnn)))

train(model_cnn)
test(model_cnn)

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第12张图片

由此可知,在参数数量相近的情况下,CNN的效果优于简单的全连接网络,因为CNN通过卷积核池化,能更好地提取信息

1.5 打乱像素顺序再次在两个网络上训练与测试

卷积和池化操作都是基于图像地局部进行的,能提取到像素的位置关系,此时尝试把图像中的像素打乱顺序

# 打乱像素顺序的演示

perm = torch.randperm(784)  # 给定参数n,返回一个从0到n-1的随机整数排列
plt.figure(figsize=(8,4))
for i in range(10):
    image,_ = train_loader.dataset.__getitem__(i)
    # permute pixels
    image_perm = image.view(-1,28*28).clone()
    image_perm = image_perm[:,perm]
    image_perm = image_perm.view(-1,1,28,28)
    plt.subplot(4,5,i+1)
    plt.imshow(image.squeeze().numpy(), 'gray')
    plt.axis('off')
    plt.subplot(4,5,i+11)
    plt.imshow(image_perm.squeeze().numpy(),'gray')
    plt.axis('off')

打乱像素顺序后的效果:

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第13张图片

打乱像素顺序的函数:

# 对每个batch里的数据,打乱像素顺序的函数
def perm_pixel(data,perm):
  # 转化为二维矩阵
  data_new = data.view(-1,28*28)
  # 打乱像素顺序
  data_new = data_new[:,perm]
  # 恢复为原来4维的tensor
  data_new = data_new.view(-1,1,28,28)
  return data_new

在全连接网络上训练和测试:

# 打乱像素顺序训练全连接网络

perm = torch.randperm(784)
n_hidden = 8  # number of hidden units

model_fnn = FC2Layer(input_size,n_hidden,output_size)
model_fnn.to(device)
optimizer = optim.SGD(model_fnn.parameters(),lr=0.01,momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_fnn)))

train_perm(model_fnn,perm)
test_perm(model_fnn,perm)

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第14张图片

在卷积神经网络上训练和测试:

# 打乱像素顺序训练卷积神经网络

perm = torch.randperm(784)
n_features = 6  # number of feature maps

model_cnn = CNN(input_size,n_features,output_size)
model_cnn.to(device)
optimizer = optim.SGD(model_cnn.parameters(),lr=0.01,momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_cnn)))

train_perm(model_cnn,perm)
test_perm(model_cnn,perm)

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第15张图片

由此可知,打乱像素顺序后,卷积神经网络性能下降了,像素间的局部关系对卷积神经网络来说是个很重要的训练信息

2 CIFAR10数据集分类

代码链接:(colab)CIFAR10数据集分类

CIFAR10数据集包含10个类别,图像尺寸为3*32*32,可以使用torchsivion加载,torchvision数据集的输出范围是[0,1]的PILImage,使用前需要先进行归一化操作,转换为[-1,1]的张量

import torch
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]])

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第16张图片

2.1 定义网络、损失函数和优化器

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)

2.2 训练网络

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%200==0:   
            print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch+1,i+1,loss.item()))

print('Finished Training')

 训练结果:

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第17张图片【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第18张图片

2.3 观察识别效果

# 得到一组图像
images,labels = iter(testloader).next()
# 展示图像
imshow(torchvision.utils.make_grid(images))
# 展示图像的标签
for j in range(8):
    print(classes[labels[j]])

outputs = net(images.to(device))
_,predicted = torch.max(outputs,1)

print("预测结果:")

# 展示预测的结果
for j in range(8):
    print(classes[predicted[j]])

 【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第19张图片

 发现有少量的识别错误

2.4 统计整体准确率

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第20张图片

 准确率较低,有待提高

3 使用VGG16对CIFAR10分类

代码链接:(colab)VGG_CIFAR10

3.1 定义dataloader

相比代码练习二,这里的归一化操作的参数有了一些改变

import torch
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_train = transforms.Compose([
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize((0.4914,0.4822,0.4465),(0.2023,0.1994,0.2010))])

transform_test = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.4914,0.4822,0.4465),(0.2023,0.1994,0.2010))])

trainset = torchvision.datasets.CIFAR10(root='./data',train=True,download=True,transform=transform_train)
testset = torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform_test)

trainloader = torch.utils.data.DataLoader(trainset,batch_size=128,shuffle=True,num_workers=2)
testloader = torch.utils.data.DataLoader(testset,batch_size=128,shuffle=False,num_workers=2)

classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')

3.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

# 简化版的VGG

class VGG(nn.Module):
  def __init__(self):
    super(VGG,self).__init__()
    self.cfg = [64,'M',128,'M',256,256,'M',512,512,'M',512,512,'M']
    self.features = self._make_layers(self.cfg)
    self.classifier = nn.Linear(2048,10)  # 根据分类任务的类别数量确定

  def forward(self,x):
    out = self.features(x)
    out = out.view(out.size(0),-1)
    out = self.classifier(out)
    return out

  def _make_layers(self,cfg):
    layers = []
    in_channels = 3
    for x in cfg:
      if x=='M':
        layers += [nn.MaxPool2d(kernel_size=2,stride=2)]
      else:
        layers += [nn.Conv2d(in_channels,x,kernel_size=3,padding=1),nn.BatchNorm2d(x),nn.ReLU(inplace=True)]
        in_channels = x
    layers += [nn.AvgPool2d(kernel_size=1,stride=1)]
    return nn.Sequential(*layers)


# 网络放到GPU上
net = VGG().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(),lr=0.001)

3.3 网络训练

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')

训练过程的loss:

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第21张图片【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第22张图片

3.4 测试验证准确率

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第23张图片

 相比代码练习二中使用CNN训练得到的准确率,使用VGG得到的准确率提高了20点,VGG比代码练习二的CNN深度更深,非线性变换的可能情况更多,更有利于VGG找到更适合的非线性变换来解决数据分类问题

Part3 问题思考

1 dataloader 里面 shuffle 取不同值有什么区别?

shuffle是bool类型的参数,当shuffle为True时,加载数据集数据时会将数据打乱,shuffle为False时不打乱,打乱顺序会使得每轮训练中的数据序列都不一样,消除了数据排列对训练效果的影响

2 transform 里,取了不同值,这个有什么区别?

此处的transform定义了一些常用的数据预处理操作,包括数据归一化,随机裁剪、翻转等,可以用于数据增强,充分利用数据样本,提高训练模型的泛化能力

代码练习中用到的transforms.normalize()用于逐个channel对图像进行标准化,使得数据服从均值为0,标准差为1的分布,加快模型的收敛速度,基本实现公式为x=(x-mean)/std,其中mean是数据本身的均值,std是数据本身的标准差,这两个值需要事先计算得到

normalize之前,数据在[0,1],normalize时,如果是normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),则是对数据进行归一化,如果是normalize(mean, std),则是将数据处理为均值为0,标准差为1的分布

3 epoch和batch的区别?

epoch是训练数据集的轮数,一个epoch相当于全部跑完一次数据集;bantch是一个epoch内一次批量训练的样本数

4 1x1的卷积和FC有什么区别?主要起什么作用?

1*1卷积是二维卷积的一种特殊情况,可以起到降维的作用,在应对多维度的输入时,可以调节通道数,减少参数,帮助捕捉深度上的pattern,还可以增加非线性,代替FC作为分类器。与FC相比,1*1卷积能实现权值共享,参数量较同等功能的fc层相比少,使用了位置信息,并且fc层对于训练样本要求统一尺寸,但是1*1的卷积不受这种规定的限制

5 residual leanring为什么能够提升准确率?

在训练网络的过程中,深度越深,参数越复杂,网络也就越复杂,但分类任务具有过程未知性,并且深度的神经网络很难实现恒等映射,导致网络很难学习到更优的参数,引入残差学习后,网络能实现恒等映射了,训练过程中可以根据实际效果跳过其中的几个层,灵活性更大,因此可以提高准确率

6 代码练习二里,网络和1989年Lecun提出的LeNet有什么区别?

LeNet结构大致如下:

【OUC深度学习入门】第2周学习记录:卷积神经网络基础_第24张图片

代码练习二中使用的是最大池化和ReLU激活函数,而LeNet使用的是平均池化,激活函数是sigmoid

7 代码练习二里,卷积以后feature map 尺寸会变小,如何应用 Residual Learning?

可以参考50层以上的ResNet网络的BottleNeck的设计,使用1*1卷积来调整维度和feature map尺寸

8 有什么方法可以进一步提升准确率?

  1. 添加Dropout操作
  2. 多尝试不同的网络结构,适当调节层数
  3. 尝试不同的激活函数
  4. 使用L1/L2正则化
  5. 使用预训练,使用预训练得到的参数进行正式训练
  6. 尝试不同的优化器和损失函数,尝试调节超参数

你可能感兴趣的:(python,深度学习,神经网络,人工智能)