MNIST手写数字集的多分类问题(Linear Layer)
import torch # 引入模块PyTorch
from torchvision import transforms # 从torch视觉中引入转换函数
from torchvision import datasets # 导入数据库
from torch.utils.data import DataLoader # 导入数据加载器
import torch.nn.functional as F # 导入激活函数
import torch.optim as optim # 导入优化器
# 使用的数字分类数据集,只有一个灰度通道0-255
batch_size = 64
transform = transforms.Compose([
transforms.ToTensor(), # 将图像的通道从[0,255]映射到[0,1]
transforms.Normalize((0.1307,), (0.3081,)) # 根据手写数字集的平均值和标准差来实现归一化
]) # 定义mnist数据集转化管道
train_dataset = datasets.MNIST(root='./dataset/mnist/', # 设置数据集存放的根目录
train=True, # 选择是否是训练集
download=True, # 是否从网上下载
transform=transform) # 使用可选参数trannsform来使用前面定义的转换
train_loader = DataLoader(dataset=train_dataset, # 使用数据加载器来读入训练集数据
shuffle=True, # 使用可选参数shuffle=True来打乱训练集
batch_size=batch_size) # 使用可选参数batch_size来确定每批的数据数量
test_dataset = datasets.MNIST(root='./dataset/mnist/',
train=False, # train=False 在这里代表选用了测试集
download=True,
transform=transform)
test_loader = DataLoader(dataset=test_dataset,
shuffle=False, # 测试机数据不用打乱
batch_size=batch_size) # 每批数据数量同前面一样
class Net(torch.nn.Module): # 创建网络类
def __init__(self): # 初始化类
super(Net, self).__init__() # 继承父类
self.l1 = torch.nn.Linear(784, 512) # 实现线性层
self.l2 = torch.nn.Linear(512, 256)
self.l3 = torch.nn.Linear(256, 128)
self.l4 = torch.nn.Linear(128, 64)
self.l5 = torch.nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 784) # 将输入的shape=(28,28)的张量展平为(batch_size,28*28)
x = F.gelu(self.l1(x)) # 将输入通过线性层后再经由激活函数gelu进入到下一线性层
x = F.gelu(self.l2(x))
x = F.gelu(self.l3(x))
x = F.gelu(self.l4(x))
return self.l5(x)
model = Net() # 将神经网络模型实例化给model
criterion = torch.nn.CrossEntropyLoss() # 定义多分类损失函数
# 使用SGD(Stochastic Gradient for Tensor Decomposition)随机梯度下降优化器来修正模型的参数
# 并定义了学习率和动量来加速网络的收敛
optimizer = torch.optim.SGD(model.parameters(), lr=0.01,
momentum=.5)
def train(epoch): # 定义训练函数
running_loss = 0 # 初始化损失为0
for batch_idx, (x, y) in enumerate(train_loader): # 从可迭代对象train_loader中获取获取批数,还有输入和输出
inputs, target = x, y # 将x,y分别给输入和目标值
optimizer.zero_grad() # 初始化将梯度置0
outputs = model(inputs) # 输入经由model的正向传播得到输入
loss = criterion(outputs, target) # 通过criterion函数来计算损失
loss.backward() # 将损失函数进行反向传播计算梯度
optimizer.step() # 根据梯度来更新参数
running_loss += loss # 计算每300批的损失值
if batch_idx % 300 == 299:
print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300)) # 输出300批损失值的平均值
running_loss = 0 # 将损失值置0
def test(): # 定义测试集
corrent = 0 # 定义正确率
total = 0 # 定义总数
with torch.no_grad(): # 因为是测试集,不用计算跟踪梯度
for data in test_loader:
images, labels = data
outputs = model(images)
_, prediction = torch.max(outputs, dim=1) # torch.max()函数按维度dim返回最大值的那个元素和索引
total += labels.size(0) # labels的size(0)就是每批数据的数目
corrent += (prediction == labels).sum().item() # 用预测正确的数目的和除以总数目来获得正确率
print('Accuracy on test set %d %%' % (100 * corrent / total))
if __name__ == '__main__':
for epoch in range(10): # 训练十轮
train(epoch)
test()
运行结果: