一、引言
要深入了解大模型底层原理,先要能手撸transformer模型结构,在这之前,pytorch、tensorflow等深度学习框架必须掌握,之前做深度学习时用的tensorflow,做aigc之后接触pytorch多一些,今天写一篇pytorch的入门文章吧,感兴趣的可以一起聊聊。
PyTorch由facebook人工智能研究院研发,2017年1月被提出,是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。PyTorch既可以看作加入了GPU支持的numpy,同时也可以看成一个拥有自动求导功能的强大的深度神经网络。
PyTorch的前身是Torch,其底层和Torch框架一样,但是使用Python重新写了很多内容,不仅更加灵活,支持动态图,而且提供了Python接口。它是由Torch7团队开发,是一个以Python优先的深度学习框架,不仅能够实现强大的GPU加速,同时还支持动态神经网络。
Pytorch是一个python包,提供两个高级功能:
张量(tensor):可以理解为多位数组,是Pytorch的基本计算单元,Pytorch的特性就是可以基于GPU快速完成张量的计算,包括求导、切片、索引、数学运算、线性代数、归约等
import torch
import torch.nn.functional as F
# 1. 张量的创建
x = torch.tensor([[1, 2, 3], [4, 5, 6]])
y = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(x) #tensor([[1, 2, 3],[4, 5, 6]])
print(y) #tensor([[1, 2, 3],[4, 5, 6]])
# 2. 张量的运算
z=x+y
print(z) #tensor([[2, 4, 6],[8, 10, 12]])
# 3. 张量的自动求导
x = torch.tensor(3.0, requires_grad=True)
print(x.grad) #None
y = x**2
y.backward()
print(x.grad) #tensor(6.)
Pytorch提供了一种独一无二的构建神经网络的方式:动态图机制
不同于TensorFlow、Caffe、CNTK等静态神经网络:网络构建一次反复使用,如果修改了网络不得不重头开始。
在Pytorch中,使用了一种“反向模式自动微分的技术(reverse-mode auto-differentiation)”,允许在零延时或开销的情况下任意更改网络。
这里建议大家采用conda创建环境,采用pip管理pytorch包
1.建立名为pytrain,python版本为3.11的conda环境
conda create -n pytrain python=3.11
conda activate pytrain
2.采用pip下载torch和torchvision包
pip install torch torchvision torchmetrics -i https://mirrors.cloud.tencent.com/pypi/simple
这里未指定版本,默认下载最新版本torch-2.3.0、torchvision-0.18.0以及其他一堆依赖。
动手实现一个三层DNN网络:
这里主要是torch、torch.nn网络、torch.optim优化器、torch.utils.data数据处理等
import torch # 导入pytorch
import torch.nn as nn # 神经网络模块
import torch.optim as optim # 优化器模块
from torch.utils.data import DataLoader, TensorDataset # 数据集模块
引入nn.Module类,编写构造函数定义网络结构,编写前向传播过程定义激活函数。
# 定义三层神经网络模型
class ThreeLayerDNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(ThreeLayerDNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size) # 第一层全连接层
self.fc2 = nn.Linear(hidden_size, hidden_size) # 第二层全连接层
self.fc3 = nn.Linear(hidden_size, output_size) # 输出层
self.sigmoid = nn.Sigmoid() # 二分类输出层使用Sigmoid激活函数
def forward(self, x):
x = torch.relu(self.fc1(x)) # 使用ReLU激活函数
x = torch.relu(self.fc2(x)) # 中间层也使用ReLU激活函数
x = torch.sigmoid(self.fc3(x)) # 二分类输出层使用Sigmoid激活函数
return x
# 数据准备
input_size = 1000 # 输入特征数
hidden_size = 512 # 隐藏层节点数
output_size = 2 # 输出类别数
num_samples = 1000 # 样本数
# 示例数据,实际应用中应替换为真实数据
X_train = torch.randn(num_samples, input_size)
y_train = torch.randint(0, output_size, (num_samples,))
# 数据加载
dataset = TensorDataset(X_train, y_train)
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)
损失函数与优化器是机器学习的重要概念,先看代码,nn来自于torch.nn,optim来自于torch.optim,均为torch封装的工具类
# 实例化模型
model = ThreeLayerDNN(input_size, hidden_size, output_size)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 适合分类问题
optimizer = optim.Adam(model.parameters(), lr=0.001)
损失函数:用于衡量模型预测值与真实值的差距,是模型优化的目标。常见损失函数为
优化器:优化算法用于调整模型参数,以最小化损失函数。常见的优化算法为
模型训练可以简单理解为一个“双层for循环”
第一层for循环:迭代的轮数,这里是10轮 第二层for循环:针对每一条样本,前、后向传播迭代一遍网络,1000条样本就迭代1000次。 所以针对10轮迭代,每轮1000条样本,要迭代网络10*1000=10000次。
# 训练循环
num_epochs = 10
for epoch in range(num_epochs):
model.train() # 设置为训练模式
running_loss = 0.0
for i, (inputs, labels) in enumerate(data_loader, 0):
optimizer.zero_grad() # 清零梯度
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward() # 反向传播
optimizer.step() # 更新权重
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / (i + 1)}')
print('Training finished.')
运行后可以看到loss逐步收敛:
通过引入torchmetrics库对模型效果进行评估,主要分为以下几步
import torchmetrics # 导入torchmetrics
test_num_samples = 200 # 测试样本数
test_X_train = torch.randn(test_num_samples, input_size)
test_y_train = torch.randint(0, output_size, (test_num_samples,))
# 数据加载
test_dataset = TensorDataset(test_X_train,test_y_train)
test_data_loader = DataLoader(test_dataset, batch_size=32, shuffle=True)
# 在模型训练完成后进行评估
# 首先,我们需要确保模型在评估模式下
model.eval()
# 初始化准确率和召回率的计算器
accuracy = torchmetrics.Accuracy(task="multiclass", num_classes=output_size)
recall = torchmetrics.Recall(task="multiclass", num_classes=output_size)
with torch.no_grad(): # 确保在评估时不进行梯度计算
for inputs, labels in test_data_loader:
outputs = model(inputs)
preds = torch.softmax(outputs, dim=1)
# 更新指标计算器
accuracy.update(preds, labels)
recall.update(preds, labels)
# 打印准确率和召回率
print(f'Accuracy: {accuracy.compute():.4f}')
print(f'Recall: {recall.compute():.4f}')
print('Evaluation finished.')
运行后,可以输出模型的准确率与召回率,由于采用随机生成的测试数据且迭代轮数较少,具体数值不错参考,可以根据自己需要丰富数据。
附可以直接运行的代码,先跑起来,再一行行研究!
import torch # 导入pytorch
import torch.nn as nn # 神经网络模块
import torch.optim as optim # 优化器模块
from torch.utils.data import DataLoader, TensorDataset # 数据集模块
# 定义三层神经网络模型
class ThreeLayerDNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(ThreeLayerDNN, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size) # 第一层全连接层
self.fc2 = nn.Linear(hidden_size, hidden_size) # 第二层全连接层
self.fc3 = nn.Linear(hidden_size, output_size) # 输出层
self.sigmoid = nn.Sigmoid() # 二分类输出层使用Sigmoid激活函数
def forward(self, x):
x = torch.relu(self.fc1(x)) # 使用ReLU激活函数
x = torch.relu(self.fc2(x)) # 中间层也使用ReLU激活函数
x = torch.sigmoid(self.fc3(x)) # 二分类输出层使用Sigmoid激活函数
return x
# 数据准备
input_size = 1000 # 输入特征数
hidden_size = 512 # 隐藏层节点数
output_size = 2 # 输出类别数
num_samples = 1000 # 样本数
# 示例数据,实际应用中应替换为真实数据
X_train = torch.randn(num_samples, input_size)
y_train = torch.randint(0, output_size, (num_samples,))
# 数据加载
dataset = TensorDataset(X_train, y_train)
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)
# 实例化模型
model = ThreeLayerDNN(input_size, hidden_size, output_size)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 适合分类问题
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练循环
num_epochs = 10
for epoch in range(num_epochs):
model.train() # 设置为训练模式
running_loss = 0.0
for i, (inputs, labels) in enumerate(data_loader, 0):
optimizer.zero_grad() # 清零梯度
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward() # 反向传播
optimizer.step() # 更新权重
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / len(data_loader)}')
print('Training finished.')
#for param in model.parameters():
# print(param.data)
import torchmetrics # 导入torchmetrics
test_num_samples = 200 # 测试样本数
test_X_train = torch.randn(test_num_samples, input_size)
test_y_train = torch.randint(0, output_size, (test_num_samples,))
# 数据加载
test_dataset = TensorDataset(test_X_train,test_y_train)
test_data_loader = DataLoader(test_dataset, batch_size=32, shuffle=True)
# 在模型训练完成后进行评估
# 首先,我们需要确保模型在评估模式下
model.eval()
# 初始化准确率和召回率的计算器
accuracy = torchmetrics.Accuracy(task="multiclass", num_classes=output_size)
recall = torchmetrics.Recall(task="multiclass", num_classes=output_size)
with torch.no_grad(): # 确保在评估时不进行梯度计算
for inputs, labels in test_data_loader:
outputs = model(inputs)
# 将输出通过softmax转换为概率分布(虽然CrossEntropyLoss内部做了,但这里为了计算指标明确显示)
preds = torch.softmax(outputs, dim=1)
# 更新指标计算器
accuracy.update(preds, labels)
recall.update(preds, labels)
# 打印准确率和召回率
print(f'Accuracy: {accuracy.compute():.4f}')
print(f'Recall: {recall.compute():.4f}')
print('Evaluation finished.')
本文先对pytorch深度学习框架历史、特点及安装方法进行介绍,接下来基于pytorch带读者一步步开发一个简单的三层神经网络程序,最后附可执行的代码供读者进行测试学习。个人感觉网络结构部分比tensorflow稍微抽象一点点,不过各有优劣吧,初学者最好对比着学习。下一篇写tensorflow吧,一起讲了大家可以对比着看。