抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Hello World

人よ、幸福に生きろ!

PyTorch深度学习

神经网络

层层组成,多达几百层或者上千层的叫作深度神经网络。从海量的数据中进行处理和分析,提炼出物体的特征,建立模型,从而实现处理大量数据,解决复杂的任务。

架构:每个数据与不同权重相乘后加和,加上偏差后激活再将结果传入下一个神经网络。

神经网络架构概述.png

构建一个神经网络需要下面五个步骤:

  1. 准备数据
  2. 定义模型
  3. 训练模型
  4. 评估预测
  5. 做出预测

那么我们怎么高效快速地完成上述五个步骤呢?

卷积神经网络CNN(Convolution Neural Networks)

例:LeNet-5

  1. PyTorch是一款流行的深度学习框架,有着丰富的工具包
  2. 利用PyTorch识别数字
    1. 准备数据:计算机将图片进行分割,将图片转化成数字信息
    2. 定义模型:
      1. 卷积层:把图像变为一系列数据范围为0~1的矩阵。
      2. 池化层:把一张很大的图像压缩,变成一张更小更容易计算的图像矩阵。
      3. 全连接层:把处理后的图像转化成一段数据。
    3. 训练模型:
      1. 将训练数据输入模型并计算损失并调整更新参数。重复进行多个周期后直到模型能够很好地识别数字。
      2. 损失函数:交叉熵损失(Cross Entropy Loss)
      3. 优化器:随机梯度下降(SGD)
    4. 评估模型+预测

LeNet-5.png

  1. 卷积层(Convolutions):提取特征
  2. 池化层(Subsampling):将特征提取到最突出的元素
  3. 全连接层(Full connection):最后OUTPUT为一个十维向量,每一维代表一个数字类别的预测概率

PyTorch实操

验证/安装pytorch

1
2
import torch
print(torch.__version__) # torch.__version__ 返回安装的 PyTorch 的版本号
2.3.0+cpu

准备数据

  1. 数据下载:将数据变为适合神经网络模型训练的格式
  2. 加载数据:经过预处理,使得数字都位于图像的中心位置,手写数据分类
1
2
3
4
5
6
7
8
from torchvision.datasets import MNIST
from torchvision.transforms import ToTensor
# 定义保存或加载数据集的位置
path = '~/.torch/datasets/mnist'

# 下载并定义数据集
train = MNIST(path, train=True, download=True, transform=ToTensor())
test = MNIST(path, train=True, download=True, transform=ToTensor())
  1. 处理图像数据
    PIL图像:以像素数组的形式保存,每个像素点数字范围为0~1,这样就会有无限的精度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PIL import Image
import torchvision.transforms as transforms

# Load the image using PIL
image_path = './personal/1.png'
image = Image.open(image_path)

# Convert the image to a PyTorch tensor
transform = transforms.ToTensor()
tensor = transform(image)

print(image)

# Check the tensor shape to confirm conversion
tensor.shape, tensor.dtype # (torch.Size([3, 1024, 1024]), torch.float32)
<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=1920x1200 at 0x1B6D50F8F10>





(torch.Size([4, 1200, 1920]), torch.float32)
  1. 数据集划分:
    将数据划分为更小的batch(子数据集),增加处理大量数据的效率
    通过枚举的方式进行训练
1
2
3
4
# 定义如何枚举数据集
from torch.utils.data import DataLoader
train_dl = DataLoader(train, batch_size=64, shuffle=True)
test_dl = DataLoader(test, batch_size=1024,shuffle=False)

定义模型

特征提取

  1. 卷积:将矩阵和一组权重相乘,生成一个新的二维数组
    1. 卷积核(kernel),对某个局部的加权求和,决定了权重矩阵
    2. 特征图(feature map),一个特征图对应一个图像的一个特征
    3. 不同的卷积核和同一个卷积组合,生成了不同的特征图,这些二维的特征图实际上实现了一个三维的卷积层。层数越高,可以识别的特征越高级
    4. 层与层之间会有若干个卷积核,上一层的每个特征图跟每个卷积核做卷积,都会产生下一层的一个特征图
    5. 输入的特征图也可以是多个,例如RGB
  2. 池化:
    1. 逐渐缩小表示空间的大小以提高计算效率
    2. 会单独对每个特征图进行运算
    3. 常用方法:最大池化
  3. 全连接层:
    1. 对前面卷积层提取的特征进行整合,以进行最终的分类决策
    2. 将前一层的所有神经元与当前层的每个神经元相连接,从而使网络能够理解并学习到图像更加复杂的特征

  1. 定义继承自Module父类的类CNN
    建立方法__init__

  2. 第一个卷积层使用Conv2d创建二维卷积层,接收n_channels个输入通道,输出32个特征图,使用3X3的卷积核进行卷积运算
    使用kaiming_uniform_方法初始化权重(weight也称为参数),并设置激活函数为relu
    (机器学习的关键是更新每次卷积的权重)

    1. 激活函数,做出是否要传递信息的决定门
      激活函数.jpg
      Relu.jpg
  3. 第一个池化层将特征图分割成2X2大小的区域,并从每个区域中取最大值(最大池化)
    stride(2,2)是池化操作的步长

    这意味着池化窗口每次移动两个像素,有效减少了特征图的维度

    最大池化.jpg
    作用:

    • 保留了最大特征的同时减少了尺寸
    • 减少过拟合,减少泛化能力
  4. 第二层卷积层的作用是进一步提取池化层的特征,需要注意的是Conv2d的第一个参数由n_channels变成了32,这是因为这里的输入是第一层卷积层的输入

这意味着我们从32个3x3的卷积核中进行操作,并将从每个位置的3x3区域提取特征,并输出32个新的特征通道

  1. 第二层池化的作用:
    • 通过减少特征图的空间尺寸,来降低后续网络层的计算负载
    • 在一定程度上增强模型的抗噪声能力

通过这两层的连续操作,我们的CNN能够逐渐抽象图像内容,将原始输入转化为高级特征,从而对后续的分类或其他任务提供必要的信息
全连接层.jpg

  1. 第一个全连接层将5x5x32个线索转化为100个有意义的概念

    • 使用kaiming_uniform来初始化这个处理中心的连接权重
    • RELU激活函数引入了一种非线性的思考方式,让神经网络捕捉到更加复杂的模式和联系
  2. 第二个全连接层将提炼出的100个概念进一步简化为10个最终的决策,每一个决策都对应着一个手写数字的类别(0~9)

    1. 使用xavier_uniform_的方法来初始化每个连接的权重
      • 使神经网络的网既不是太紧也不是太松–权重适中,柔韧性与强度兼得
      • 如果权重过大–神经网络僵硬,难以捕捉细微的特征
      • 如果权重过小–神经网络松散,容易错过重要的模式
      • xavier_uniform_通过初始化权重为一个均匀分布的值,帮助神经网络一开始时就保持了一种平衡状态
    2. Softmax为激活函数,它将决策中心的输出转换为概率分布。使神经网络能够根据概率最高的类别来做出最终的预测
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from torch.nn import Module

class CNN(Module):
# 定义模型属性
def __init__(self, n_channels):
super().__init__()
# 输入到卷积层 1
self.hidden1 = Conv2d(n_channels, 32, (3,3))
kaiming_uniform_(self.hidden1.weight, nonlinearity='relu')
self.act1 = ReLU()
# 池化层 1
self.pool1 = MaxPool2d((2,2), stride=(2,2))
# 卷积层 2
self.hidden2 = Conv2d(32, 32, (3, 3))
kaiming_uniform_(self.hidden2.weight, nonlinearity='relu')
self.act2 = ReLU()
# 池化层 2
self.pool2 = MaxPool2d((2,2), stride(2,2))
# 全连接层 1
self.hidden3 = Linear(5*5*32, 100)
kaiming_uniform_(self.hidden3.weight, nonlinearity='relu')
self.act3 = RELU()
# 全连接层 2
self.hidden4 = Linear(100, 10)
xavier_uniform_(self.hidden4.weight)
self.act4 = Softmax(dim=1)

前向传播

定义

  1. 指数据在神经网络中的流动方向
  2. 输入层 -> 隐藏层 -> 输出层
  3. 在卷积神经网络中起到关键作用

目的

  • 计算输出: 根据输入数据和网络结构计算神经网络的输出
  • 损失函数评估: 使用输出数据与真实标签计算损失函数,以评估模型的性能
  • 反向传播准备: 为反向传播阶段提供必要的中间信息,如每层的输入、权重和激活函数的导数等

反向传播

目的是计算损失函数关于网络参数的梯度,以便通过梯度下降等优化算法更新网络的权重,从而改进模型的性能

前向传播是路径上执行具体的数据处理,执行层与层之间的数据传递和参数计算

而模型架构则是定义了前向传播的路径和操作顺序

  • 将数据进行输入进入第一层卷积层进行处理,然后通过激活函数后再进行进一步的池化操作
  • 数据经过进一步的提取特征,减少体积操作。例如特征图体积从(32,15,15)变为(32,7,7)
  • 数据扁平化(Flattening): 将多维的数据结构转化为一维向量形式,使其能够被神经网络处理

  • 全连接层 self.hidden3(X) 将扁平化后的数据传入后,将输入向量与权重矩阵相乘,加上偏置,然后输出结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 前向传播
def forward(self, X):
# 输入到隐层 1
X = self.hidden1(X)
X = self.act1(X)
X = self.pool1(X)
# 隐层 2
X = self.hidden2(X)
X = self.act2(X)
X = self.pool2(X)
# 扁平化
X = X.view(-1, 5*5*32)
# 隐层 3
X = self.hidden3(X)
X = self.act3(X)
# 输出层
X = self.hidden4(X)
X = self.act4(X)
return X

损失函数

提供了一个预测结果和真实结果差距有多大的测量标准

优化器

  • 根据损失函数提供的反馈来调整模型参数
  • 决定了如何以最有效的方式更新参数以最小化损失函数

最小梯度下降

  • 最基本
  • 在处理复杂损失面的情况下可能陷入收敛慢或局部最优

Adam优化器

  • 通过自适应学习率标准,常能更快地收敛到全局最优或者较优的解

下面使用交叉熵损失函数和随机梯度下降作为优化器

交叉熵损失函数

  • 分类问题中常用的损失函数
  • 衡量了预测概率分布和实际标签分布之间的差异
  • 可以有效处理概率输出,并且在数学上可以解释为最大似然估计

随机梯度下降优化器

  • model.parameters() 表示优化器将更新所有模型的运行参数
  • 学习率(learning rate)决定了每次参数更新的步长大小
  • 动量(momentum)通过在更新方向上加速,帮助优化器在鞍点附近更快收敛,并减小震荡

训练周期 epoch

  • 一个epoch指模型训练时一次完整的前向传播和反向传播的过程
  • 多次遍历可以使模型更好地学习数据的特征

训练损失 Train Loss

  • 模型在训练数据集上的平均损失值
  • 训练损失越低,表示模型对训练数据的拟合度越好

训练准确率 Train Acc

  • 衡量模型在训练数据集上预测正确的比例

测试准确率 Test Acc

  • 衡量模型在测试数据集上预测正确的比例
  • 可以很真实地反应模型对未知数据的泛化能力

minibatch

  • 有利于模型的稳定训练,提高计算效率
  • 每个minibatch包含输入数据(inputs)和对应的标签(targets)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def train_model(train_dl, model):
# 定义优化器
criterion = CrossEntropyLoss()
optimizer = SGD(model.parameters(),lr=0.01,momentum=0.9)
# 枚举 epochs
for epoch in range(10):
# 枚举 mini batches
for i, (inputs, targets) in enumerate(train_dl):
# 梯度清除
optimizer.zero_grad()
# 计算模型输出
yhat = model(inputs)
# 计算损失
loss = criterion(yhat,targets)
# 贡献度分配
loss.backward()
# 升级模型权重
optimizer.step()

评估模型

评估误差:

  • 均方误差 (MSE, Mean Squared Error)

    预测值与实际值之间的平均均方误差

  • 均方根误差 (RMSE,Root Mean Squared Error)

RMSE=MSERMSE = \sqrt{MSE}

  • 平均绝对误差 (MAE, Mean Absolute Error)

  • 拟合优度

    值越接近1,模型的解释能力越强

评估指标

对于分类模型而言,评估指标只要衡量模型的分类效果

  • 混淆矩阵G (Confusion Matrix)

    包括TP、TN、FP、FN

    1. TP (True Positive):被判定为正样本,实际上是正样本 -> 真阳性
    2. FN (False Negative):被判定为负样本,实际上是正样本 -> 假阴性
    3. FP (False Positive):被判定为正样本,实际上是负样本 -> 假阳性
    4. TN (True Negative):被判定为负样本,实际上是负样本 -> 真阴性
  • ROC曲线 (Receiver Operating Characteristic Curve)

    横轴表示的是 FPR ,即错误地预测为正例的概率

    纵轴表示的是 TPR ,即正确地预测为正例的概率

FPR=FPFP+TNFPR = \frac {FP} {FP+TN}

TPR=TPTP+FNTPR = \frac {TP} {TP+FN}

  • AOC (Area Under the Curve)

    • 衡量的是ROC曲线下的面积
    • AOC越大,表示当前的分类算法,就越有可能将正样本排在负样本前面,模型的分类性能越好

  • 准确率 (Accuracy)

Accuracy=TP+TNTP+TN+FP+FNAccuracy = \frac {TP+TN}{TP+TN+FP+FN}

  • 精确率 (Precision)

    衡量模型预测为正类的样本中,实际为正类的比率

    适用于假阳性比例较高的情况

Precision=TPTP+FPPrecision = \frac {TP}{TP + FP}

  • 召回率 (Recall)

    衡量模型预测为负类的样本中,实际为负类的比率

    适用于假阴性比例较高的情况

Recall=TPTP+FNRecall = \frac {TP}{TP+FN}

  • F1分数

    一般公认的结合精确率和召回率的指标

F1Score=2PrecisionAccuracyPrecision+AccuracyF1 Score = \frac {2\cdot{Precision}\cdot{Accuracy}} {Precision + Accuracy}

评论