Pytorch 的神经网络 学习笔记

发布于:2024-04-27 ⋅ 阅读:(24) ⋅ 点赞:(0)

参照官方网址

Module — PyTorch 2.2 documentation

一. 介绍

1. torch.nn模块

torch.nn是PyTorch中专门用于构建神经网络的模块。它提供了构建深度学习模型所需的所有构建块,包括各种层类型(如全连接层、卷积层、循环层等)、激活函数、损失函数等。

2.nn.Module

nn.Module是所有神经网络模块和层的基类。自定义的网络模型通常通过继承nn.Module类来创建。在这个类中,你需要定义__init__方法来初始化网络层,以及forward方法来指定数据如何通过这些层。

3. 层(Layers)

PyTorch提供了多种预定义的层,可以直接用于构建神经网络。例如:

  • nn.Linear:全连接层(线性层)。
  • nn.Conv2d:二维卷积层,用于图像处理。
  • nn.LSTM:长短期记忆网络层,用于处理序列数据。
  • nn.ReLUnn.Sigmoidnn.Tanh等:激活函数层。

4. 损失函数(Loss Functions)

损失函数用于计算模型输出与真实标签之间的差异。PyTorch提供了多种损失函数,如:

  • nn.MSELoss:均方误差损失,常用于回归任务。
  • nn.CrossEntropyLoss:交叉熵损失,常用于分类任务。
  • nn.BCEWithLogitsLoss:带有Sigmoid的二元交叉熵损失。

5. 优化器(Optimizers)

PyTorch通过torch.optim模块提供了多种优化算法来更新网络的权重。这些优化器包括:

  • optim.SGD:随机梯度下降。
  • optim.Adam:基于自适应矩估计的优化算法。
  • optim.RMSprop:均方根传播优化算法。

6. 数据处理(DH)

如前所述,torch.utils.data.Datasettorch.utils.data.DataLoader是PyTorch中用于处理数据的重要组件。它们帮助你高效地加载和预处理数据,以便用于训练和评估模型。

7. 自动微分(AD)

自动微分(Automatic Differentiation),PyTorch的autograd模块提供了自动微分功能,这是训练神经网络的核心。它允许开发者只需定义前向传播,而后向传播(梯度计算)则由库自动完成。

一个典型的神经网络训练流程包括定义模型结构、选择损失函数和优化器、加载数据、执行前向传播、计算损失、执行反向传播以及更新模型参数。

 8.先写一个最基础的

引入依赖

import torch
from torch import tensor, nn

创建类

class ykModule(nn.Module):

定义最基本的两个函数,首先是init函数,必须要重写父类的init方法

    def __init__(self):
        super().__init__()

然后还有向前传播forward方法,

    def forward(self, input):
        output = input + 1
        return output

创建实例测试,创建对象,创建张量,代入测试

yk = ykModule()
x = torch.tensor(1.0)
output = yk(x)
print(output)

全部代码

import torch
from torch import tensor, nn


class ykModule(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, input):
        output = input + 1
        return output


yk = ykModule()
x = torch.tensor(1.0)
output = yk(x)
print(output)

打印

二. 卷积层

CONV2D 是卷积神经网络(Convolutional Neural Network, CNN)中常见的一种操作。它指的是二维卷积操作(2D Convolution),用于处理二维图像数据。在卷积神经网络中,通过使用卷积操作可以从输入图像中提取特征,并在不同层次上进行特征的抽象和表示。

在 CNN 中,CONV2D 操作通常由一个卷积核(kernel)对输入图像进行滑动计算得到的结果组成。这个操作会将卷积核与输入图像的每个位置进行对应元素相乘,并将结果相加,得到输出特征图。卷积核的参数通常是需要学习的,它决定了卷积操作提取的特征种类和性质。

1. 参数

  1. in_channels(int):输入图像的通道数,即输入图像的深度。对于彩色图像,通常有RGB三个通道,因此该参数为3;对于单通道灰度图像,该参数为1。

  2. out_channels(int):输出特征图的通道数,即卷积核的数量,也是卷积操作产生的特征图的深度。

  3. kernel_size(int或tuple):卷积核的大小。可以是一个整数表示卷积核的高度和宽度相等,也可以是一个元组 (k_height, k_width) 表示卷积核的高度和宽度分别为 k_height 和 k_width

  4. stride(int或tuple,可选):卷积核在输入图像上移动的步长。默认值为1,表示每次移动一个像素;可以是一个元组 (s_height, s_width) 表示垂直方向和水平方向的步长分别为 s_height 和 s_width

  5. padding(int、tuple或str,可选):在输入图像的四个边缘添加的零填充的数量,用于控制卷积操作的输出尺寸与输入尺寸的关系。默认值为0,表示不进行零填充;可以是一个整数表示在所有边缘添加相同数量的填充,也可以是一个元组 (pad_height, pad_width) 表示在垂直方向和水平方向的填充数量分别为 pad_height 和 pad_width

  6. padding_mode(str,可选):零填充的方式。可选值有 ‘zeros’(默认)、‘reflect’、‘replicate’ 或 ‘circular’。

  7. dilation(int或tuple,可选):卷积核内部元素之间的空间间隔,用于控制卷积核的感受野(receptive field)。默认值为1,表示卷积核内部元素之间没有空隙;可以是一个元组 (d_height, d_width) 表示垂直方向和水平方向的空间间隔分别为 d_height 和 d_width

  8. groups(int,可选):分组卷积的组数,用于将输入通道分成几组并分别对每组进行卷积操作。默认值为1,表示不使用分组卷积。

  9. bias(bool,可选):是否添加可学习的偏置。默认为True,表示在卷积操作的结果上添加一个可学习的偏置项。

参照了b站土堆的演示图

代码演示

import torch
import torch.nn.functional as F

input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [2, 1, 0, 1, 1],
                      [2, 1, 0, 1, 1]])

ker_nal = torch.tensor([[1, 2, 1],
                        [0, 1, 0],
                        [2, 1, 0]])
# 二维卷积操作需要输入四元素
input = torch.reshape(input, (1, 1, 5, 5))
ker_nal = torch.reshape(ker_nal, (1, 1, 3, 3))
output = F.conv2d(input, ker_nal, stride=1)
print(output)

打印

 将padding设置为1,默认为padding为0,填充的位置值为0

out_channel为2时

2. 卷积层操作

(1)引入库

也可以先写代码,使用pycharm的import引入

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWrite

(2)获取数据集

dataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)

(3)创建数据加载器

loader = DataLoader(dataset, batch_size=64)

(4)创建类

class Yk(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=(3, 3), stride=(1, 1), padding=0)

    def forward(self, x):
        x = self.conv1(x)
        return x

(5)测试

writer = SummaryWriter("../logs")
yk = Yk()
step = 0
for data in loader:
    imgs, targets = data
    output = yk(imgs)
    writer.add_images("input", imgs, step)
    output = torch.reshape(output, (-1, 3, 20, 30))
    print(imgs.shape)
    print(output.shape)
    writer.add_images("output", output, step)

    step = step + 1
writer.close()

三. 池化层

1. 介绍

在PyTorch中,池化层(Pooling layer)是用于卷积神经网络中的一种常见层,主要用于减少数据的空间尺寸(即宽度和高度),从而减少参数的数量和计算量,同时也有助于提取特征中的主要信息,增加模型的抗噪声能力。

常见的池化层类型包括:

  1. 最大池化层(Max Pooling Layer):该层通过从覆盖区域中选择最大值来工作。例如,在一个 2x2 的池化窗口中,它会从四个数字中选择最大的一个。这有助于保留特征中的显著信息。

  2. 平均池化层(Average Pooling Layer):与最大池化相比,平均池化层会计算其覆盖区域的平均值。这使得网络在特征的整体平均响应上更加关注,有时可以减少最大池化可能带来的特征损失。

  3. 全局池化层(Global Pooling Layer):该层通常在网络的末端使用,可以将整个特征图的尺寸减少到 1x1,这通常用于将空间特征映射到类别预测上。

这些池化层在PyTorch中可以通过 torch.nn 模块中的 MaxPool2dAvgPool2d 等类来实现。

2. 参数

  1. kernel_size:池化窗口的大小。如果设置为一个整数,那么池化窗口将是正方形的,即宽度和高度相同。如果设置为一个元组,可以指定不同的宽度和高度。

  2. stride:池化窗口移动的步长。如果未指定,则默认为 kernel_size 的值。步长决定了池化窗口在输入特征图上移动的距离。如果步长小于池化窗口的大小,则池化窗口之间会有重叠;如果步长等于窗口大小,则没有重叠。

  3. padding:在输入特征图的边缘添加的填充。如果设置为一个整数,那么在所有边缘上添加相同数量的填充;如果设置为一个元组,则可以指定在不同边缘上添加不同数量的填充。填充通常用于控制输出特征图的大小。

  4. dilation:控制池化窗口中元素之间的间隔。通常设置为1,表示没有间隔。如果增加dilation值,池化窗口将包含输入特征图中更广泛区域的元素,但实际上并不增加池化窗口的大小。

  5. return_indices:是否返回池化操作中每个最大值的索引。这在使用 torch.nn.MaxUnpool2d 进行上采样时很有用,因为它可以帮助将值放回到正确的位置。

  6. ceil_mode:计算输出尺寸时使用的模式。默认情况下(ceil_mode=False),输出尺寸是通过向下取整计算得到的。如果设置为 True,则使用向上取整。这会影响输出特征图的大小,特别是当输入尺寸不能被池化窗口大小整除时。

整理课堂笔记(土堆)

演示(最大池化)

3. 操作实例

获取数据集,并创建dataloader实例

dataset = torchvision.datasets.CIFAR10("./data", download=False, train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)

创建类

class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, input):
        output = self.maxpool1(input)
        return output

创建对象,并创建writer实例

yk = Yk()
writer = SummaryWriter("../logs")

循环获取批量图片并通过池化层处理

step = 0
for data in dataloader:
    imgs, target = data
    writer.add_images("input", imgs, step)
    output = yk(imgs)
    writer.add_images("output", output, step)
    step = step + 1

最后关闭writer

writer.close()

全部代码

import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("./data", download=False, train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)

    def forward(self, input):
        output = self.maxpool1(input)
        return output


yk = Yk()
writer = SummaryWriter("../logs")
step = 0
for data in dataloader:
    imgs, target = data
    writer.add_images("input", imgs, step)
    output = yk(imgs)
    writer.add_images("output", output, step)
    step = step + 1
writer.close()

展示

四. 非线性激活

1. 介绍

非线性激活函数是神经网络中的一种函数,它的作用是在神经元的输出上引入非线性变换。这种非线性是神经网络能够学习和执行复杂任务的关键因素之一,因为没有非线性激活函数,无论神经网络有多少层,最终都只能表示线性变换,这大大限制了网络的表达能力和复杂度。

非线性激活函数有很多种,以下是一些常用的激活函数:

  1. ReLU (Rectified Linear Unit):目前最流行的激活函数之一,定义为 f(x) = max(0, x)。它的优点是计算简单,能够加快训练速度,并且在正区间内梯度恒定,有助于缓解梯度消失问题。

  2. Sigmoid:早期神经网络中常用的激活函数,定义为 f(x) = 1 / (1 + exp(-x))。它将输入压缩到 (0, 1) 范围内,常用于二分类问题的输出层。然而,它容易导致梯度消失和饱和,且计算相对复杂。

  3. Tanh (Hyperbolic Tangent):类似于 Sigmoid 函数,但将输入压缩到 (-1, 1) 范围内,定义为 f(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))。它的中心化特性使得在某些情况下优于 Sigmoid。

  4. Leaky ReLU:ReLU 的变体,旨在解决 ReLU 在负区间导致的神经元死亡问题。定义为 f(x) = x if x > 0 else alpha * x,其中 alpha 是一个小的正数。

  5. Softmax:常用于多分类问题的输出层,将输入向量转换为概率分布,每个元素的范围在 (0, 1) 之间,且所有元素之和为 1。

  6. Swish:是一种相对较新的激活函数,定义为 f(x) = x * sigmoid(x)。它结合了 Sigmoid 和 ReLU 的特性,实验表明在某些情况下性能优于 ReLU。

非线性激活函数使得神经网络能够捕捉数据中的复杂模式和关系,而不仅仅是简单的线性关系。在设计神经网络时,选择合适的激活函数是非常重要的,因为它会影响网络的学习能力和性能。

2. 操作示例

代码

import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d, ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("./data", download=False, train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset, batch_size=64)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.relu1 = ReLU()
        self.sigmoid1 = Sigmoid()

    def forward(self, input):
        output = self.sigmoid1(input)
        return output


yk = Yk()
writer = SummaryWriter("../logs")
step = 0
for data in dataloader:
    imgs, target = data
    writer.add_images("input", imgs, step)
    output = yk(imgs)
    writer.add_images("output", output, step)
    step += 1
writer.close()

Tensorboard页面展示

五. 归一化

1. 介绍

归一化在数据预处理和机器学习模型设计中扮演着重要角色,主要作用包括:

  1. 提升模型训练效率

    • 归一化通过将输入数据的范围缩放到一个统一的尺度(如0到1或-1到1),有助于提高梯度下降等优化算法的收敛速度。因为它使得所有维度的特征具有相似的尺度,从而避免了某些特征在计算中占主导地位。
  2. 防止数据溢出

    • 在处理具有极端值或不同量级的特征时,未归一化的数据可能导致计算时数值不稳定或溢出。归一化能够减少这种情况的发生。
  3. 提高模型的泛化能力

    • 归一化有助于减少模型在训练数据中的偏见,特别是当数据的某些特征比其他特征具有更大的变数或范围时。这有助于提升模型在新未见数据上的表现。
  4. 满足模型算法的假设要求

    • 某些机器学习算法(如支持向量机SVM和K-最近邻KNN)需要归一化输入数据来保证模型运行正确。这些算法在处理距离计算时尤其敏感,不同的尺度会影响最终的结果。
  5. 使特征之间比较公平

    • 归一化确保没有任何一个特征会由于其值范围较大而对模型的预测结果产生不成比例的影响。

2. 参数

这些参数是批量归一化(Batch Normalization)层在机器学习库如PyTorch中的常见配置项,它们分别控制不同的功能和行为:

  1. num_features (int)

    • 该参数指定输入数据中的特征数量(即通道数C),是批量归一化层需要处理的特征维度。对于卷积层来说,这通常是输入数据的通道数;对于全连接层,则是输入向量的维数。
  2. eps (float)

    • 用于数值稳定性的一个小常数,添加到方差的分母中,防止在方差非常小的情况下除以零的错误发生。默认值通常设为1e-5。
  3. momentum (float)

    • 用于计算运行均值(running_mean)和运行方差(running_var)的动量。这个参数决定了每个批次统计量在更新时保留多少历史信息。如果设置为None,则使用累积移动平均(简单平均),即每次都根据所有过去批次的平均值来更新。
  4. affine (bool)

    • 如果设置为True,则该层将包含可学习的仿射变换参数,即每个特征有其对应的缩放参数(scale/gamma)和偏移参数(shift/beta)。这允许模型在归一化后对数据进行进一步的线性变换。
  5. track_running_stats (bool)

    • 如果设置为True,该层将在训练过程中跟踪(即计算和更新)运行均值和运行方差。这些统计量在模型评估(验证或测试)阶段被用来代替批次统计量。如果设置为False,则该层不会跟踪这些运行统计量,无论在训练还是评估阶段,都将使用当前批次的统计量。

这些参数共同决定了批量归一化层的行为和效果,使得网络训练更加稳定,加快收敛速度,同时提高模型的泛化能力。

六. 线性层

1. 介绍

在 PyTorch 中,线性层(linear layer)是一种常见的神经网络层,也被称为全连接层(fully connected layer)或密集层(dense layer)。线性层的作用是将输入张量与权重矩阵相乘,并添加偏置项,从而实现对输入数据的线性变换。

具体来说,线性层的作用包括:

  1. 线性变换:线性层接收一个输入张量,其形状为 (batch_size, input_size),其中 batch_size 表示批量大小,input_size 表示输入特征的数量。线性层还有一个权重矩阵,其形状为 (input_size, output_size),其中 output_size 表示输出特征的数量。线性层将输入张量与权重矩阵相乘,得到形状为 (batch_size, output_size) 的输出张量。

  2. 添加偏置项:线性层还可以选择是否添加偏置项。偏置项是一个长度为 output_size 的向量,每个元素对应输出张量中的一个特征。偏置项的作用是对线性变换的结果进行平移,从而引入非线性变换,增加模型的表达能力。

线性层通常用于神经网络的隐藏层和输出层,它们能够学习输入数据的线性映射,从而实现特征提取和转换。在深度学习模型中,线性层通常与非线性激活函数(如ReLU、sigmoid、tanh等)结合使用,以增加模型的非线性表达能力。

在 PyTorch 中,可以使用 torch.nn.Linear 类来创建线性层,该类提供了一个简单的接口来定义和初始化线性层的参数。

3. 实例操作

获取数据集,并使用数据加载器

dataset = torchvision.datasets.CIFAR10("./data", train=False, download=True,
                                       transform=torchvision.transforms.ToTensor())
dataLoad = DataLoader(dataset, batch_size=64,drop_last=True)

我建议先计算一下图片的shape(可以先跳过这一步)

for data in dataLoad:
    imgs, targets = data
    print(imgs.shape)

打印得到每一张图片的shape为 torch.Size([64, 3, 32, 32])

创建类

class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.learner1 = Linear(196608, 10)

    def forward(self, input):
        output = self.learner1(input)
        return output

遍历,需要将图片reshape

yk = Yk()
for data in dataLoad:
    imgs, targets = data
    print(imgs.shape)
    # output = torch.reshape(imgs, (1, 1, 1, -1))
    output = torch.flatten(imgs)
    print(output.shape)
    output = yk(output)
    print(output.shape)

运行

全部代码

import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10("./data", train=False, download=True,
                                       transform=torchvision.transforms.ToTensor())
dataLoad = DataLoader(dataset, batch_size=64,drop_last=True)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.learner1 = Linear(196608, 10)

    def forward(self, input):
        output = self.learner1(input)
        return output


yk = Yk()
for data in dataLoad:
    imgs, targets = data
    print(imgs.shape)
    # output = torch.reshape(imgs, (1, 1, 1, -1))
    output = torch.flatten(imgs)
    print(output.shape)
    output = yk(output)
    print(output.shape)

七. 循环层

1. 介绍

在PyTorch中,循环神经网络(RNN)层用于处理序列数据,如文本、时间序列或任何具有序列结构的数据。RNN层在每个时间步接受输入并输出隐藏状态,这个隐藏状态会传递到下一个时间步。这种递归结构使得RNN能够捕捉序列中的时间相关性,并对序列数据进行建模。

RNN在自然语言处理(NLP)中广泛应用,用于文本生成、语言建模、机器翻译等任务。此外,RNN也被用于时间序列分析、股票预测、音频处理等领域。

PyTorch提供了多种类型的RNN层,如nn.RNNnn.LSTMnn.GRU,它们分别对应于标准的RNN、长短期记忆网络(LSTM)和门控循环单元(GRU)。这些不同的层具有不同的内部结构和能力,可以根据具体任务的需求选择适当的RNN类型。

2. 参数

在PyTorch中,循环神经网络(RNN)层的参数意义如下:

  • input_size: 输入 x 中的特征数目。对于文本数据,通常是词嵌入的维度大小;对于时间序列数据,可能是每个时间步的特征数量。

  • hidden_size: 隐藏状态 h 的特征数目,即RNN层的输出大小或者说隐藏层的大小。这个参数决定了模型能够学习和存储的信息量。

  • num_layers: 循环层的数量,即堆叠RNN的层数。如果设置为大于1的值,则会形成一个堆叠的RNN,其中第二个RNN会接收第一个RNN的输出并计算最终结果。

  • nonlinearity: 使用的非线性激活函数,可以选择’tanh’或’relu’。默认为’tanh’。

  • bias: 是否使用偏置项。如果设置为False,则RNN层将不使用偏置权重 ��ℎbih​ 和 �ℎℎbhh​。默认为True。

  • batch_first: 如果为True,则输入和输出张量的形状为(batch, seq, feature),而不是(seq, batch, feature)。注意,这不适用于隐藏状态或单元状态。默认为False。

  • dropout: 如果非零,则在每个RNN层的输出上引入一个Dropout层,除了最后一层以外的所有层都会应用dropout,dropout的概率等于dropout参数值。默认为0,即不应用dropout。

  • bidirectional: 是否使用双向循环神经网络。如果为True,则RNN层将变为双向。默认为False。

这些参数可以根据具体任务的需求进行调整,例如调整隐藏状态的大小、增加层数以增加模型的复杂度、使用双向RNN以捕捉前后文信息等。

八. 正则化层

1. 介绍

PyTorch中的正则化层主要用于帮助神经网络模型避免过拟合,提高模型的泛化能力。常见的正则化层有以下几种:

  1. 批量归一化(Batch Normalization)

    • 功能:在网络的每一个批次数据通过激活函数前,对数据进行标准化处理(即减去均值,除以标准差),使得输出数据更加稳定,加快训练速度,提高模型的收敛速率。
    • 使用场景:通常用在全连接层或卷积层与激活层之间。
  2. 层归一化(Layer Normalization)

    • 功能:与批量归一化类似,但是层归一化不是对批次的特征进行标准化,而是对单个样本中的所有特征进行归一化。这使得层归一化不依赖于批次大小,适用于不稳定批次大小或很小批次的场景。
    • 使用场景:常用在循环神经网络(RNN)中,也可以用在变换器(Transformer)模型中。
  3. Dropout

    • 功能:在训练过程中随机地将网络中的部分权重或激活输出置零,这种随机性帮助减少模型对训练数据的依赖,从而减轻过拟合。
    • 使用场景:可以用在各种类型的网络中,如全连接层、卷积层等。
  4. 权重衰减(L2正则化)

    • 功能:通过在损失函数中添加一项与权重的平方成正比的惩罚项,促使模型学习到更小、更分散的权重值,有助于防止模型过于复杂导致过拟合。
    • 使用场景:通常用于全连接层或卷积层的参数训练中。

这些正则化技术在PyTorch中往往通过在模型定义中添加相应的层或在损失函数中增加额外的项来实现。使用这些方法可以显著提升模型在实际应用中的表现和鲁棒性。

九. transformer 层

1. 介绍

Transformer层是Transformer模型的基本组成部分之一,用于处理序列数据。Transformer模型由多个Transformer层组成,每个Transformer层又由多个子层组成,包括自注意力机制层和前馈神经网络层。

一个标准的Transformer层通常包含以下两个子层:

  1. 自注意力机制层(Self-Attention Layer):这个层允许模型在序列中建立全局依赖关系,即在序列中的每个位置上,模型都能够同时考虑到序列中其他位置的信息。通过计算每个位置与其他位置的相关性得分,自注意力机制可以捕捉序列中不同位置之间的依赖关系。

  2. 前馈神经网络层(Feedforward Neural Network Layer):这个层通常由两个线性层组成,中间经过一个非线性激活函数(如ReLU),用于对每个位置的特征进行非线性变换。这有助于模型学习更复杂的序列表示。

Transformer层的核心思想是通过多头自注意力机制来捕捉序列中的全局依赖关系,并通过前馈神经网络层来进行局部特征的变换和提取。这种结构使得Transformer模型能够有效地处理不同长度的序列数据,并在自然语言处理等任务中取得了显著的成功。

十. 序列 SEQUENTIAL

1. 介绍

在PyTorch中,SEQUENTIAL是一个容器类,它允许将多个层或操作按顺序组合在一起,形成一个神经网络模型。SEQUENTIAL的作用是简化模型的定义和管理。

具体来说,SEQUENTIAL可以用来定义一个由多个层组成的神经网络模型。通过将不同的层按顺序添加到SEQUENTIAL容器中,可以按照特定的顺序依次应用这些层来处理输入数据。

使用SEQUENTIAL的主要好处是简化了模型定义的过程。通过将层按顺序添加到SEQUENTIAL中,可以避免手动定义每个层的输入和输出,以及手动管理层之间的连接。SEQUENTIAL会自动处理这些细节,使得模型定义更加简洁和易于管理。

2. 示例

dilation默认是1,stride默认是1

根据以上流程,创建类并设计流程执行操作

直观写法,把各步骤都写一遍

class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.conv1 = Conv2d(3, 32, 5, padding=2)
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, padding=2)
        self.maxpool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, padding=2)
        self.maxpool3 = MaxPool2d(2)
        self.flatten = Flatten()
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x

测试

yk = Yk()
print(yk)
input = torch.ones((64, 3, 32, 32))
output = yk(input)
print(output.shape)

打印

使用squential简化操作

class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

测试相同

yk = Yk()
print(yk)
input = torch.ones((64, 3, 32, 32))
output = yk(input)
print(output.shape)

打印

可将model展现在Tensorboard

十一. 损失函数和反向传播

在PyTorch中,损失函数和反向传播是神经网络训练的两个核心概念。

1. 损失函数

损失函数(Loss Function),也称为目标函数,是用来衡量模型的预测值与真实值之间差异的指标。它是一个非负实数,损失函数的值越小,表示模型的预测结果与真实结果越接近,模型的性能也就越好,并为我们的更新输出提供一定的依据(反向传播)。PyTorch提供了多种内置的损失函数,常用的有:

  1. 均方误差损失(MSE Loss) - 用于回归任务,计算预测值与真实值之间差的平方的平均值。

    import torch.nn as nn mse_loss = nn.MSELoss()
  2. 交叉熵损失(Cross Entropy Loss) - 用于分类任务,特别是多类分类问题。

    ce_loss = nn.CrossEntropyLoss()
  3. 二元交叉熵损失(Binary Cross Entropy Loss) - 用于二分类问题。

    bce_loss = nn.BCELoss()
  4. L1损失(L1 Loss) - 用于回归任务,计算预测值与真实值之间的绝对差的平均值。

    l1_loss = nn.L1Loss()

2. 反向传播

反向传播(Backpropagation)是训练神经网络中最重要的算法之一,用于计算损失函数对网络参数的梯度。这个过程涉及三个步骤:

  1. 前向传播 - 数据通过网络进行传播,从输入层移动到输出层。

  2. 损失计算 - 在输出层计算预测值和真实值之间的损失。

  3. 反向传播 - 计算损失函数相对于网络参数的梯度,并使用这些梯度通过优化算法(如SGD、Adam等)来更新网络的权重。

在PyTorch中,反向传播可以简单地通过调用.backward()方法来自动完成。示例如下:

import torch

# 创建数据和标签
data = torch.randn(10, 3)
labels = torch.randn(10, 3)

# 定义模型
model = nn.Linear(3, 3)

# 前向传播
predictions = model(data)

# 计算损失
loss = mse_loss(predictions, labels)

# 反向传播
loss.backward()

# 更新模型参数
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
optimizer.step()

以上就是使用PyTorch进行模型训练时涉及到的损失函数和反向传播的基本过程。通过这些工具,我们可以有效地训练各种神经网络,进行各种机器学习任务。

3. 梯度下降

4. 示例

首先获取数据集,并使用dataloader获取,然后创建类,使用各层处理

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
dataloader = DataLoader(dataset, batch_size=64, drop_last=True)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

然后创建损失函数

loss = nn.CrossEntropyLoss()

循环测试,并在处理的最后加上反向传播

yk = Yk()
for data in dataloader:
    imgs, targets = data
    output = yk(imgs)
    result_loss = loss(output, targets)

加上反向传播

    result_loss.backward()

打印

    print(result_loss)

全部代码

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
dataloader = DataLoader(dataset, batch_size=64, drop_last=True)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x


loss = nn.CrossEntropyLoss()
yk = Yk()
for data in dataloader:
    imgs, targets = data
    output = yk(imgs)
    result_loss = loss(output, targets)
    result_loss.backward()
    print(result_loss)

打印测试

十二. 优化器

在PyTorch中,优化器是实现梯度下降(及其变体)的核心组件之一,用于自动更新神经网络的权重和参数以最小化损失函数。PyTorch提供了多种内置优化器,每种优化器都适用于不同的应用场景和具有不同的数学属性。

1. 优化器的作用

优化器的主要作用是根据损失函数相对于网络参数的梯度来更新参数。它们执行以下步骤:

  1. 接收梯度:在模型的反向传播过程后,优化器将接收每个参数的梯度。
  2. 参数更新:根据特定的算法,优化器利用梯度信息来更新网络的权重。

2. 常用的PyTorch优化器

以下是PyTorch中几种常见的优化器:

(1)SGD(随机梯度下降)

  • 最基本的优化器,只要提供梯度和学习率,它就会更新参数。
  • 可选项如动量和权重衰减可以帮助缓解SGD的一些问题(如鞍点和局部最小值)

(2)Adam(Adaptive Moment Estimation)

  • 结合了动量和学习率自适应的优点,通常在很多深度学习应用中表现优异。
  • 维护每个参数的学习率,可以帮助更快地收敛。

(3)RMSprop

  • 类似于Adam,主要区别在于它使用平方梯度的移动平均来调整每个参数的学习率。
  • 适用于非平稳目标和非常噪声的问题。

(4)AdamW

  • 对Adam的修改,它对权重衰减进行了更合理的处理,这在不同的测试中有所改善。
  • 适用于需要正则化的任务,可以防止过拟合。

3. 使用优化器的流程

(1)介绍

在使用PyTorch进行模型训练时,通常的步骤包括:

  1. 定义模型和优化器。
  2. 在一个训练循环中:
    • 执行前向传播得到输出和损失。
    • 执行反向传播得到参数的梯度。
    • 调用优化器的step方法来更新模型的参数。
    • (可选)调用优化器的zero_grad()方法来清除之前的梯度,以避免累积。
for epoch in range(num_epochs):
    for data, target in dataloader:
        optimizer.zero_grad()  # 清除旧的梯度
        output = model(data)   # 前向传播
        loss = loss_function(output, target)  # 计算损失
        loss.backward()        # 反向传播,计算梯度
        optimizer.step()       # 更新参数

通过这些优化器,PyTorch使得神经网络的训练过程不仅更简单,还可以根据不同的应用需求选择最合适的优化算法。

(2)实例

先创建优化器,第一个参数为创建的类的参数,第二个参数为学习速率,然后每轮学习。先清除优化器中保存的上一次迭代的梯度信息,以便进行下一次迭代的梯度更新。计算损失函数对模型参数的梯度,并将梯度信息保存在各个参数的.grad属性中。这一步是通过反向传播算法实现的。根据上一步计算得到的梯度信息,更新模型参数,使损失函数值减小。这一步是通过优化器(如SGD、Adam等)实现的。

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

dataset = torchvision.datasets.CIFAR10("./data", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
dataloader = DataLoader(dataset, batch_size=64, drop_last=True)


class Yk(nn.Module):
    def __init__(self):
        super(Yk, self).__init__()
        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x


loss = nn.CrossEntropyLoss()
yk = Yk()
optim = torch.optim.SGD(yk.parameters(), lr=0.01)
for epoch in range(20):
    running_loss = 0.0
    for data in dataloader:
        imgs, targets = data
        output = yk(imgs)
        result_loss = loss(output, targets)
        optim.zero_grad()
        result_loss.backward()
        optim.step()
        running_loss = result_loss + running_loss
    print(running_loss)

打印结果

可见损失值逐次减小。