背景阐述:

利用神经网络完成对手写数字进行识别的实例。 在手写数字的识别中,我们不关心图形的颜色,所以需要的是灰度图。 手写数字的识别基础可见这篇博文,PASS:写得挺有意思
基于pytorch函数实现

构建网络层可以基于Module类或函数(nn.functional)。 nn中的大多数层在functional中都有与之对应的函数。
神经网络结构
使用两个隐含层,每层激活函数为ReLU,最后使用torch.max(out, 1)找出张量out最大值对应索引作为预测值。

代码
导入模块
import os
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision.datasets import mnist
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim
from torch import nn
定义超参数
train_batch_size = 64
test_batch_size = 128
learning_rate = 0.01
num_epoches = 20
lr = 0.01
momentum = 0.5
transform = transforms.Compose(
[transforms.ToTensor(), transforms.Normalize([0.5], [0.5])])
is_downloda = True
if os.path.exists('./data/MNIST'):
is_downloda = False
train_dataset = mnist.MNIST(
'./data', train=True, transform=transform, download=is_downloda)
test_dataset = mnist.MNIST('./data', train=False, transform=transform)
train_loader = DataLoader(
train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(
test_dataset, batch_size=test_batch_size, shuffle=False)
Normalize([0.5], [0.5])对张量进行归一化,这里两个0.5分别表示对张量进行归一化的全局平均值和方差。因图像是灰色的只有一个通道,如果有多个通道,需要有多个数字,如3个通道,应该是Normalize([m1, m2, m3], [n1, n2, n3]);
可视化数据
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
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([])

构建网络
class Net(nn.Module):
"""
使用sequential构建网络,Sequential()函数的功能是将网络的层组合到一起
"""
def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
super(Net, self).__init__()
self.layer1 = nn.Sequential(
nn.Linear(in_dim, n_hidden_1), nn.BatchNorm1d(n_hidden_1))
self.layer2 = nn.Sequential(
nn.Linear(n_hidden_1, n_hidden_2), nn.BatchNorm1d(n_hidden_2))
self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))
def forward(self, x):
x = F.relu(self.layer1(x))
x = F.relu(self.layer2(x))
x = self.layer3(x)
return x
实例化
调用前面构建的函数,输入为28*28,300个、100个隐藏层,10个输出
print("GPU是否可用", torch.cuda.is_available())
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = Net(28 * 28, 300, 100, 10)
model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
训练模型
losses = []
acces = []
eval_losses = []
eval_acces = []
for epoch in range(num_epoches):
train_loss = 0
train_acc = 0
model.train()
if epoch % 5 == 0:
optimizer.param_groups[0]['lr'] *= 0.1
for img, label in train_loader:
img = img.to(device)
label = label.to(device)
img = img.view(img.size(0), -1)
out = model(img)
loss = criterion(out, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
train_loss += loss.item()
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
train_acc += acc
losses.append(train_loss / len(train_loader))
acces.append(train_acc / len(train_loader))
eval_loss = 0
eval_acc = 0
model.eval()
for img, label in test_loader:
img = img.to(device)
label = label.to(device)
img = img.view(img.size(0), -1)
out = model(img)
loss = criterion(out, label)
eval_loss += loss.item()
_, pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct / img.shape[0]
eval_acc += acc
eval_losses.append(eval_loss / len(test_loader))
eval_acces.append(eval_acc / len(test_loader))
print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}'
.format(epoch, train_loss / len(train_loader), train_acc / len(train_loader),
eval_loss / len(test_loader), eval_acc / len(test_loader)))

将训练过程可视化
plt.title('train loss')
plt.subplot(1,2,1)
plt.plot(np.arange(len(losses)), losses)
plt.legend(['Train Loss'], loc='upper right')
plt.subplot(1,2,2)
plt.title('train acces')
plt.plot(np.arange(len(acces)),acces,color='red', label='acces')
plt.legend(['Train acces'], loc='upper right')
plt.savefig(fname="./test_score.png", dpi=100)

References
【1】Pytorch官网 【2】Pytorch实现神经网络案例
|