pytorch之Softmax回归

理论推导

简介

softmax回归模型,实际是一个分类模型,与线性回归模型有很多不同的地方(与线性回归一样都是一个单层的神经网络)

pytorch之Softmax回归_第1张图片

分类问题介绍

输入图片的每一个像素值都可以用一个标量表示,我们将图片中的4个像素用 x1,x2,x3,x4表示

假设训练数据集中图像的真实标签为狗、猫或鸡(假设可以用4像素表示出这3种动物),这些标签分别对应离散值y 1 , y 2 , y 3

softmax回归模型

softmax回归跟线性回归一样将输入特征与权重做线性叠加。与线性回归的一个主要不同在于,softmax回归的输出值个数等于标签里的类别数。因为一共有4种特征和3种输出动物类别,所以权重包含12个标量(带下标的w)、偏差包含3个标量(带下标的b),每个输入都会得到三个输出o1,o2,o3

pytorch之Softmax回归_第2张图片

 输出oi当作预测类别i的置信度,将最大的置信度输出作为预测的种类(我们会用一些方法把Oi转换成为概率),假如O1=o.1,O2=o.3,O3=0.6 , 最大,那么预测类别为2,其代表猫。

代码实践

从零开始

引入数据集

#sec_fashion_mnist中引入的Fashion-MNIST数据集, 并设置数据迭代器的批量大小为256
import torch
from IPython import display
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)//iter 是迭代器

初始化模型参数

num_inputs = 784#模型输入有784
num_outputs = 10#模型输入有10

W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)#初始一个权重,选一个高斯随机数据为权重
b = torch.zeros(num_outputs, requires_grad=True)#初始化偏差,利用某个数学方法在数据中选择一个作为偏差

定义softmax操作

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdim=True), X.sum(1, keepdim=True)
def softmax(X):
    X_exp = torch.exp(X)#对元素进行指数计算
    partition = X_exp.sum(1, keepdim=True)#对每一行进行求和
    return X_exp / partition  # 这里应用了广播机制
#将输出变成总概率为1
X = torch.normal(0, 1, (2, 5))
X_prob = softmax(X)
X_prob, X_prob.sum(1)

定义模型

def net(X):
    return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b

定义损失函数

def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])

cross_entropy(y_hat, y)

分类精度

#将预测类别与真实y元素进行比较
def accuracy(y_hat, y):  #@save
    """计算预测正确的数量"""
    if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
        y_hat = y_hat.argmax(axis=1)
    cmp = y_hat.type(y.dtype) == y
    return float(cmp.type(y.dtype).sum())
accuracy(y_hat, y) / len(y)#预测正确的概率

绘制动画

#在展示训练函数的实现之前,我们[定义一个在动画中绘制数据的实用程序类]Animator
class Animator:  #@save
    """在动画中绘制数据"""
    def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
                 ylim=None, xscale='linear', yscale='linear',
                 fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
                 figsize=(3.5, 2.5)):
        # 增量地绘制多条线
        if legend is None:
            legend = []
        d2l.use_svg_display()
        self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
        if nrows * ncols == 1:
            self.axes = [self.axes, ]
        # 使用lambda函数捕获参数
        self.config_axes = lambda: d2l.set_axes(
            self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
        self.X, self.Y, self.fmts = None, None, fmts

    def add(self, x, y):
        # 向图表中添加多个数据点
        if not hasattr(y, "__len__"):
            y = [y]
        n = len(y)
        if not hasattr(x, "__len__"):
            x = [x] * n
        if not self.X:
            self.X = [[] for _ in range(n)]
        if not self.Y:
            self.Y = [[] for _ in range(n)]
        for i, (a, b) in enumerate(zip(x, y)):
            if a is not None and b is not None:
                self.X[i].append(a)
                self.Y[i].append(b)
        self.axes[0].cla()
        for x, y, fmt in zip(self.X, self.Y, self.fmts):
            self.axes[0].plot(x, y, fmt)
        self.config_axes()
        display.display(self.fig)
        display.clear_output(wait=True)

训练

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save
    """训练模型(定义见第3章)"""
    animator = 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):#扫n遍数据
        train_metrics = train_epoch_ch3(net, train_iter, loss, updater)#根据之前函数,训练一次
        test_acc = evaluate_accuracy(net, test_iter)#评估一下测试精度
        animator.add(epoch + 1, train_metrics + (test_acc,))#显示各种精度
    train_loss, train_acc = train_metrics
    assert train_loss < 0.5, train_loss
    assert train_acc <= 1 and train_acc > 0.7, train_acc
    assert test_acc <= 1 and test_acc > 0.7, test_acc
#小批量随机梯度下降来优化模型的损失函数,设置学习率为0.1
lr = 0.1

def updater(batch_size):
    return d2l.sgd([W, b], lr, batch_size)
num_epochs = 10#训练10个迭代周期
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)#开始训练

预测

#现在训练已经完成,我们的模型已经准备好[对图像进行分类预测]。 给定一系列图像,我们将比较它们的实际标签(文本输出的第一行)和模型预测(文本输出的第二行)
def predict_ch3(net, test_iter, n=6):  #@save
    """预测标签(定义见第3章)"""
    for X, y in test_iter:
        break
    trues = d2l.get_fashion_mnist_labels(y)
    preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
    titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
    d2l.show_images(
        X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])

predict_ch3(net, test_iter)

pytorch简洁实现

引入数据集

import torch
from torch import nn
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

初始化模型参数

 PyTorch不会隐式地调整输入的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))#模型在这里创建出来

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights)#每一层跑一下这个函数就可以完成初始化

softmax的实现

loss = nn.CrossEntropyLoss(reduction='none')

优化算法

trainer = torch.optim.SGD(net.parameters(), lr=0.1)#调用优化算法,设置学习率为0.1 ,这与我们在线性回归例子中的相同,这说明了优化器的普适性

训练

num_epochs = 10#训练10圈
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)#调用第三章的那个ch3函数训练

你可能感兴趣的:(#,pytorch,深度学习)