【从零开始学习深度学习】7.自己动手实现softmax回归的训练与预测

简介: 【从零开始学习深度学习】7.自己动手实现softmax回归的训练与预测

1. 自己动手实现softmax回归


首先导入本节实现所需的包或模块。


import torch
import torchvision
import numpy as np
import sys
import d2lzh_pytorch as d2l


1.1 读取数据


我们将使用Fashion-MNIST数据集,并设置批量大小为256。


batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)



1.2 初始化模型参数

image.png


num_inputs = 784
num_outputs = 10
W = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_outputs)), dtype=torch.float)
b = torch.zeros(num_outputs, dtype=torch.float)

同之前一样,我们需要模型参数梯度。


W.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True) 
• 1
• 2


1.3 实现softmax运算


在介绍如何定义softmax回归之前,我们先描述一下对如何对多维Tensor按维度操作。在下面的例子中,给定一个Tensor矩阵X。我们可以只对其中同一列(dim=0)或同一行(dim=1)的元素求和,并在结果中保留行和列这两个维度(keepdim=True)。


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运算了。在下面的函数中,矩阵X的行数是样本数,列数是输出个数。为了表达样本预测各个输出的概率,softmax运算会先通过exp函数对每个元素做指数运算,再对exp矩阵同行元素求和,最后令矩阵每行各元素与该行元素之和相除。这样一来,最终得到的矩阵每行元素和为1且非负。因此,该矩阵每行都是合法的概率分布。softmax运算的输出矩阵中的任意一行元素代表了一个样本在各个输出类别上的预测概率。


def softmax(X):
    X_exp = X.exp()
    partition = X_exp.sum(dim=1, keepdim=True)
    return X_exp / partition  # 这里应用了广播机制


可以看到,对于随机输入,我们将每个元素变成了非负数,且每一行和为1。


X = torch.rand((2, 5))
X_prob = softmax(X)
print(X_prob, X_prob.sum(dim=1))


输出:


tensor([[0.2206, 0.1520, 0.1446, 0.2690, 0.2138],
        [0.1540, 0.2290, 0.1387, 0.2019, 0.2765]]) tensor([1., 1.])


1.4 定义模型


有了softmax运算,就可以定义softmax回归模型。这里通过view函数将每张原始图像改成长度为num_inputs的向量。


def net(X):
    return softmax(torch.mm(X.view((-1, num_inputs)), W) + b)


1.5 定义损失函数


之前介绍了softmax回归使用的交叉熵损失函数。为了得到标签的预测概率,我们可以使用gather函数。在下面的例子中,变量y_hat是2个样本在3个类别的预测概率,变量y是这2个样本的标签类别。通过使用gather函数,我们得到了2个样本的标签的预测概率。与3.4节(softmax回归)数学表述中标签类别离散值从1开始逐一递增不同,在代码中,标签类别的离散值是从0开始逐一递增的。


y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y = torch.LongTensor([0, 2])
y_hat.gather(1, y.view(-1, 1))


输出:


tensor([[0.1000],
        [0.5000]])


下面为(softmax回归)中介绍的交叉熵损失函数。


def cross_entropy(y_hat, y):
    return - torch.log(y_hat.gather(1, y.view(-1, 1)))


1.6 计算分类准确率


给定一个类别的预测概率分布y_hat,我们把预测概率最大的类别作为输出类别。如果它与真实类别y一致,说明这次预测是正确的。分类准确率即正确预测数量与总预测数量之比。


为了演示准确率的计算,下面定义准确率accuracy函数。其中y_hat.argmax(dim=1)返回矩阵y_hat每行中最大元素的索引,且返回结果与变量y形状相同。相等条件判断式(y_hat.argmax(dim=1) == y)是一个类型为ByteTensor的Tensor,我们用float()将其转换为值为0(相等为假)或1(相等为真)的浮点型Tensor。


def accuracy(y_hat, y):
    return (y_hat.argmax(dim=1) == y).float().mean().item()

让我们继续使用在演示gather函数时定义的变量y_hat和y,并将它们分别作为预测概率分布和标签。可以看到,第一个样本预测类别为2(该行最大元素0.6在本行的索引为2),与真实标签0不一致;第二个样本预测类别为2(该行最大元素0.5在本行的索引为2),与真实标签2一致。因此,这两个样本上的分类准确率为0.5。

print(accuracy(y_hat, y))

输出:


0.5
• 1


类似地,我们可以评价模型net在数据集data_iter上的准确率。


def evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0
    for X, y in data_iter:
        acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
        n += y.shape[0]
    return acc_sum / n


因为我们随机初始化了模型net,所以这个随机模型的准确率应该接近于类别个数10的倒数即0.1。


print(evaluate_accuracy(test_iter, net))
• 1


输出:


0.0681


1.7 训练模型

使用小批量随机梯度下降来优化模型的损失函数。在训练模型时,迭代周期数num_epochs和学习率lr都是可以调的超参数。改变它们的值可能会得到分类更准确的模型。


num_epochs, lr = 5, 0.1
def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,
              params=None, lr=None, optimizer=None):
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
        for X, y in train_iter:
            y_hat = net(X)
            l = loss(y_hat, y).sum()
            # 梯度清零
            if optimizer is not None:
                optimizer.zero_grad()
            elif params is not None and params[0].grad is not None:
                for param in params:
                    param.grad.data.zero_()
            l.backward()
            if optimizer is None:
                d2l.sgd(params, lr, batch_size)
            else:
                optimizer.step()  
            train_l_sum += l.item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
              % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [W, b], lr)

输出:

epoch 1, loss 0.7878, train acc 0.749, test acc 0.794
epoch 2, loss 0.5702, train acc 0.814, test acc 0.813
epoch 3, loss 0.5252, train acc 0.827, test acc 0.819
epoch 4, loss 0.5010, train acc 0.833, test acc 0.824
epoch 5, loss 0.4858, train acc 0.836, test acc 0.815


1.8 预测


训练完成后,现在就可以演示如何对图像进行分类了。给定一系列图像(第三行图像输出),我们比较一下它们的真实标签(第一行文本输出)和模型预测结果(第二行文本输出)。


X, y = iter(test_iter).next()
true_labels = d2l.get_fashion_mnist_labels(y.numpy())
pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(dim=1).numpy())
titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]
d2l.show_fashion_mnist(X[0:9], titles[0:9])


完整代码


import torch
import torchvision
import numpy as np
import sys
import d2lzh_pytorch as d2l
# 加载数据
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
# 初始化模型
num_inputs = 784
num_outputs = 10
W = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_outputs)), dtype=torch.float)
b = torch.zeros(num_outputs, dtype=torch.float)
W.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True) 
# 定义softmax回归
def softmax(X):
    X_exp = X.exp()
    partition = X_exp.sum(dim=1, keepdim=True)
    return X_exp / partition  # 这里应用了广播机制
# 网络计算
def net(X):
    return softmax(torch.mm(X.view((-1, num_inputs)), W) + b)
# 计算准确率
def evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0
    for X, y in data_iter:
        acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
        n += y.shape[0]
    return acc_sum / n
# 交叉熵损失
def cross_entropy(y_hat, y):
    return - torch.log(y_hat.gather(1, y.view(-1, 1)))
# 模型训练
num_epochs, lr = 5, 0.1
def train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size,
              params=None, lr=None, optimizer=None):
    for epoch in range(num_epochs):
        train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
        for X, y in train_iter:
            y_hat = net(X)
            l = loss(y_hat, y).sum()
            # 梯度清零
            if optimizer is not None:
                optimizer.zero_grad()
            elif params is not None and params[0].grad is not None:
                for param in params:
                    param.grad.data.zero_()
            l.backward()
            if optimizer is None:
                d2l.sgd(params, lr, batch_size)
            else:
                optimizer.step()  # “softmax回归的简洁实现”一节将用到
            train_l_sum += l.item()
            train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
            n += y.shape[0]
        test_acc = evaluate_accuracy(test_iter, net)
        print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
              % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, batch_size, [W, b], lr)
# 预测
X, y = iter(test_iter).next()
true_labels = d2l.get_fashion_mnist_labels(y.numpy())
pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(dim=1).numpy())
titles = [true + '\n' + pred for true, pred in zip(true_labels, pred_labels)]
d2l.show_fashion_mnist(X[0:9], titles[0:9])


小结


  • 可以使用softmax回归做多类别分类。与训练线性回归相比,你会发现训练softmax回归的步骤和它非常相似:获取并读取数据、定义模型和损失函数并使用优化算法训练模型。
相关文章
|
16天前
|
机器学习/深度学习 数据采集 人工智能
AI赋能教育:深度学习在个性化学习系统中的应用
【10月更文挑战第26天】随着人工智能的发展,深度学习技术正逐步应用于教育领域,特别是个性化学习系统中。通过分析学生的学习数据,深度学习模型能够精准预测学生的学习表现,并为其推荐合适的学习资源和规划学习路径,从而提供更加高效、有趣和个性化的学习体验。
74 9
|
1月前
|
机器学习/深度学习 算法 测试技术
深度学习环境搭建笔记(二):mmdetection-CPU安装和训练
本文是关于如何搭建深度学习环境,特别是使用mmdetection进行CPU安装和训练的详细指南。包括安装Anaconda、创建虚拟环境、安装PyTorch、mmcv-full和mmdetection,以及测试环境和训练目标检测模型的步骤。还提供了数据集准备、检查和网络训练的详细说明。
85 5
深度学习环境搭建笔记(二):mmdetection-CPU安装和训练
|
14天前
|
机器学习/深度学习 自然语言处理 并行计算
DeepSpeed分布式训练框架深度学习指南
【11月更文挑战第6天】随着深度学习模型规模的日益增大,训练这些模型所需的计算资源和时间成本也随之增加。传统的单机训练方式已难以应对大规模模型的训练需求。
60 3
|
26天前
|
机器学习/深度学习 存储 自然语言处理
深度学习之少样本学习
少样本学习(Few-Shot Learning, FSL)是深度学习中的一个重要研究领域,其目标是在只有少量标注样本的情况下,训练出能够很好地泛化到新类别或新任务的模型。
24 2
|
1月前
|
机器学习/深度学习 自然语言处理 计算机视觉
深度学习中的迁移学习技术
【10月更文挑战第11天】 本文探讨了深度学习中的迁移学习技术,并深入分析了其原理、应用场景及实现方法。通过实例解析,展示了迁移学习如何有效提升模型性能和开发效率。同时,文章也讨论了迁移学习面临的挑战及其未来发展方向。
|
16天前
|
安全 搜索推荐 机器学习/深度学习
AI赋能教育:深度学习在个性化学习系统中的应用
【10月更文挑战第26天】在人工智能的推动下,个性化学习系统逐渐成为教育领域的重要趋势。深度学习作为AI的核心技术,在构建个性化学习系统中发挥关键作用。本文探讨了深度学习在个性化推荐系统、智能辅导系统和学习行为分析中的应用,并提供了代码示例,展示了如何使用Keras构建模型预测学生对课程的兴趣。尽管面临数据隐私和模型可解释性等挑战,深度学习仍有望为教育带来更个性化和高效的学习体验。
44 0
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习之生物启发的学习系统
基于深度学习的生物启发学习系统(Biologically Inspired Learning Systems)旨在借鉴生物大脑的结构和学习机制,设计出更高效、更灵活的人工智能系统。
18 0
|
7天前
|
机器学习/深度学习 人工智能 测试技术
深度学习在图像识别中的应用与挑战
本文探讨了深度学习技术,尤其是卷积神经网络(CNN)在图像识别任务中的最新进展和面临的主要挑战。通过分析不同的网络架构、训练技巧以及优化策略,文章旨在提供一个全面的概览,帮助研究人员和实践者更好地理解和应用这些技术。
36 9
|
3天前
|
机器学习/深度学习 人工智能 算法
深度学习在图像识别中的应用与挑战
本文探讨了深度学习技术在图像识别领域的应用,重点分析了卷积神经网络(CNN)的工作原理及其在处理图像数据方面的优势。通过案例研究,展示了深度学习如何提高图像识别的准确性和效率。同时,文章也讨论了当前面临的主要挑战,包括数据不足、过拟合问题以及计算资源的需求,并提出了相应的解决策略。
|
4天前
|
机器学习/深度学习 分布式计算 并行计算
深度学习在图像识别中的应用与挑战
本文深入探讨了深度学习技术在图像识别领域的应用,分析了当前主流的卷积神经网络(CNN)架构,并讨论了在实际应用中遇到的挑战和可能的解决方案。通过对比研究,揭示了不同网络结构对识别准确率的影响,并提出了优化策略。此外,文章还探讨了深度学习模型在处理大规模数据集时的性能瓶颈,以及如何通过硬件加速和算法改进来提升效率。

热门文章

最新文章