本节可参看线性回归的从零开始实现,两者流程类似,故本节不再详述。
在上一节中已经自定义实现的函数,本节中直接使用作者提供的 d2lzh_pytorch模块。
3.6.1 获取和读取数据
# 获取数据集DATA_SETS_PATH = "~/My-Project/Python学习/PyTorch学习/知乎马卡斯扬-动手学深度学习PyTorch版/Data-Sets"# 训练集training_set = torchvision.datasets.FashionMNIST(root=DATA_SETS_PATH, train=True, download=True, transform=torchvision.transforms.ToTensor())# 测试集testing_set = torchvision.datasets.FashionMNIST(root=DATA_SETS_PATH, train=False, download=True, transform=torchvision.transforms.ToTensor())# 读取小批次数据batch_size = 256# 创建读取小批次数据的迭代器training_set_iter = torch.utils.data.DataLoader(training_set, batch_size=batch_size, shuffle=True, num_workers=10)testing_set_iter = torch.utils.data.DataLoader(testing_set, batch_size=batch_size, shuffle=True, num_workers=10)
3.6.2 初始化模型参数
softmax可以看成神经网络。用到的特征是一张 2828 的灰度图,因此输入层每一个元素对应一个像素点的灰度值。因为共有 10 个类别,输出层用 10 个单元表示各个类的置信度。所有表示权重的有 2828 个,偏差有 10 个。
# 初始化模型参数feature_size = 28 * 28labels_size = 10elem_type = torch.float32w = torch.normal(0, 0.01, (feature_size, labels_size), dtype=elem_type, requires_grad=True)b = torch.zeros(labels_size, dtype=elem_type, requires_grad=True)
3.6.3 实现 softmax 运算
在实现 softmax 运算之前,我们首先要知道如何对 Tensor 的元素进行按维度求和。dim 参数指定求和时所要沿着的方向,这和 NumPy 十分类似。缺省为对所有元素求和, dim=0 表示沿 x 轴(横向)对其他维度上所有元素求和, dim=1 表示沿 y 轴(纵向)对其他维度上所有元素求和。
# 实现 softmax 运算# 对多维 Tensor 按维度操作x = torch.tensor([[1, 2, 3],[4, 5, 6]])print(x.sum(dim=0, keepdim=True))print(x.sum(dim=1, keepdim=True))
运行结果
tensor([[5, 7, 9]])tensor([[ 6],[15]])
以此为基础,我们就可以自己实现 softmax 的运算了。
在我们的表示输出层的Tensor 中, a[i][j] 表示第 i 个样本第 j 类的概率。
def softmax(x):"""对 x 进行 softmax 运算Args:x: 原始的输出结果Returns:无Raises:无"""x_exp = x.exp()sum = x_exp.sum(dim=1, keepdim=True)return x_exp / sumx = torch.rand((2, 5))x_prob = softmax(x)print(x_prob, x_prob.sum(dim=1))
运行结果
tensor([[0.2539, 0.1704, 0.2625, 0.1335, 0.1797],[0.1366, 0.1897, 0.2679, 0.1926, 0.2132]]) tensor([1.0000, 1.0000])
3.6.4 定义模型
对输入特征进行 softmax 运算即可。
# 定义模型def net(x):"""以 x 为输入特征建立 softmax 模型Args:x: 特征Returns:无Raises:无"""return softmax(torch.mm(x.view((-1, feature_size)), w) + b)
3.6.5 定义损失函数
定义损失函数前,我们需要先找到输出层中 正确标签对应的概率 。
用 gather() 方法可以实现按指定索引位置查找元素。 y_output.gather(1, y.view(-1, 1)) 中, 1 用于指定要沿着的维度,y.view(-1, 1)是一个表示描述索引位置的Tensor。
# 定义损失函数# 用 gather 方法就可以方便地找到正确标签位置上的概率y_output = torch.tensor([[0.1, 0.3, 0.6],[0.3, 0.2, 0.5]])y = torch.tensor([0, 2])print(y_output.gather(1, y.view(-1, 1)))
运行结果
tensor([[0.1000],[0.5000]])
基于此,我们可以实现损失函数,最后返回一个标量
def cross_entropy(y_output, y):"""计算交叉熵损失函数的值Args:y_output: 预测的标签值y: 正确的标签值Returns:损失的值Raises:无"""return - torch.log(y_output.gather(1, y.view(-1, 1))).sum()
3.6.6 计算分类的准确性
argmax给出最大元素的索引值,可以指定维度。 .float() 将True /False 的布尔乐行转换为 1/0 的浮点数。accuracy 用于计算某次分类后的准确性,evaluate_accuracy用于计算对整个数据集分类后的准确性。
# 计算分类的准确率def accuracy(y_output, y):"""计算分类的准确率Args:y_output: 预测的标签值y: 正确的标签值Returns:准确率Raises:无"""return (y_output.argmax(dim=1) == y).float().mean().item()print(accuracy(y_output, y))# 已在 d2lzh_pytorch 中的 evaluate_accuracy 实现def evaluate_accuracy(data_iter, net):"""计算分类的准确率Args:data_iter: 迭代器net: 模型Returns:正确率Raises:无"""# d2lzh_pytorch.use_svg_display()# 按样本数量建立子图sum, n = 0.0, 0for x, y in data_iter:sum += (net(x).argmax(dim=1) == y).float().sum().item()n += y.shape[0]return sum / nprint(evaluate_accuracy(testing_set_iter, net))
一开始随机初始化值后,分类的准确率近似
0.50.1144
3.6.7 训练模型
流程和之前都是一样的,不再赘述。
# 训练模型iterate_num = 10loss_func = cross_entropyoptimizer = d2l.sgdfor i in range(iterate_num):for x, y in training_set_iter:y_output = net(x)current_lose = loss_func(y_output, y)current_lose.backward()optimizer([w, b], 0.1, batch_size)w.grad.data.zero_()b.grad.data.zero_()train_acc = accuracy(y_output, y)test_acc = evaluate_accuracy(testing_set_iter, net)print("第{0}次迭代后的损失为{1:.4f}, 训练准确率为{2:.4f}, 测试准确率为{3:.4f}".format(i + 1, current_lose, train_acc, test_acc))
运行结果
第1次迭代后的损失为66.6867, 训练准确率为0.7188, 测试准确率为0.7890第2次迭代后的损失为45.0898, 训练准确率为0.8542, 测试准确率为0.8126第3次迭代后的损失为44.6852, 训练准确率为0.8229, 测试准确率为0.8123第4次迭代后的损失为32.5271, 训练准确率为0.9167, 测试准确率为0.8237第5次迭代后的损失为36.5115, 训练准确率为0.8542, 测试准确率为0.8264第6次迭代后的损失为38.3955, 训练准确率为0.8438, 测试准确率为0.8319第7次迭代后的损失为38.3066, 训练准确率为0.8229, 测试准确率为0.8301第8次迭代后的损失为40.7758, 训练准确率为0.8750, 测试准确率为0.8299第9次迭代后的损失为31.7146, 训练准确率为0.8542, 测试准确率为0.8321第10次迭代后的损失为25.3807, 训练准确率为0.9062, 测试准确率为0.8353
3.6.8 预测结果的可视化
# 预测结果的可视化x, y = iter(testing_set_iter).next()true_labels = d2l.get_fashion_mnist_labels(y.numpy())predict_labels = d2l.get_fashion_mnist_labels(net(x).argmax(dim=1).numpy())titles = [true + '\n' + pred for true, pred in zip(true_labels, predict_labels)]d2l.show_fashion_mnist(x[0:9], titles[0:9])plt.show()

