整理自:《动手学深度学习》
import numpy as np
import torch,torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l
1. 获取数据集
使用torchvision库自带的经典数据集Fashion-MNST。下载后将其加载到内存中。
通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式,并除以255使得所有像素的数值均在0到1之间。
def load_data_fashion_mnist(batch_size, resize=None):
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
mnist_train = torchvision.datasets.FashionMNIST(
root="data", """下载到哪个文件夹"""
train=True, """训练集还是测试集"""
transform=trans, """转换格式"""
download=True """是否下载到本地"""
)
mnist_test = torchvision.datasets.FashionMNIST(
root="data",
train=False,
transform=trans,
download=True
)
train_dl = data.DataLoader(mnist_train, batch_size, shuffle=True, num_workers=4)
test_dl = data.DataLoader(mnist_test, batch_size, shuffle=True, num_workers=4)
"""num_workers是cpu多线程读入内存"""
return (train_dl, test_dl)
train_iter, test_iter = load_data_fashion_mnist(32,resize=64)
for X,y in train_iter:
print(X.shape,X.dtype)
print(y.shape,y.dtype)
break
2. 定义模型
PyTorch不会隐式地调整输⼊的形状。因此,我们在线性层前定义了展平层(flatten),来调整⽹络输⼊的形状
这里的net是已经封装好的模型,所有功能都有。
backward后,自动求导都存到了net里,step()后theta自动更新到net里,再次调用net就是训练好的模型。
所以同样是loss( y, net(X) )这个函数,训练前的值和训练后的值就不一样。
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
"""初始化参数,就是初始化theta的过程,从这个点开始梯度下降"""
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01) '''均值0和标准差0.01随机初始化权重'''
net.apply(init_weights);
3. 损失函数
如果训练时画的图不显示,则使用后一个reduction='none'
reduction是计算模式,有三种选择:
1. reduction = mean, 会对N个样本的loss进行平均之后返回标量,(默认)
2. reduction = sum, 会对N个样本的loss求和后返回标量
3. reduction = none, 表示直接返回n个样本的loss返回向量
loss = nn.CrossEntropyLoss()
or
loss = nn.CrossEntropyLoss(reduction='none')
4. 优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.1)
5.训练
为了方便画图,分成两个函数。
5.1 整个数据集的小批次训练
def train_epoch_ch3(net, train_iter, loss, trainer):
metric = d2l.Accumulator(3)
for X,y in train_iter:
y_hat = net(X)
l = loss(y_hat, y)
trainer.zero_grad()
l.mean().backward()
trainer.step()
metric.add(float(l.sum()), d2l.accuracy(y_hat,y), y.numel())
'''返回训练损失和训练精度'''
return metric[0]/metric[2], metric[1]/metric[2]
5.2 画图, 和多次扫描数据集训练
def train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer):
'''动态画图实例'''
animator = d2l.Animator(xlabel='epoch', xlim=[1,num_epochs], ylim=[0.3,0.9],legend=['train loss', 'train acc', 'test acc'])
for epoch in range(num_epochs):
'''训练,顺便返回损失和精度'''
train_metirc = train_epoch_ch3(net, train_iter, loss, trainer)
'''记录训练过程中的测试集准确度'''
test_acc = d2l.evaluate_accuracy(net, test_iter)
animator.add(epoch+1, train_metirc+(test_acc,))
正式开始
num_epochs = 10
train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)