神经网络与深度学习(基于动手学深度学习pytorch)(二)

本文详细介绍了卷积神经网络的基础概念,包括全连接网络的问题、卷积运算、填充、步长、多通道卷积,以及AlexNet的结构和改进措施,如ReLU激活、池化层、Dropout防止过拟合。同时,提供了使用PyTorch实现的基本卷积神经网络示例。
摘要由CSDN通过智能技术生成

【内容介绍】本文中主要对卷积神经网络进行介绍和部分代码进行实验演示,其中主要使用平台为pytorch,相关安装教程可以参考2023最新pytorch安装(超详细版),代码运行平台为vscode,插件jupyter。

1.卷积神经网络基础

1.1 全连接网络问题

       前面章节中介绍了全连接网络,全连接神经网络(Fully Connected Netural Network,FCN),是一种连接方式较为简单的人工神经网络结构,属于前馈神经网络的一种,只要有输入层、隐藏层和输出层构成,并且在每个隐藏层中可以有多个神经元。多层感知机(MLP, Multi-Layer Perceptron),也叫人工神经网络(ANN,Artificial Neural Network)就属于是全连接网络,MLP 网络是可以应用于几乎所有任务的多功能学习方法,包括分类、回归,甚至是无监督学习。

       但随着现代科技的发展,神经网络面对的数据量越来越大,全连接网络容易出现链接权过多,算的慢,难收敛,同时可能进入局部极小值,也容易产生过拟合问题。为解决这个问题,相关学者提出减少权值连接,每一个节点只连到上一层的少 数神经元,即局部连接网络。信息分层处理,每一层在上层提取特征的基 础上获取进行再处理,得到更高级别的特征。

2.基本概念

2.1基本概念

2.1.1 卷积

        深度学习里面所谓的卷积运算,其实它被称为互相关(cross-correlation)运算:将图像矩阵中,从左到右,由上到下,取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,最后的结果组成一个矩阵,其中没有对核进行翻转。

2.1.2填充

       有时我们希望输入和输出的大小应该保持一致。为解决这个问题,可以在进行卷积操作前,对原矩阵进行边界填充(Padding),也就是在矩阵的边界上填充一些值,以增加矩阵的大小,通常都用“0”来进行填充的。通过填充的方法,当卷积核扫描输入数据时,它能延伸到边缘以外的伪像素,从而使输出和输入size相同。

2.1.3步长

        滑动卷积核时,我们会先从输入的左上角开始,每次往左滑动一列或者往下滑动一行逐一计算输出,我们将每次滑动的行数和列数称为Stride,卷积过程中,有时需要通过padding来避免信息损失,有时也要在卷积时通过设置的步长(Stride)来压缩一部分信息,或者使输出的尺寸小于输入的尺寸。Stride的作用:是成倍缩小尺寸,而这个参数的值就是缩小的具体倍数,比如步幅为2,输出就是输入的1/2;步幅为3,输出就是输入的1/3。以此类推。

2.1.4多通道卷积

       多通道卷积的计算过程:将矩阵与滤波器对应的每一个通道进行卷积运算,最后相加,形成一个单通道输出,加上偏置项后,我们得到了一个最终的单通道输出。如果存在多个filter,这时我们可以把这些最终的单通道输出组合成一个总输出。

        可以通过相关网站进行进行体会基础卷积神经网络“ 相关卷积神经网络3D可视化

import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
nn.Linear(120, 84), nn.Sigmoid(),
nn.Linear(84, 10))
X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape: \t',X.shape)
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)
def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    """使用GPU计算模型在数据集上的精度"""
    if isinstance(net, nn.Module):
        net.eval() # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device
    # 正确预测的数量,总预测的数量
    metric = d2l.Accumulator(2)
    with torch.no_grad():
       for X, y in data_iter:
          if isinstance(X, list):
# BERT微调所需的(之后将介绍)
              X = [x.to(device) for x in X]
          else:
              X = X.to(device)
          y = y.to(device)
          metric.add(d2l.accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]
#@save
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """用GPU训练模型(在第六章定义)"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
             nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
                            legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    for epoch in range(num_epochs):
# 训练损失之和,训练准确率之和,样本数
        metric = d2l.Accumulator(3)
        net.train()
        for i, (X, y) in enumerate(train_iter):
            timer.start()
            optimizer.zero_grad()
            X, y = X.to(device), y.to(device)
            y_hat = net(X)
            l = loss(y_hat, y)
            l.backward()
            optimizer.step()
            with torch.no_grad():
                metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
            timer.stop()
            train_l = metric[0] / metric[2]
            train_acc = metric[1] / metric[2]
            if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
                animator.add(epoch + (i + 1) / num_batches,
                            (train_l, train_acc, None))
            test_acc = evaluate_accuracy_gpu(net, test_iter)
            animator.add(epoch + 1, (None, None, test_acc))
    print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
     f'test acc {test_acc:.3f}')
    print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
      f'on {str(device)}')
lr, num_epochs = 0.9, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

3.基本卷积神经网络

3.1AlexNet

 AlexNet输入为RGB三通道的224 × 224 × 3大小的图像(也可填充为227 × 227 × 3 )。AlexNet 共包含5 个卷积层(包含3个池化)和 3 个全连接层。其中,每个卷积层都包含卷积核、偏置项、ReLU激活函数和局部响应归一化(LRN)模块。第1、2、5个卷积层后面都跟着一个最大池化层,后三个层为全连接层。最终输出层为softmax,将网络输出转化为概率值,用于预测图像的类别。

3.1.1卷积层池化层

AlexNet共有五个卷积层,每个卷积层都包含卷积核、偏置项、ReLU激活函数和局部响应归一化(LRN)模块。

卷积层C1:使用96个核对224 × 224 × 3的输入图像进行滤波,卷积核大小为11 × 11 × 3,步长为4。将一对55×55×48的特征图分别放入ReLU激活函数,生成激活图。激活后的图像进行最大池化,size为3×3,stride为2,池化后的特征图size为27×27×48(一对)。池化后进行LRN处理。

卷积层C2:使用卷积层C1的输出(响应归一化和池化)作为输入,并使用256个卷积核进行滤波,核大小为5 × 5 × 48。

卷积层C3:有384个核,核大小为3 × 3 × 256,与卷积层C2的输出(归一化的,池化的)相连。

卷积层C4:有384个核,核大小为3 × 3 × 192。

卷积层C5:有256个核,核大小为3 × 3 × 192。卷积层C5与C3、C4层相比多了个池化,池化核size同样为3×3,stride为2。

其中,卷积层C3、C4、C5互相连接,中间没有接入池化层或归一化层。

3.1.2 全连接层(后三层)

全连接层F6:因为是全连接层,卷积核size为6×6×256,4096个卷积核生成4096个特征图,尺寸为1×1。然后放入ReLU函数、Dropout处理。值得注意的是AlexNet使用了Dropout层,以减少过拟合现象的发生。

全连接层F7:同F6层。

全连接层F8:最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000个类别预测的值。

 3.1.3 Dropout改进

为了防止过拟合,AlexNet 引入了数据增强和 Dropout 技术。数据增强可以通过对图像进行旋转、翻转、裁剪等变换,增加训练数据的多样性,提高模型的泛化能力。Dropout 则是在训练过程中随机删除一定比例的神经元,强制网络学习多个互不相同的子网络,从而提高网络的泛化能力。Dropout简单来说就是在前向传播的时候,让某个神经元的激活值以一定的概率p停止工作,这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征。

 3.1.4代码实现

import torch
from torch import nn
from d2l import torch as d2l
net = nn.Sequential(
     # 这里使用一个11*11的更大窗口来捕捉对象。 
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
      nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
      nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
      nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
      nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
      nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
      nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
      nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
      nn.MaxPool2d(kernel_size=3, stride=2),
      nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
      nn.Linear(6400, 4096), nn.ReLU(),
      nn.Dropout(p=0.5),
      nn.Linear(4096, 4096), nn.ReLU(),
      nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
      nn.Linear(4096, 10))
X = torch.randn(1, 1, 224, 224)
for layer in net:
    X=layer(X)
    print(layer.__class__.__name__,'output shape:\t',X.shape)
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值