这里使用CNN对MNIST数据集进行分类,直接上代码
#导入相应包
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transform
#cuda加速
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#定义输入维度、隐藏层维度、输出维度、训练次数、batch大小、学习率
input_size = 28 * 28
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001
#定义训练集测试集并转为DataLoader格式
train_dataset = torchvision.datasets.MNIST(root='data/',
train=True,
transform=transform.ToTensor(),
download=True)
test_dataset = torchvision.datasets.MNIST(root='data/',
train=False,
transform=transform.ToTensor())
train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
batch_size=batch_size,
shuffle=False)
#定义模型
class ConvNet(nn.Module):
def __init__(self, num_classes):
super(ConvNet, self).__init__()
#这是第一层,Sequential表示将一系列函数封装到一个函数
self.layer1 = nn.Sequential(
#卷积函数,第一个参数为输入通道,第二个为输出通道,kernel_size表示卷积核大小,stride表示卷积核移动步长,padding表示添加边框大小(一般为kernel_size - 1 /2)这样能保证输入和输出图片的大小一致
nn.Conv2d(1, 16, kernel_size=5, stride=1, padding=2),
#BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的
nn.BatchNorm2d(16),
#定义激活函数
nn.ReLU(),
#池化层,是取矩阵2*2(kernel_size)中最大的数,一般stride步长与kernel_size一致
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.layer2 = nn.Sequential(
nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
#原本照片像素为28*28,由于做了两次池化缩小2*2变为7*7
self.fc = nn.Linear(7*7*32, num_classes)
def forward(self, x):
out = self.layer1(x)
out = self.layer2(out)
#注意这里将矩阵转为1位数据
out = out.reshape(out.size(0), -1)
out = self.fc(out)
return out
model = ConvNet(num_classes).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
#训练
total_step = len(train_loader)
for epoch in range(num_epochs):
for i, (images, labels) in enumerate(train_loader):
images = images.to(device)
labels = labels.to(device)
# 前向
outputs = model(images)
loss = criterion(outputs, labels)
# 反向和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i + 1) % 100 == 0:
print('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
.format(epoch + 1, num_epochs, i + 1, total_step, loss.item()))
# 测试
model.eval() # eval mode (batchnorm uses moving mean/variance instead of mini-batch mean/variance)
with torch.no_grad():
correct = 0
total = 0
for images, labels in test_loader:
images = images.to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Test Accuracy of the model on the 10000 test images: {} %'.format(100 * correct / total))
# 保存
torch.save(model.state_dict(), 'model.ckpt')
最后输出结果如下:
Epoch [1/5], Step [100/600], Loss: 0.1086
Epoch [1/5], Step [200/600], Loss: 0.0674
Epoch [1/5], Step [300/600], Loss: 0.0866
Epoch [1/5], Step [400/600], Loss: 0.0204
Epoch [1/5], Step [500/600], Loss: 0.0307
Epoch [1/5], Step [600/600], Loss: 0.1147
Epoch [2/5], Step [100/600], Loss: 0.0057
Epoch [2/5], Step [200/600], Loss: 0.0620
Epoch [2/5], Step [300/600], Loss: 0.0134
Epoch [2/5], Step [400/600], Loss: 0.1040
Epoch [2/5], Step [500/600], Loss: 0.0705
Epoch [2/5], Step [600/600], Loss: 0.0129
Epoch [3/5], Step [100/600], Loss: 0.0318
Epoch [3/5], Step [200/600], Loss: 0.0140
Epoch [3/5], Step [300/600], Loss: 0.0270
Epoch [3/5], Step [400/600], Loss: 0.0655
Epoch [3/5], Step [500/600], Loss: 0.0056
Epoch [3/5], Step [600/600], Loss: 0.0104
Epoch [4/5], Step [100/600], Loss: 0.0052
Epoch [4/5], Step [200/600], Loss: 0.0068
Epoch [4/5], Step [300/600], Loss: 0.0359
Epoch [4/5], Step [400/600], Loss: 0.0696
Epoch [4/5], Step [500/600], Loss: 0.0317
Epoch [4/5], Step [600/600], Loss: 0.0208
Epoch [5/5], Step [100/600], Loss: 0.0182
Epoch [5/5], Step [200/600], Loss: 0.0383
Epoch [5/5], Step [300/600], Loss: 0.0571
Epoch [5/5], Step [400/600], Loss: 0.0057
Epoch [5/5], Step [500/600], Loss: 0.0494
Epoch [5/5], Step [600/600], Loss: 0.0609
Test Accuracy of the model on the 10000 test images: 99.13 %