导入相关的库
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
导入数据
training_data = datasets.MNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)
test_data = datasets.MNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)
We pass the as an argument to . This wraps an iterable over our dataset, and supports automatic batching, sampling, shuffling and multiprocess data loading. Here we define a batch size of 256, i.e. each element in the dataloader iterable will return a batch of 64 features and labels.
batch_size = 256
# Create data loaders.
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
for X, y in test_dataloader:
print(f"Shape of X [N, C, H, W]: {X.shape}")
print(f"Shape of y: {y.shape} {y.dtype}")
break
Shape of X [N, C, H, W]: torch.Size([256, 1, 28, 28]) Shape of y: torch.Size([256]) torch.int64
使用GPU计算
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using {device} device")
Using cuda device
卷积层尝试解决这两个问题。一方面,卷积层保留输入形状,使图像的像素在高和宽两个方向上的相关性均可能被有效识别;另一方面,卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免参数尺寸过大。
卷积神经网络就是含卷积层的网络。本节里我们将介绍一个早期用来识别手写数字图像的卷积神经网络:LeNet 。这个名字来源于LeNet论文的第一作者Yann LeCun。LeNet展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当时最先进的结果。这个奠基性的工作第一次将卷积神经网络推上舞台,为世人所知。LeNet的网络结构如下图所示。
不过我们使用改进版的卷积神经网络
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv = nn.Sequential(
nn.Conv2d(1, 32, 5), # in_channels, out_channels, kernel_size
nn.ReLU(),
nn.MaxPool2d(2, 2), # kernel_size, stride
nn.Conv2d(32, 64, 5),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Sequential(
nn.Linear(64*4*4, 128),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(128, 64),
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(64, 10)
)
def forward(self, img):
feature = self.conv(img)
output = self.fc(feature.view(img.shape[0], -1))
return output
model = LeNet().to(device)
model
LeNet( (conv): Sequential( (0): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1)) (1): ReLU() (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (3): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1)) (4): ReLU() (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) (fc): Sequential( (0): Linear(in_features=1024, out_features=128, bias=True) (1): ReLU() (2): Dropout(p=0.5, inplace=False) (3): Linear(in_features=128, out_features=64, bias=True) (4): ReLU() (5): Dropout(p=0.5, inplace=False) (6): Linear(in_features=64, out_features=10, bias=True) ) )
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
model.train()
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
# Compute prediction error
pred = model(X)
loss = loss_fn(pred, y)
# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
编写训练循环
epochs = 10
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")
Epoch 1 ------------------------------- loss: 2.308621 [ 0/60000] loss: 0.505998 [25600/60000] loss: 0.268082 [51200/60000] Test Error: Accuracy: 96.4%, Avg loss: 0.117353 Epoch 2 ------------------------------- loss: 0.329561 [ 0/60000] loss: 0.254944 [25600/60000] loss: 0.189128 [51200/60000] Test Error: Accuracy: 98.1%, Avg loss: 0.065033 Epoch 3 ------------------------------- loss: 0.152760 [ 0/60000] loss: 0.204619 [25600/60000] loss: 0.112943 [51200/60000] Test Error: Accuracy: 98.4%, Avg loss: 0.057176 Epoch 4 ------------------------------- loss: 0.137523 [ 0/60000] loss: 0.149151 [25600/60000] loss: 0.111854 [51200/60000] Test Error: Accuracy: 98.6%, Avg loss: 0.046431 Epoch 5 ------------------------------- loss: 0.102964 [ 0/60000] loss: 0.076728 [25600/60000] loss: 0.107589 [51200/60000] Test Error: Accuracy: 98.9%, Avg loss: 0.035916 Epoch 6 ------------------------------- loss: 0.126341 [ 0/60000] loss: 0.068162 [25600/60000] loss: 0.081467 [51200/60000] Test Error: Accuracy: 98.9%, Avg loss: 0.038968 Epoch 7 ------------------------------- loss: 0.130671 [ 0/60000] loss: 0.110663 [25600/60000] loss: 0.087696 [51200/60000] Test Error: Accuracy: 99.0%, Avg loss: 0.032638 Epoch 8 ------------------------------- loss: 0.083890 [ 0/60000] loss: 0.135233 [25600/60000] loss: 0.082023 [51200/60000] Test Error: Accuracy: 99.0%, Avg loss: 0.036280 Epoch 9 ------------------------------- loss: 0.150658 [ 0/60000] loss: 0.068766 [25600/60000] loss: 0.094734 [51200/60000] Test Error: Accuracy: 99.1%, Avg loss: 0.036989 Epoch 10 ------------------------------- loss: 0.191105 [ 0/60000] loss: 0.152277 [25600/60000] loss: 0.091440 [51200/60000] Test Error: Accuracy: 99.0%, Avg loss: 0.032618 Done!