PyTorch是一个开源的机器学习库,广泛用于计算机视觉和自然语言处理等应用。它提供了强大的GPU加速的张量计算能力,以及构建深度学习模型的动态计算图。
定义:
1. 张量(Tensor)
在PyTorch中,张量是多维数组的表示,类似于NumPy中的数组,但可以在GPU上进行计算。张量是PyTorch中最基本的数据结构,用于表示数据和模型参数。
2. 动态计算图(Dynamic Computational Graph)
PyTorch使用动态计算图(也称为自动微分系统)来构建和训练神经网络。在这种机制下,计算图在运行时构建,允许更灵活的模型设计和调试。每次执行计算时,都会构建一个新的图,这使得修改模型结构变得容易。
3. 自动微分(Autograd)
PyTorch的自动微分引擎能够自动计算梯度,这对于训练神经网络至关重要。当使用张量进行运算时,PyTorch会自动记录操作,使得反向传播变得简单。
4. 模块(Module)
torch.nn.Module
是所有神经网络模块的基类。通过继承这个类,你可以定义自己的网络层、损失函数和模型。模块可以包含其他模块,支持模型的层次化设计。
5. 参数(Parameter)
在神经网络中,参数是模型的权重和偏置,它们在训练过程中被优化。在PyTorch中,Parameter
是Tensor
的一个子类,用于表示可以学习的参数。
6. 优化器(Optimizer)
优化器用于在训练过程中更新模型的参数。PyTorch提供了多种优化器,如SGD、Adam等,它们根据损失函数的梯度来调整参数。
7. 损失函数(Loss Function)
损失函数用于评估模型的预测与真实值之间的差异。常见的损失函数包括均方误差(MSE)、交叉熵损失(CrossEntropyLoss)等。
8. 数据加载器(DataLoader)
DataLoader
是PyTorch中用于加载数据集的类。它提供了一种简便的方式来迭代数据集,支持批处理、打乱数据和多线程加载。
9. 训练循环(Training Loop)
训练循环是执行模型训练的代码块,通常包括前向传播、计算损失、反向传播和参数更新。
算法步骤
1. 数据准备
使用PyTorch的datasets.MNIST
类加载MNIST数据集,包括训练集和测试集。数据集被转换为PyTorch张量,并使用DataLoader
进行批量加载。
python
# 导入必要的库
import torch.cuda
from torchvision import datasets
from torchvision.transforms import ToTensor
# 加载训练数据集
traning_data = datasets.MNIST(root='data', train=True, download=True, transform=ToTensor())
# 加载测试数据集
test_data = datasets.MNIST(root='data', train=False, download=True, transform=ToTensor())
# 打印训练数据集的大小
print(len(traning_data))
# 导入DataLoader工具,用于创建数据加载器
from torch.utils.data import DataLoader
# 创建训练数据加载器
train_dataloader = DataLoader(traning_data, batch_size=64)
# 创建测试数据加载器
test_dataloader = DataLoader(test_data, batch_size=64)
# 选择设备,优先使用GPU,如果没有GPU则使用CPU
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
# 打印选择的设备
print(f"{device}")
2. 模型构建
定义一个包含四个隐藏层和一个输出层的全连接神经网络。每个隐藏层后都使用Sigmoid激活函数。
python
# 导入PyTorch的神经网络模块
import torch.nn as nn
# 定义神经网络模型
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
# 定义一个展平层,将图像数据展平为一维向量
self.flatten = nn.Flatten()
# 定义四个隐藏层和一个输出层
self.hidden1 = nn.Linear(28 * 28, 512)
self.hidden2 = nn.Linear(512, 256)
self.hidden3 = nn.Linear(256, 128)
self.hidden4 = nn.Linear(128, 64)
self.out = nn.Linear(64, 10)
def forward(self, x):
# 展平输入图像
x = self.flatten(x)
# 通过四个隐藏层进行前向传播
x = self.hidden1(x)
x = torch.sigmoid(x)
x = self.hidden2(x)
x = torch.sigmoid(x)
x = self.hidden3(x)
x = torch.sigmoid(x)
x = self.hidden4(x)
x = torch.sigmoid(x)
# 通过输出层得到最终的预测结果
x = self.out(x)
return x
# 实例化模型并将其转移到选择的设备上
model = NeuralNetwork().to(device)
3.定义训练函数
python
# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
model.train() # 设置模型为训练模式
batch_size_num = 1
for x, y in dataloader:
x, y = x.to(device), y.to(device) # 将数据转移到选择的设备上
pred = model(x) # 进行前向传播
loss = loss_fn(pred, y) # 计算损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
loss_value = loss.item()
if batch_size_num % 400 == 0:
print(f"{loss_value} {batch_size_num}")
batch_size_num += 1
4.定义测试函数
python
# 定义测试函数
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval() # 设置模型为评估模式
test_loss, correct = 0, 0
with torch.no_grad(): # 关闭梯度计算
for x, y in dataloader:
x, y = x.to(device), y.to(device)
pred = model(x)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test result: \n Accuracy: {(100 * correct)}%, Avg loss: {test_loss}")
5. 损失函数和优化器
使用交叉熵损失函数和Adam优化器进行模型训练。在训练过程中,每400个批次输出一次损失值,以监控训练进度。
python
# 定义损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
6. 测试过程
在训练完成后,使用测试数据集评估模型的性能。计算测试集上的准确率和平均损失。
python
# 进行一次训练和测试
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
7. 多轮训练
进行25轮训练,每轮结束后在测试集上评估模型性能。
python
# 进行多个epoch的训练
epochs = 25
for t in range(epochs):
print(f"epoch {t + 1}\n")
train(train_dataloader, model, loss_fn, optimizer)
print("done")
# 在所有训练epoch完成后,再次测试模型的性能
test(test_dataloader, model, loss_fn)
实验结果
算法分析
-
模型结构:本实验使用的是一个简单的全连接神经网络,没有使用卷积层或池化层,这限制了模型对图像特征的提取能力。
-
激活函数:Sigmoid激活函数可能导致梯度消失问题,影响训练效果。可以考虑使用ReLU等其他激活函数。
-
优化器:Adam优化器在大多数情况下表现良好,但根据具体问题,可能需要调整学习率和其他超参数。
-
训练策略:实验中没有使用验证集来调整模型参数,这可能导致过拟合。可以考虑引入验证集来监控模型的泛化能力。
完整代码
python
import torch.cuda
from torchvision import datasets
from torchvision.transforms import ToTensor
traning_data=datasets.MNIST(root='data',train=True,download=True,transform=ToTensor())
test_data=datasets.MNIST(root='data',train=False,download=True,transform=ToTensor())
print(len(traning_data))
# from matplotlib import pyplot as plt
# figure=plt.figure()
# for i in range(9):
# img,label=traning_data[i+59000]
# figure.add_subplot(3,3,i+1)
# plt.title(label)
# plt.axis("off")
# plt.imshow(img.squeeze(),cmap="gray")
# a=img.squeeze()
# plt.show()
from torch.utils.data import DataLoader
train_dataloader=DataLoader(traning_data,batch_size=64)
test_dataloader=DataLoader(test_data,batch_size=64)
device='cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
print(f"{device}")
import torch.nn as nn
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten=nn.Flatten()#展开,创建一个展开对象flatten,输入层
self.hidden1=nn.Linear(28*28,512)
self.hidden2=nn.Linear(512,256)
self.hidden3=nn.Linear(256,128)
self.hidden4=nn.Linear(128,64)
self.out=nn.Linear(64,10)
def forward(self,x):
x=self.flatten(x)
x=self.hidden1(x)
x=torch.sigmoid(x)
x=self.hidden2(x)
x = torch.sigmoid(x)
x = self.hidden3(x)
x = torch.sigmoid(x)
x = self.hidden4(x)
x = torch.sigmoid(x)
x=self.out(x)
return x
model=NeuralNetwork().to(device)
# print(model)
def train(dataloader,model,loss_fn,optimzier):
model.train()
batch_size_num=1
for x,y in dataloader:
x,y=x.to(device),y.to(device)
pred=model.forward(x)
loss=loss_fn(pred,y)
optimzier.zero_grad()
loss.backward()
optimzier.step()
loss_value=loss.item()
if batch_size_num%400==0:
print(f"{loss_value} {batch_size_num}")
batch_size_num+=1
def test(dataloader,model,loss_fn):
size=len(dataloader.dataset)
num_batches=len(dataloader)
model.eval()
test_loss,correct=0,0
with torch.no_grad():
for x,y in dataloader:
x,y=x.to(device),y.to(device)
pred=model.forward(x)
test_loss+=loss_fn(pred,y).item()
correct+=(pred.argmax(1)==y).type(torch.float).sum().item()
a=(pred.argmax(1)==y)
b=(pred.argmax(1)==y).type(torch.float)
test_loss/=num_batches
correct/=size
print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")
loss_fn=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(model.parameters(),lr=0.001)
train(train_dataloader,model,loss_fn,optimizer)
test(test_dataloader,model,loss_fn)
epochs=25
for t in range(epochs):
print(f"epoch{t+1}\n")
train(train_dataloader,model,loss_fn,optimizer)
print("done")
test(test_dataloader,model,loss_fn)
结论
通过本实验,我们成功地使用PyTorch构建了一个简单的神经网络,并在MNIST数据集上进行了训练和测试。实验结果表明,模型能够逐渐学习并提高准确率。然而,为了进一步提高模型性能,可以考虑使用更复杂的模型结构、调整激活函数和优化器,以及引入验证集等策略。