本文为[小白入门Pytorch]学习记录博客
本文主要记录深度学习中的神经网络学习内容,包括理论和代码
在小白入门pytorch(一)中学习了pytorch的基本操作,本篇文章主要是记录使用Pytorch搭建神经网络的基础代码。文章记录的
顺序是按照[小白入门Pytorch]教案二进行的。
了解一下神经网络的历史:神经生物学家Warren MeCulloch和数学家Walter Pitts于1943年提出了一种基于早期的神经元理论学说的人工神经网络模型,称为MP模型(McCulloch-Pitts模型)。该模型是一种具有生物神经元特征的人工神经网络模型,被认为是神经网络研究的开端。
MP模型的基本思想是将神经元视为一个二进制变量,二进制变量很好懂,要么是1,要么是0,1是神经元兴奋和0是神经元抑制,我们将多个神经元进行连接,进行一系列的矩阵运算,就可以实现复杂的计算功能即是神经网络。
神经元通常由以下几个部分组成:
import torch
class Neuron(torch.nn.Module):
def __init__(self, input_size):
# 继承PyTorch中nn.Module类并实现自定义神经元模型Neuron
super(Neuron, self).__init__()
# 定义权重参数,大小为input_size
self.weights = torch.nn.Parameter(torch.randn(input_size))
# 定义偏置参数,大小为1
self.bias = torch.nn.Parameter(torch.randn(1))
# 实现前向传播函数
def forward(self, inputs):
# 计算加权和,点乘输入和权重,然后加上偏置
weighted_sum = torch.sum(inputs * self.weights) + self.bias
# 应用sigmoid函数进行非线性变换,计算输出结果
output = torch.sigmoid(weighted_sum)
return output
# 创建一个Neuron对象,输入大小为3
neuron = Neuron(3)
# 输入层,大小为3的张量
inputs = torch.tensor([0.5, -0.3, 0.1])
# 计算神经元的输出
output = neuron(inputs)
# 打印输出结果
print(output)
输出结果:
tensor([0.3399], grad_fn=<SigmoidBackward0>)
上面这部分代码是定义了一个自定义的神经元模型 Neuron,并计算了神经元的输出,使用Pytorch搭建。
首先,先定义一个定义了一个名为 Neuron 的类,它继承自 torch.nn.Module。该类表示一个神经元模型,并具有两个属性:权重参数 weights 和偏置参数 bias。这些参数在初始化时根据输入大小进行随机初始化。
然后,在 forward 方法中,计算加权和(权重与输入的点乘之和),并添加了偏置。
接下来,应用 sigmoid 激活函数将加权和转化为非线性输出。
最后,输出结果。
神经网络是一种有多个神经元以一定的方式联结形成的网络结构,是一种仿照生物神经网络结构和功能的人工智能技术。
说白了,神经网络中的计算过程就是矩阵运算,当然我这里指的是前线传播的过程。反向传播就是求导。
神经网络的组成: 输入层、多个隐藏层、输出层
以下是一些常见的神经网络层类型:
下面是一个包含两个全连接层的神经网络示例代码:
import 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)
# 准备输入数据,包含2个数值
inputs = torch.tensor([0.5, -0.3])
# 对于输入数据,计算神经网络的输出结果
output = net(inputs)
# 打印输出结果
print(output)
输出结果:
tensor([0.5437], grad_fn=<SigmoidBackward0>)
神经网络的目标是最小化预测输出与真实标签之间的差异。损失函数衡量了这种差异,并提供一个可优化的目标。常见的损失函数包括**均方误差(Mean Squared Error)、交叉熵损失(Cross-Entropy Loss)、对数损失(Log Loss)**等。
以下是一个使用均方误差作为损失函数的示例:
import torch
# 创建预测值张量
predictions = torch.tensor([0.99999, 0.2222, 0.11111])
# 创建标签值张量
labels = torch.tensor([1.0, 1.0, 0.0])
# 实例化均方根误差(MSE)损失函数对象
loss_function = torch.nn.MSELoss()
# 使用损失函数计算预测值和标签值之间的均方根误差
loss = loss_function(predictions, labels)
# 打印均方根误差
print(loss)
输出结果:
tensor(0.2058)
import torch
# 创建一个神经网络和损失函数
net = NeuralNetwork(2, 3, 1) # 创建一个具有2个输入特征、3个隐藏层单元和1个输出的神经网络模型
loss_function = torch.nn.MSELoss() # 均方根误差(MSE)损失函数
# 创建一个优化器
optimizer = torch.optim.Adam(net.parameters(), lr=0.01) # Adam优化器,用于参数更新,学习率为0.01
# 输入数据和真实标签
inputs = torch.tensor([0.1, -0.3]) # 输入数据张量,包含两个特征
labels = torch.tensor([1.0]) # 真实标签张量
# 前向传播
output = net(inputs) # 将输入数据传递给神经网络模型进行前向传播得到预测值
loss = loss_function(output, labels) # 使用损失函数计算预测值和真实标签之间的均方根误差
# 反向传播和参数更新
optimizer.zero_grad() # 清零之前的梯度,避免梯度累积
loss.backward() # 执行反向传播,计算梯度
optimizer.step() # 根据梯度更新网络参数
print(loss) # 打印损失值
输出结果:
tensor(0.2413, grad_fn=<MseLossBackward0>)
神经网络中包括哪些层呢?
1.全连接层(Fully connected Layer)
2.卷积层(Convolutional Layer)
3.池化层(Pooling Layer)
4.循环神经网络层(Recurrent Neural Network Layer)
5.转置卷积层(Transpose Convolutional Layer)
6.归一化层(Normalization Layer)
7.激活函数层(Activation Function Layer)
8.损失函数层(Loss Function Layer)
9.优化器层(optimizer Layer)
import torch
import torch.nn as nn
# 导入PyTorch库
# 定义输入和输出维度
input_size = 784 # 输入特征的数量784
output_size = 10 # 输出特征的数量,表示10个不同的类别
# 创建全连接层
fc_layer = nn.Linear(input_size, output_size) # 创建一个全连接层对象,输入特征数量为784,输出特征数量为10
# 打印全连接层的权重和偏置项
print("权重:", fc_layer.weight) # 打印全连接层的权重,形状为(10, 784)
print("偏置项:", fc_layer.bias) # 打印全连接层的偏置项,形状为(10,)
权重: Parameter containing:
tensor([[ 2.5574e-02, -5.3259e-03, -4.4039e-03, ..., 4.0028e-05,
8.8669e-03, -1.5488e-02],
[ 9.5699e-04, 1.1061e-03, 1.3532e-02, ..., 2.4001e-02,
3.0188e-03, -1.9964e-02],
[-2.4929e-02, -6.6258e-05, -3.1090e-02, ..., 2.0909e-02,
2.9723e-02, -1.2300e-02],
...,
[-3.3147e-02, -2.1986e-02, 1.3504e-02, ..., 1.5667e-02,
2.0060e-02, 1.2932e-02],
[ 5.0174e-03, 2.7909e-02, -3.5111e-02, ..., 2.7326e-02,
3.1136e-02, -2.1508e-02],
[ 3.4995e-02, -2.9416e-02, 8.9518e-03, ..., 2.4333e-02,
2.5510e-02, 3.4048e-02]], requires_grad=True)
偏置项: Parameter containing:
tensor([ 0.0235, -0.0071, -0.0277, 0.0201, 0.0285, -0.0066, 0.0244, -0.0015,
-0.0274, -0.0254], requires_grad=True)
import torch
import torch.nn as nn
# 定义输入通道数、输出通道数和卷积核大小
in_channels = 3 # 输入图像的通道数,比如RGB图像的通道数为3
out_channels = 10 # 输出特征图的通道数,决定了卷积层的深度
kernel_size = 3 # 卷积核的大小,可以是一个整数或者一个元组(高度,宽度)
# 创建二维卷积层
conv_layer = nn.Conv2d(in_channels, out_channels, kernel_size) # 创建一个二维卷积层对象,指定输入通道数、输出通道数和卷积核大小
# 打印二维卷积层的权重和偏置项
print("权重:", conv_layer.weight) # 打印卷积层的权重,形状为(10, 3, 3, 3),表示10个输出通道,每个通道对应一个3x3的卷积核,输入通道数为3
print("偏置项:", conv_layer.bias) # 打印卷积层的偏置项,形状为(10,),表示10个输出通道各自的偏置项
权重: Parameter containing:
tensor([[[[-0.1345, -0.1756, -0.1378],
[-0.1873, 0.0453, 0.1870],
[-0.0587, -0.1824, 0.0206]],
[[-0.0236, 0.0837, -0.1119],
[ 0.1802, -0.0412, 0.0246],
[ 0.0555, -0.1600, -0.1051]],
[[ 0.0305, -0.1235, 0.1504],
[ 0.1417, -0.1083, -0.1260],
[ 0.1019, 0.0467, -0.0930]]],
[[[ 0.0049, 0.1599, -0.0155],
[ 0.1395, 0.1167, 0.0457],
[ 0.1842, 0.1533, 0.1551]],
[[ 0.0357, -0.0851, 0.0223],
[-0.1629, 0.1369, 0.0167],
[ 0.1904, 0.0222, -0.1388]],
[[-0.0846, -0.1352, -0.0039],
[ 0.0290, 0.1842, -0.1837],
[ 0.0431, 0.1595, -0.0067]]],
[[[-0.1126, -0.0355, -0.1463],
[ 0.0333, 0.0095, 0.0695],
[-0.0106, -0.0312, -0.1256]],
[[ 0.1589, 0.0826, 0.0012],
[-0.1898, 0.0701, 0.1293],
[ 0.1104, 0.1357, -0.0181]],
[[-0.0141, 0.0343, 0.1184],
[ 0.0223, 0.1064, 0.1161],
[-0.1302, -0.0461, 0.1534]]],
[[[-0.1347, 0.0752, -0.0799],
[ 0.1490, 0.1549, 0.1169],
[ 0.0238, -0.0565, 0.1537]],
[[-0.0109, 0.1576, -0.1237],
[-0.1440, -0.0062, 0.1227],
[ 0.1083, 0.0711, -0.1654]],
[[ 0.1691, -0.0773, -0.1273],
[ 0.0252, 0.0923, 0.1173],
[ 0.1610, 0.1237, 0.0340]]],
[[[ 0.0421, -0.0296, -0.0942],
[ 0.1319, -0.0052, 0.1092],
[ 0.0359, 0.1117, -0.1803]],
[[ 0.1128, 0.0074, 0.1556],
[-0.1156, -0.1290, -0.0532],
[-0.1897, -0.0241, 0.0173]],
[[ 0.1492, 0.0639, 0.0156],
[-0.1848, 0.0436, 0.1843],
[ 0.1261, -0.1529, -0.0433]]],
[[[-0.0377, -0.1315, 0.1441],
[ 0.1290, 0.1604, 0.1032],
[-0.1481, -0.0640, -0.1081]],
[[-0.0525, 0.1381, -0.0980],
[-0.0356, -0.1787, 0.0579],
[ 0.0794, -0.0317, 0.1197]],
[[ 0.0696, -0.1164, -0.1332],
[-0.0522, 0.1866, -0.1177],
[ 0.0478, -0.1263, -0.0446]]],
[[[-0.0707, 0.0787, 0.0932],
[-0.0645, -0.0981, 0.1409],
[ 0.0830, -0.0724, 0.0160]],
[[-0.0663, -0.1531, 0.0385],
[-0.0376, -0.0028, 0.0165],
[ 0.1408, 0.0061, -0.0085]],
[[ 0.1485, -0.0885, -0.0300],
[ 0.0784, 0.1103, -0.1027],
[-0.1513, -0.1135, 0.1773]]],
[[[ 0.1529, 0.0545, 0.0845],
[-0.0492, 0.0263, 0.0706],
[ 0.1417, -0.0234, 0.1385]],
[[-0.1917, -0.1262, -0.1102],
[ 0.0726, 0.1231, 0.0764],
[-0.0670, 0.0726, 0.0026]],
[[ 0.0701, -0.1172, -0.0528],
[-0.0076, -0.0333, -0.0411],
[-0.0275, -0.0982, 0.0640]]],
[[[-0.1637, 0.1234, 0.1289],
[-0.0831, -0.0061, 0.0587],
[-0.0125, -0.1588, -0.0585]],
[[ 0.1838, 0.1203, -0.1888],
[-0.1113, -0.0859, 0.1053],
[ 0.0857, -0.1597, 0.0186]],
[[ 0.1576, -0.1528, 0.1484],
[ 0.0019, 0.0216, -0.0182],
[-0.1688, -0.1134, 0.1220]]],
[[[ 0.1687, -0.0447, -0.0339],
[-0.1022, -0.1690, 0.0198],
[-0.1686, -0.1009, -0.0762]],
[[ 0.0394, 0.0816, 0.0880],
[ 0.0414, -0.0767, 0.1095],
[ 0.1279, -0.0704, -0.0042]],
[[-0.1413, 0.0231, -0.1731],
[-0.1102, 0.1115, 0.1701],
[-0.0567, -0.1341, 0.0511]]]], requires_grad=True)
偏置项: Parameter containing:
tensor([ 0.0481, -0.1906, -0.1884, 0.0912, -0.0207, 0.1297, -0.1344, 0.0010,
-0.1730, -0.1730], requires_grad=True)
import torch
import torch.nn as nn
# 导入PyTorch库
# 定义池化层区域大小和步幅
kernel_size = 2 # 池化区域的大小,可以是一个整数或者一个元组(高度,宽度)
stride = 2 # 步幅,控制池化操作移动的步长
# 创建池化层
pool_layer = nn.MaxPool2d(kernel_size, stride) # 创建一个最大池化层对象,指定池化区域的大小和步幅
# 打印最大池化层的参数
print('池化区域大小:', pool_layer.kernel_size) # 打印池化区域的大小,形状为(2, 2),表示高度和宽度均为2的池化区域
print('步幅:', pool_layer.stride) # 打印步幅,形状为(2, 2),表示在高度和宽度方向上的步幅均为2
池化区域大小: 2
步幅: 2
import torch
import torch.nn as nn
# 定义输入特征维度、隐藏状态维度和层数
input_size = 10 # 输入特征的维度,也就是每个时间步的输入数据的大小
hidden_size = 20 # 隐藏状态的维度,决定了RNN层的输出大小
num_layers = 2 # RNN层的层数,决定了RNN的深度
# 创建RNN层
rnn_layer = nn.RNN(input_size, hidden_size, num_layers) # 创建一个RNN层对象,指定输入特征维度、隐藏状态维度和层数
# 打印RNN层的参数
print('输入特征维度:', rnn_layer.input_size) # 打印输入特征维度,即为10
print('隐藏状态维度:', rnn_layer.hidden_size) # 打印隐藏状态维度,即为20
print('层数:', rnn_layer.num_layers) # 打印层数,即为2
输入特征维度: 10
隐藏状态维度: 20
层数: 2
import 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) # 打印转置卷积的权重,形状为(16, 3, 3, 3),表示有16个卷积核,每个卷积核的形状为(3, 3, 3)
print("偏置项:", transconv_layer.bias) # 打印转置卷积的偏置项,形状为(16,),表示有16个偏置项,每个偏置项对应一个卷积核
import torch
import torch.nn as nn
# 定义特征维度
num_features = 16 # 特征的维度,即特征的深度
# 创建批归一化层
bn_layer = nn.BatchNorm2d(num_features) # 创建一个批归一化层对象,指定特征维度
# 打印批归一化层的参数
print('特征维度:', bn_layer.num_features) # 打印特征维度,即为16
print("均值:", bn_layer.running_mean) # 打印批归一化层的均值,初始化为全零
print('方差:', bn_layer.running_var) # 打印批归一化层的方差,初始化为全零
特征维度: 16
均值: tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
方差: tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
import 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)
输出张量: tensor([0.0000, 0.0000, 1.6909, 0.0000, 0.0000, 0.0000, 0.0000, 0.9084, 0.0000,
0.0000])
import 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__方法
import torch.utils.data as data
# 创建MyDataset实例my_dataset,它包含了一个整数列表。
my_dataset = MyDataset([1, 2, 3, 4, 5, 6, 7, 8, 9])
# 使用DataLoader类创建一个数据加载器my_dataloader,它将my_dataset作为输入,并将数据分成大小为4的批次,并对数据进行打乱随机化。
my_dataloader = data.DataLoader(my_dataset,
batch_size=4,
shuffle=True)
# 遍历my_dataloader,打印每个批次的数据
for batch in my_dataloader:
print(batch)
tensor([4, 2, 5, 8])
tensor([1, 3, 9, 6])
tensor([7])
Pytorch中模型训练主要包括以下几个步骤:
掌握这几个步骤,你就知道怎么进行模型训练了
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
train_data = np.arange(512)
# 准备数据
train_dataset = MyDataset(train_data)
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)
# 定义模型
model = MyModel() # 注:这里的MyModel()需要自己去写一个模型,我这里没有写
# 定义损失函数
loss_fn = nn.CrossEntropyLoss()
# 定义优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练模型
for epoch in range(num_epochs):
for batch in train_dataloader:
inputs, labels = batch
# 前向传播
outputs = model(inputs)
# 计算损失
loss = loss_fn(outputs, labels)
# 反向传播
optimizer.zero_grad() # 梯度清零
loss.backward()
# 参数更新
optimizer.step()
# 准备验证数据
val_dataset = MyDataset(val_data)
val_dataloader = DataLoader(val_dataset, batch_size=64)
# 模型验证
model.eval() # 设置模型为评估模式
with torch.no_grad(): # 禁止梯度计算
for batch in val_dataloader:
inputs, labels = batch
#前向传播
outputs = model(inputs)
以上介绍了深度学习中的神经网络,以及搭建神经网络所需要的步骤。