关于 Mnist 数据集
- MNIST 包含70,000张手写数字图像: 60,000张用于培训,10,000张用于测试。
- 图像是灰度的,28x28像素的,并且居中的,以减少预处理和加快运行。
代码实现
import torch
import torchvision
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt
数据准备
data_path = 'data/mnist'
transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
(0.1307,), (0.3081,))
])
train_dataset = torchvision.datasets.MNIST(data_path, train=True, download=True, transform=transform)
test_dataset = torchvision.datasets.MNIST(data_path, train=False, download=True, transform=transform)
batch_size_train = 64
batch_size_test = 1000
# batch_size: 一次性加载的数据量; num_workers=4 使用4个子进程加载数据
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size_train, shuffle=True, num_workers=4)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=batch_size_test, shuffle=True, num_workers=4)
查看数据组成
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
batch_idx # 0
example_data.shape
# torch.Size([1000, 1, 28, 28])
example_data
'''
tensor([[[[-0.4242, -0.4242, -0.4242, ..., -0.4242, -0.4242, -0.4242],
[-0.4242, -0.4242, -0.4242, ..., -0.4242, -0.4242, -0.4242],
...,
[-0.4242, -0.4242, -0.4242, ..., -0.4242, -0.4242, -0.4242]]],
...,
[[[-0.4242, -0.4242, -0.4242, ..., -0.4242, -0.4242, -0.4242],
...,
[-0.4242, -0.4242, -0.4242, ..., -0.4242, -0.4242, -0.4242]]]])
'''
example_targets
'''
tensor([3, 3, 2, 7, 5, 7, 6, 5, 4, 8, 3, 1, 7, 8, 0, 1, 4, 7, 9, 4, 4, 4, 6, 1, 7, 8, 8, 0, 9, 7, 2, 1])
'''
print(example_data.shape) # torch.Size([1000, 1, 28, 28])
显示图片
fig = plt.figure()
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.tight_layout()
plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
plt.title("Ground Truth: {}".format(example_targets[i]))
plt.xticks([])
plt.yticks([])
plt.show()
定义网络
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
训练
设置超参数
n_epochs = 3
learning_rate = 0.01
momentum = 0.5
log_interval = 10
random_seed = 1
torch.manual_seed(random_seed)
设置模型保存地址等
import os
model_dir = '/Users/xx/mnist/model/'
model_path = os.path.join(model_dir, 'model.pth')
optimizer_path = os.path.join(model_dir, 'optimizer.pth')
def train(epoch):
network.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = network(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % log_interval == 0:
print('-- Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, batch_idx * len(data),
len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item()))
train_losses.append(loss.item())
train_counter.append((batch_idx * 64) + ((epoch - 1) * len(train_loader.dataset)))
torch.save(network.state_dict(), model_path)
torch.save(optimizer.state_dict(), optimizer_path)
train(1)
'''
-- Train Epoch: 1 [0/60000 (0%)] Loss: 2.371851
-- Train Epoch: 1 [6400/60000 (11%)] Loss: 2.068980
-- Train Epoch: 1 [12800/60000 (21%)] Loss: 1.208917
-- Train Epoch: 1 [19200/60000 (32%)] Loss: 0.748824
-- Train Epoch: 1 [25600/60000 (43%)] Loss: 0.609824
...
-- Train Epoch: 1 [57600/60000 (96%)] Loss: 0.467529
'''
测试
def test():
network.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
output = network(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.data.max(1, keepdim=True)[1]
correct += pred.eq(target.data.view_as(pred)).sum()
test_loss /= len(test_loader.dataset)
test_losses.append(test_loss)
print('\n-- Test set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
test()
# Test set: Avg. loss: 0.2085, Accuracy: 9396/10000 (94%)
for epoch in range(1, n_epochs + 1):
train(epoch)
test()
'''
-- Train Epoch: 1 [0/60000 (0%)] Loss: 0.365044
-- Train Epoch: 1 [6400/60000 (11%)] Loss: 0.463751
-- Train Epoch: 1 [12800/60000 (21%)] Loss: 0.384765
-- Train Epoch: 1 [19200/60000 (32%)] Loss: 0.439015
-- Train Epoch: 1 [25600/60000 (43%)] Loss: 0.386983
-- Train Epoch: 1 [32000/60000 (53%)] Loss: 0.287491
-- Train Epoch: 1 [38400/60000 (64%)] Loss: 0.313556
-- Train Epoch: 1 [44800/60000 (75%)] Loss: 0.612881
-- Train Epoch: 1 [51200/60000 (85%)] Loss: 0.340482
-- Train Epoch: 1 [57600/60000 (96%)] Loss: 0.290289
Test set: Avg. loss: 0.1251, Accuracy: 9617/10000 (96%)
-- Train Epoch: 2 [0/60000 (0%)] Loss: 0.449924
-- Train Epoch: 2 [6400/60000 (11%)] Loss: 0.438897
-- Train Epoch: 2 [12800/60000 (21%)] Loss: 0.292782
...
-- Train Epoch: 2 [57600/60000 (96%)] Loss: 0.404231
Test set: Avg. loss: 0.1002, Accuracy: 9688/10000 (97%)
-- Train Epoch: 3 [0/60000 (0%)] Loss: 0.202292
-- Train Epoch: 3 [6400/60000 (11%)] Loss: 0.512848
-- Train Epoch: 3 [12800/60000 (21%)] Loss: 0.255428
...
-- Train Epoch: 3 [57600/60000 (96%)] Loss: 0.186922
Test set: Avg. loss: 0.0845, Accuracy: 9727/10000 (97%)
'''
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
with torch.no_grad():
output = network(example_data)
output
fig = plt.figure()
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.tight_layout()
plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
plt.title("Prediction: {}".format(output.data.max(1, keepdim=True)[1][i].item()))
plt.xticks([])
plt.yticks([])
plt.show()
fig = plt.figure()
plt.plot(train_counter, train_losses, color='blue')
plt.scatter(test_counter, test_losses, color='red')
plt.legend(['Train Loss', 'Test Loss'], loc='upper right')
plt.xlabel('number of training examples seen')
plt.ylabel('negative log likelihood loss')
# Text(0, 0.5, 'negative log likelihood loss')
LeNet 网络
定义网络模型
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
# 1-输入一张灰度图, 6-输出6张特征图,(5,5)也可简化为5,大小为 5*5 的卷积核过滤器。
self.c1 = nn.Conv2d(1, 6, (5, 5))
# 输入 6 张特诊图,输出 16 张特征图,过滤器仍为 5*5
self.c3 = nn.Conv2d(6, 16, 5)
# 由池化层 S4 中所有的特征点(共 16*4*4 个),全连接到 120 个点。
self.fc1 = nn.Linear(16*4*4, 120)
# 由 120 个点,全连接到 84 个点
self.fc2 = nn.Linear(120, 84)
# 由 84 个点,全连接到输出层中的 10 个点
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
# 池化核大小为 2*2,也可简化为参数 2
x = F.max_pool2d(F.relu(self.c1(x)), 2)
x = F.max_pool2d(F.relu(self.c3(x)), 2)
x = x.view(-1, self.num_flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
def num_flat_features(self, x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
训练
加载网络
if torch.cuda.is_available():
lenet = LeNet().cuda()
else:
lenet = LeNet()
lenet
LeNet(
(c1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
(c3): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=256, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
训练
def train(model, criterion, optimizer, epochs=1):
for epoch in range(epochs):
running_loss = 0.0
for i, data in enumerate(train_loader, 0):
inputs, labels = data
if torch.cuda.is_available():
inputs, labels = inputs.cuda(), labels.cuda()
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i%1000==999:
print(f'-- epoch : {epoch+1}, %%bashatch : {i+1}, loss: {running_loss/1000} ')
running_loss = 0.0
print('\n\n-- end trainning')
2023-02-08