代码实现了基本的CNN
共两层神经网络,包括两层卷积层两层池化层
使用的数据集为单通道28*28像素的MNIST数据集,共10个标签
训练集可直接在代码里下载
代码模块如下:
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms # datasets模块封装了一些常用的数据集 transforms模块封装了一些图像预处理操作
# 构建网络模型
class CNN(nn.Module):
# 初始化子类
def __init__(self):
# 继承父类属性
super(CNN, self).__init__() # 第一种继承方法 python2 python3通用
# 构建第一层卷积神经网络
self.conv1 = nn.Sequential( # 输入大小(1, 28, 28)
nn.Conv2d( # 构建卷积层
in_channels=1, # 输入特征图数量 灰度图 一个
out_channels=16, # 输入特征图数量
kernel_size=5, # 卷积核大小
stride=1, # 步长
padding=2, # 边缘填充
),
nn.ReLU(), # relu层
nn.MaxPool2d(kernel_size=2), # 池化层
)
self.conv2 = nn.Sequential(nn.Conv2d(16, 32, 5, 1, 2), nn.ReLU(), nn.MaxPool2d(2))
self.out = nn.Linear(32*7*7, 10) # 全连接层
# 前向传播
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1) # flatten操作拉长
output = self.out(x)
return output
# 计算精度
def accuracy(predictions, labels):
pr = torch.max(predictions.data, 1)[1] # torch.max()函数返回[最大值, 索引] 这里只返回索引 dim=0时返回每行 dim=1时返回每列
rights = pr.eq(labels.data.view_as(pr)).sum() # eq()函数比较梁变量各个值是否相同 返回bool值 view_as()函数返回与函数内变量相同大小的格式 最后计算True的个数
return rights, len(labels)
if __name__ == '__main__':
# 定义超参数
input_size = 28 # 图像的总尺寸为28*28
num_classes = 10 # 标签的种类数
num_epochs = 3 # 训练的总循环周期
batch_size = 128 # 每批次的大小
learning_rata = 0.001
# 训练集 直接下载
train_dataset = datasets.MNIST(root="./data", train=True, transform=transforms.ToTensor(), download=True)
# 测试集 直接下载
test_dataset = datasets.MNIST(root="./data", train=False, transform=transforms.ToTensor(), download=True)
# 构建batch数据
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True) # 总数据量/batch_size
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
# 初始化模型、损失函数、梯度下降函数三大类
net = CNN() # 初始化模型
criterion = nn.CrossEntropyLoss() # 初始化交叉熵损失函数 常用于多分类与二分类问题
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rata) # 初始化梯度下降函数
net.train() # 训练模式
for epoch in range(num_epochs):
# 当前epoch的结果保存下来
train_rights = []
# 针对容器中的每一个批次进行循环
for batch_idx, (train_data, train_target) in enumerate(train_loader): # enumerate函数对列表进行排序并生成索引
optimizer.zero_grad() # 梯度归0
train_output = net(train_data) # 计算预测结果 输出格式为tensor
loss = criterion(train_output, train_target) # 将预测值与真实值带入损失函数计算损失值
loss.backward() # 反向传播
optimizer.step() # 沿梯度下降方向更新所有参数
right = accuracy(train_output, train_target) # 计算预测正确的个数
train_rights.append(right)
if batch_idx % 100 == 0:
net.eval()
val_rights = []
for (test_data, test_target) in test_loader:
train_output = net(test_data)
right = accuracy(train_output, test_target)
val_rights.append(right)
# 准确率计算
train_r = (sum([tup[0] for tup in train_rights]), sum([tup[1] for tup in train_rights]))
val_r = (sum([tup[0] for tup in val_rights]), sum([tup[1] for tup in val_rights]))
# 打印训练信息
print("当前epoch:{} [{}/{} ({:.0f}%)]\t损失:{:.6f}\t训练集准确率:{:.2f}%\t测试集正确率:{:.2f}%".format(
epoch, batch_idx * batch_size, len(train_loader.datasets), (100. * batch_idx / len(train_loader)),
loss.data, (100. * train_r[0].numpy() / train_r[1]), (100. * val_r[0].numpy() / val_r[1])))
MNIST训练集包含60000个像本,测试集包含10000个样本
训练了3个epoch,batch_size = 128, lr = 0.001
训练结果如下:
正确率达到了预期效果