一、神经网络的组成部分
在第一部分中我们了解了 Pytorch 的相关基础知识,在这一篇文章中我将使用 Pytorch 进入深度学习的学习,学习如果使用 Pytorch 搭建神经网络中的一些基础代码,具体讲包含如下内容:
- 神经网络的组成部分
- 神经元
- 神经网络层
- 如何使用 Pytorch 完成数据加载工作以及相应的数据预处理
- 训练神经网络模型并验证
神经网络是一种由多个神经元以一定的方式联结形成的网络结构,是一种仿照生物神经系统结构和功能的人工智能技术。神经网络通常由输入层、输出层和若干个隐藏层组成,每个层包含若干个神经元。
神经网络的基本组成单位是神经元,它模拟了生物神经元的行为特征,包括输入信号的接收、加权求和、非线性激活等过程。神经元接收来自前一层神经元的输入信号,将输入信号进行加权求和,并通过激活函数将结果转换为输出信号,并将输出信号传递给下一层神经元。如图1所示为一个经典的以全连接(Full Connected, FC)方式形成的神经网络,每个圆圈代表一个神经元,圆圈间的连线代表神经元之间的联结。
1. 神经元
神经生物学家Warren MeCulloch和数学家Walter Pitts于1943年提出了一种基于早期的神经元理论学说的人工神经网络模型,称为MP模型(McCulloch-Pitts模型)。该模型是一种具有生物神经元特征的人工神经网络模型,被认为是神经网络研究的开端。
MP模型的基本思想是将神经元视为一个二进制变量,其输出值只能为0或1。神经元接收来自其他神经元的输入信号,通过一个阈值函数对输入信号进行加权和处理,并产生一个二进制输出值。MP模型中的神经元只有两种状态,即兴奋态(输出值为1)和抑制态(输出值为0),通过神经元之间的连接,可以实现复杂的计算功能。MP模型的主要贡献在于将生物神经元的工作原理转化为数学模型,为后续的神经网络研究奠定了基础。虽然MP模型非常简单,但它的基本思想和理论对于神经网络的发展和应用具有重要意义,为人工智能和机器学习的发展奠定了基础。如图2所示为MP神经元模型。
如上图所示,$u_1, ……u_j, ……u_n$是一个$n$维向量,代表与第$i$个神经元相连接的其他神经元传递的信号;$w_{1i}, ….., w_{ji}, ……w_{ni}$分别代表其他神经元和第$i$个神经元之间连接的权重值;代表第$i$个神经元的阈值;$x_i$则称为第$i$个神经元的输入,可表示为如式1所示;$f(x_i)$是非线性函数,如式2所示。
$x_{i}=\sum_{j=1}^{n} w_{j i} u_{i}-\theta_{i}\tag1$
$y_{i}=f\left(x_{i}\right)=f\left(\sum_{j=1}^{n} w_{j i} u_{j}-\theta_{i}\right)\tag2$
神经元通常由以下几个部分组成:
- 输入(Inputs):神经元接收来自其他神经元或外部环境的输入数据。
- 权重(Weights):每个输入都与一个权重相关联,用于调整输入的重要性。
- 激活函数:激活函数将加权输入映射到输出。常用的激活函数包括Sigmoid、ReLU和Tanh等。
- 偏差(Bias):偏差是一个可学习的参数,用于调整神经元输出的阈值。
1 | import torch |
这是一个简单的神经元模型,用 PyTorch 构建。让我解释一下这个模型的结构和功能:
- Neuron 类:是一个继承自 torch.nn.Module 的自定义神经元模型。继承自 torch.nn.Module 的基类允许你定义具有可学习参数的自定义神经网络模型。
- init 方法:这是模型的构造函数,它接受一个参数 input_size,表示输入特征的数量。在这个方法中,模型初始化了两个可学习的参数:weights 和 bias,这两个参数都被包装成 torch.nn.Parameter 对象,以便在模型的训练过程中进行优化。
- weights 是一个形状为 (input_size,) 的可学习权重向量,它与输入特征进行点乘。
- bias 是一个标量值,它用于调整模型的输出。
- forward 方法:这是模型的前向传播方法。在前向传播过程中,输入 inputs 与权重 weights 进行点乘,然后将点乘结果与 bias 相加,得到加权和 weighted_sum。然后,通过 sigmoid 激活函数对加权和进行激活,将结果作为模型的输出返回。
这个神经元模型可以用于二分类问题,其中 input_size 表示输入特征的数量,模型通过学习适当的权重和偏置来进行二元分类。在训练过程中,你可以使用标准的 PyTorch 优化器和损失函数来训练这个模型,以便它能够适应你的分类任务。
2. 神经网络层
神经网络由多个神经元层组成。每一层都由许多神经元组成,并且通常具有相同的结构和激活函数。以下是一些常见的神经网络层类型:
- 全连接层(Fully Connected Layer):每个神经元都与前一层的所有神经元相连接。
- 卷积层(Convolutional Layer):应用卷积操作来提取输入数据中的空间特征。
- 池化层(Pooling Layer):通过减少特征图的大小来降低计算量,并保留重要的特征。
- 循环层(Recurrent Layer):通过在神经网络中引入时间维度来处理序列数据。
以下是一个包含两个全连接层的神经网络示例代码: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
27import torch
# 定义神经网络类,继承自 torch.nn.Module
class NeuralNetwork(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(NeuralNetwork, self).__init__()
# 定义第一个全连接层,输入大小为 input_size,输出大小为 hidden_size
self.fc1 = torch.nn.Linear(input_size, hidden_size)
# 定义第二个全连接层,输入大小为 hidden_size,输出大小为 output_size
self.fc2 = torch.nn.Linear(hidden_size, output_size)
def forward(self, inputs):
# 使用 ReLU 激活函数计算第一个全连接层的输出
hidden = torch.relu(self.fc1(inputs))
# 使用 sigmoid 激活函数计算第二个全连接层的输出,最终的模型输出
output = torch.sigmoid(self.fc2(hidden))
return output
# 创建一个具有2个输入、3个隐藏神经元和1个输出的神经网络
net = NeuralNetwork(2, 3, 1)
# 输入数据
inputs = torch.tensor([0.5, -0.3])
# 计算输出
output = net(inputs)
print(output)
3. 损失函数
神经网络的目标是最小化预测输出与真实标签之间的差异。损失函数衡量了这种差异,并提供一个可优化的目标。常见的损失函数包括均方误差(Mean Squared Error)、交叉熵损失(Cross-Entropy Loss)等。
- 均方误差(Mean Squared Error,MSE):计算预测值与目标值之间的平方差的平均值。
- 交叉熵损失(Cross-Entropy Loss):在分类问题中,计算预测概率分布与真实标签之间的交叉熵。
以下是一个使用均方误差作为损失函数的示例:1
2
3
4
5
6
7
8
9
10import torch
# 随机生成一些示例数据
predictions = torch.tensor([0.9, 0.2, 0.1])
labels = torch.tensor([1.0, 0.0, 0.0])
# 计算均方误差损失
loss_function = torch.nn.MSELoss()
loss = loss_function(predictions, labels)
print(loss)
4. 优化器
优化器用于更新神经网络的参数以最小化损失函数。它使用梯度下降算法来调整参数的值。常见的优化器包括随机梯度下降(Stochastic Gradient Descent,SGD)、Adam等。
以下是一个使用Adam优化器进行参数更新的示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import torch
# 创建一个神经网络和损失函数
net = NeuralNetwork(2, 3, 1)
loss_function = torch.nn.MSELoss()
# 创建一个Adam优化器
optimizer = torch.optim.Adam(net.parameters(), lr=0.01)
# 输入数据和真实标签
inputs = torch.tensor([0.5, -0.3])
labels = torch.tensor([1.0])
# 前向传播
output = net(inputs)
loss = loss_function(output, labels)
# 反向传播和参数更新
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(loss)
通过理解和应用这些神经网络的组成部分,能够构建和训练自己的深度学习模型。
二、PyTorch中的层
在PyTorch中,神经网络层(Layers)是神经网络的基本组成部分,用于对输入数据进行转换和提取特征。PyTorch提供了丰富的层类型和功能,使得构建和训练深度学习模型变得更加便捷和灵活。这里将介绍PyTorch中的一些常用层,并提供示例代码来帮助读者理解和学习。
目录
- 全连接层(Fully Connected Layer)
- 卷积层(Convolutional Layer)
- 池化层(Pooling Layer)
- 循环神经网络层(Recurrent Neural Network Layer)
- 转置卷积层(Transpose Convolutional Layer)
- 归一化层(Normalization Layer)
- 激活函数层(Activation Function Layer)
- 损失函数层(Loss Function Layer)
- 优化器层(Optimizer Layer)
1. 全连接层
全连接层,也被称为线性层或密集层,是最简单的神经网络层之一。它将输入的每个元素与权重相乘,并加上偏置项,然后通过激活函数进行非线性变换。全连接层的输出形状由其输入形状和输出维度确定。
下面是一个创建全连接层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13import torch
import torch.nn as nn
# 定义输入和输出维度
input_size = 784
output_size = 10
# 创建全连接层
fc_layer = nn.Linear(input_size, output_size)
# 打印全连接层的权重和偏置项
print("权重:", fc_layer.weight)
print("偏置项:", fc_layer.bias)
2. 卷积层
卷积层是卷积神经网络中的核心层之一,用于从输入数据中提取空间特征。卷积层通过滑动窗口(卷积核)在输入上进行局部感知,并输出对应的特征图。PyTorch中的卷积层包括二维卷积层和三维卷积层,分别用于处理二维和三维数据。
下面是一个创建二维卷积层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14import torch
import torch.nn as nn
# 定义输入通道数、输出通道数和卷积核大小
in_channels = 3
out_channels = 16
kernel_size = 3
# 创建二维卷积层
conv_layer = nn.Conv2d(in_channels, out_channels, kernel_size)
# 打印二维卷积层的权重和偏置项
print("权重:", conv_layer.weight)
print("偏置项:", conv_layer.bias)
3. 池化层
池化层用于减小特征图的空间维度,降低模型的参数数量,并增强模型的平移不变性。最大池化和平均池化是常用的池化方式,它们分别选择局部区域中的最大值和平均值作为输出。
下面是一个创建最大池化层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13import torch
import torch.nn as nn
# 定义池化区域大小和步幅
kernel_size = 2
stride = 2
# 创建最大池化层
pool_layer = nn.MaxPool2d(kernel_size, stride)
# 打印最大池化层的参数
print("池化区域大小:", pool_layer.kernel_size)
print("步幅:", pool_layer.stride)
4. 循环神经网络层
循环神经网络(Recurrent Neural Network, RNN)层用于处理序列数据,具有记忆性和上下文感知能力。RNN层通过在时间步之间共享权重,实现对序列的逐步处理,并输出相应的隐藏状态。
下面是一个创建RNN层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import torch
import torch.nn as nn
# 定义输入特征维度、隐藏状态维度和层数
input_size = 10
hidden_size = 20
num_layers = 2
# 创建RNN层
rnn_layer = nn.RNN(input_size, hidden_size, num_layers)
# 打印RNN层的参数
print("输入特征维度:", rnn_layer.input_size)
print("隐藏状态维度:", rnn_layer.hidden_size)
print("层数:", rnn_layer.num_layers)
5. 转置卷积层
转置卷积层,也被称为反卷积层,用于实现上采样操作,将低维特征图转换为高维特征图。转置卷积层通过反向卷积操作将输入特征图映射到更大的输出特征图。
下面是一个创建转置卷积层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14import torch
import torch.nn as nn
# 定义输入通道数、输出通道数和卷积核大小
in_channels = 3
out_channels = 16
kernel_size = 3
# 创建转置卷积层
transconv_layer = nn.ConvTranspose2d(in_channels, out_channels, kernel_size)
# 打印转置卷积层的权重和偏置项
print("权重:", transconv_layer.weight)
print("偏置项:", transconv_layer.bias)
6. 归一化层
归一化层用于调整神经网络的激活值分布,提升模型的收敛速度和泛化能力。常用的归一化层包括批归一化(Batch Normalization)和层归一化(Layer Normalization)。
下面是一个创建批归一化层的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13import torch
import torch.nn as nn
# 定义特征维度
num_features = 16
# 创建批归一化层
bn_layer = nn.BatchNorm2d(num_features)
# 打印批归一化层的参数
print("特征维度:", bn_layer.num_features)
print("均值:", bn_layer.running_mean)
print("方差:", bn_layer.running_var)
7. 激活函数层
激活函数层用于引入非线性变换,增加神经网络的表达能力。常用的激活函数包括ReLU、Sigmoid和Tanh等。
下面是一个使用ReLU激活函数的示例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14import torch
import torch.nn as nn
# 创建激活函数层(ReLU)
activation_layer = nn.ReLU()
# 定义输入张量
input_tensor = torch.randn(10)
# 对输入张量进行激活函数变换
output_tensor = activation_layer(input_tensor)
# 打印输出张量
print("输出张量:", output_tensor)
三、数据加载与预处理
在深度学习任务中,数据的加载和预处理是非常重要的步骤。PyTorch提供了强大的数据加载和预处理工具,使得我们能够高效地处理各种类型的数据。这里将介绍PyTorch中的数据加载和预处理方法,并提供使用示例。
1. 数据加载
PyTorch中的数据加载主要通过torch.utils.data模块实现。该模块提供了Dataset和DataLoader两个核心类,分别用于定义数据集和数据加载器。
🚩Dataset
Dataset类是一个抽象类,用于表示数据集。我们可以继承该类并实现自定义的数据集。在自定义数据集中,我们需要实现两个方法:__len__和__getitem__。__len__方法返回数据集的样本数量,__getitem__方法根据索引返回单个样本。
以下是一个自定义数据集的示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import torch
from torch.utils import data
from torch.utils.data import Dataset
class MyDataset(data.Dataset):
def __init__(self, data_list):
# 初始化数据集
self.data_list = data_list
def __len__(self):
# 返回数据集大小
return len(self.data_list)
def __getitem__(self, index):
# 根据索引获取样本
sample = self.data_list[index]
return sample
在上述示例中,MyDataset类接受一个数据列表作为输入,并实现了__len__和__getitem__方法。
🚩DataLoader
torch.utils.data.DataLoader是PyTorch中一个重要的类,用于高效加载数据集。它可以处理数据的批次化、打乱顺序、多线程数据加载等功能。以下是一个简单的示例:1
2
3
4
5
6
7
8
9
10import torch.utils.data as data
my_dataset = MyDataset([1, 2, 3, 4, 5])
my_dataloader = data.DataLoader(my_dataset,
batch_size=4,
shuffle=True)
for batch in my_dataloader:
print(batch)
在这个示例中,我们首先创建了一个MyDataset实例my_dataset,它包含了一个整数列表。然后,我们使用DataLoader类创建了一个数据加载器my_dataloader,它将my_dataset作为输入,并将数据分成大小为4的批次,并对数据进行随机化。最后,遍历my_dataloader,并打印出每个批次的数据。
总结一下,torch.utils.data.Dataset用于构建数据集,torch.utils.data.DataLoader用于加载数据集,并对数据进行批量处理和随机化。下面是一个完整的示例,展示了如何使用这两个类来加载和处理数据:
1 | import torch.utils.data as data |
除了上述介绍的基本用法,torch.utils.data模块还有许多其他的功能和选项。下面介绍一些常用的选项和功能。
2. 数据预处理
数据预处理是在将数据输入模型之前对数据进行的一系列操作,以提高模型的性能和准确性。PyTorch提供了多种数据预处理方法,包括常见的数据变换、标准化、图像增强等。以下是一些常见的数据预处理方法:
🚩Tensor转换
将数据转换为torch.Tensor类型是数据预处理的第一步。torch.Tensor是PyTorch中表示张量的主要数据类型。1
2
3
4import torch
data = [1, 2, 3, 4, 5]
tensor = torch.tensor(data)
🚩数据变换
数据变换是对数据进行形状调整或维度变换的操作。PyTorch提供了一系列的数据变换方法,如torchvision.transforms模块中的Resize、ToTensor等。
1 | from torchvision import transforms |
🚩数据标准化
数据标准化是对数据进行平均值和标准差的缩放,以使得数据具有零均值和单位方差。这通常用于提高模型的收敛性和稳定性。
1 | import torchvision.transforms as transforms |
🚩图像增强
图像增强是对图像进行变换或添加噪声,以增加训练数据的多样性和鲁棒性。PyTorch提供了torchvision.transforms模块中的多种图像增强方法,如随机裁剪、翻转、旋转等。
1 | import torchvision.transforms as transforms |
本节介绍了PyTorch中的数据加载和预处理方法。通过自定义数据集和数据加载器,我们可以高效地加载和处理数据。同时,PyTorch提供了多种数据预处理方法,如数据变换、标准化和图像增强,以提高模型的性能和准确性。
四、模型训练与验证
1. 模型训练
PyTorch中的模型训练主要涉及以下几个步骤:
- 准备数据:首先,我们需要准备好训练数据和对应的标签。可以使用
torch.utils.data模块中的Dataset和DataLoader类来加载和批量处理数据。 - 定义模型:接下来,我们需要定义模型的结构。可以使用
torch.nn模块中的各种层和模型来构建自己的神经网络模型。 - 定义损失函数:为了训练模型,我们需要定义损失函数来度量模型预测结果与真实标签之间的差异。可以使用
torch.nn模块中的各种损失函数,如均方误差(MSE)、交叉熵损失等。 - 定义优化器:为了更新模型的参数,我们需要选择一个优化器来优化模型的损失函数。可以使用
torch.optim模块中的各种优化器,如随机梯度下降(SGD)、Adam等。 - 训练模型:在每个训练迭代中,我们需要执行以下步骤:
- 前向传播:将输入数据通过模型,得到模型的输出结果。
- 计算损失:将模型的输出结果与真实标签计算损失函数的值。
- 反向传播:根据损失函数的梯度,计算模型参数的梯度。
- 参数更新:使用优化器根据梯度信息更新模型的参数。
以下是一个简单的模型训练示例:
1 | import torch |
在上述示例中,我们使用自定义的数据集和数据加载器准备训练数据,定义了模型、损失函数和优化器,并在每个训练迭代中执行了前向传播、计算损失、反向传播和参数更新的步骤。
2. 模型验证
在模型训练之后,我们需要对模型进行验证以评估其性能和准确性。模型验证的步骤与模型训练类似,但不需要进行参数更新。
以下是一个简单的模型验证示例:
1 | # 准备验证数据 |
在上述示例中,我们使用自定义的验证数据集和数据加载器准备验证数据,并使用model.eval()将模型设置为评估模式。然后,在验证数据上进行前向传播,并根据需要对模型输出进行后处理。
介绍了PyTorch中的模型训练和验证方法。通过准备数据、定义模型、损失函数和优化器,以及执行训练和验证循环,我们可以高效地训练和评估深度学习模型。