Bootstrap

【神经网络】二、softmax回归(多输出的单层神经网络)

1.分类问题

根据上一章,我们知道线性回归模型用于解决连续值预测问题。而解决离散值的预测,例如:图像分类等。就需要使用诸如softmax回归的分类模型。

2.softmax回归模型

(1)模型定义

现有分类问题,存在三种动物 y i ( i = 1 , 2 , 3 ) y_i(i=1,2,3) yi(i=1,2,3),每种动物有四个特征 x j ( j = 1 , 2 , 3 , 4 ) x_j(j=1,2,3,4) xj(j=1,2,3,4)。对于每种动物都存在一个线性表达式为:
o i = x 1 w 1 i + x 2 w 2 i + x 3 w 3 i + x 4 w 4 i + b i o_i=x_1w_{1i}+x_2w_{2i}+x_3w_{3i}+x_4w_{4i}+b_i oi=x1w1i+x2w2i+x3w3i+x4w4i+bi
其中输出的最大值 o i o_i oi对应的索引值 i i i对应的类别 y i y_i yi是我们预测的类别,为: y ^ a r g m a x ( o i ) \hat y_{argmax(o_i)} y^argmax(oi)
softmax回归模型实际是一个多输出的单层神经网络
在这里插入图片描述

(2)softmax函数

在上述模型中, o i o_i oi的范围很难确定。并且由于真实的标签是离散值,这些离散值与不确定范围的输出值之间的误差难以衡量。所以使用softmax函数将输出值变换成值为正且和为1的概率分布:
y ^ 1 , y ^ 2 , y ^ 3 = s o f t m a x ( o 1 , o 2 , o 3 ) \hat y_1,\hat y_2,\hat y_3=softmax(o_1,o_2,o_3) y^1,y^2,y^3=softmax(o1,o2,o3)
y ^ 1 = e x p ( o 1 ) ∑ i = 1 3 e x p ( o i ) , y ^ 2 = e x p ( o 2 ) ∑ i = 1 3 e x p ( o i ) , y ^ 3 = e x p ( o 3 ) ∑ i = 1 3 e x p ( o i ) \hat y_1=\frac{exp(o_1)}{\sum_{i=1}^3 exp(o_i)},\hat y_2=\frac{exp(o_2)}{\sum_{i=1}^3 exp(o_i)},\hat y_3=\frac{exp(o_3)}{\sum_{i=1}^3 exp(o_i)} y^1=i=13exp(oi)exp(o1),y^2=i=13exp(oi)exp(o2),y^3=i=13exp(oi)exp(o3)
显然, y ^ 1 + y ^ 2 + y ^ 3 = 1 \hat y_1+\hat y_2+\hat y_3=1 y^1+y^2+y^3=1 0 ≤ y ^ 1 , y ^ 2 , y ^ 3 ≤ 1 。 0\leq\hat y_1,\hat y_2,\hat y_3\leq1。 0y^1,y^2,y^31

(3)交叉熵损失函数

为了计算损失,对于样本 i i i,我们构造向量有 y i ∈ R q \bold{y}^i\in \mathbb{R}^q yiRq,使其第 y i y^i yi个值为1,其余值为0。我们的训练目标可以设为使预测概率分布 y ^ i \hat \bold{y}^i y^i尽可能接近真实的标签概率分布 y i \bold y^i yi
对于分类问题,我们常用的损失函数为交叉熵损失函数。由于平方损失函数过于严格,在分类问题中这是不必要的,我们只需要衡量两个概率分布差异即可。函数表达式如下:
l ( Θ ) = 1 n ∑ i = 1 n H ( y i , y ^ i ) , H ( y i , y ^ i ) = − ∑ j = 1 q y j i l o g ( y ^ j i ) l(\Theta)=\frac 1n\sum_{i=1}^nH(\bold y^i,\hat \bold y^i),H(\bold y^i,\hat \bold y^i)=-\sum_{j=1}^qy_j^ilog(\hat {y}_j^i) l(Θ)=n1i=1nH(yi,y^i),H(yi,y^i)=j=1qyjilog(y^ji)

3.代码实现

Pytorch代码

import torch
import torchvision
from torch import nn
from torch.nn import init
from torch import optim

#网络模型
class SoftmaxRegress(nn.Module):
    def __init__(self,n_input,n_output):
        super(SoftmaxRegress, self).__init__()
        self.linear = nn.Linear(n_input,n_output)
    def forward(self,x):
        y = self.linear(x.view(x.shape[0],-1))#用view()将x的形状转换为(batch_size,28*28)再送入全连接层
        return y
 
#评价函数
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

#获取MNIST数据集
minst_train = torchvision.datasets.FashionMNIST(root='D:/Datasets/FashionMNIST',train=True,download=True,transform=torchvision.transforms.ToTensor())
minst_test = torchvision.datasets.FashionMNIST(root='D:/Datasets/FashionMNIST',train=False,download=True,transform=torchvision.transforms.ToTensor())

#读取数据
batch_size = 256
train_iter = torch.utils.data.DataLoader(minst_train,batch_size=batch_size,shuffle=True,num_workers=0)
test_iter = torch.utils.data.DataLoader(minst_test,batch_size=batch_size,shuffle=False,num_workers=0)


#初始化模型参数
num_inputs = 28*28
num_outputs = 10
net = SoftmaxRegress(num_inputs, num_outputs)
init.normal_(net.linear.weight, mean=0,std=0.01)
init.constant_(net.linear.bias, val=0)

#定义损失函数
loss = nn.CrossEntropyLoss()#该函数包含了softmax运算和交叉损失计算

#定义优化算法
optimizer = optim.SGD(net.parameters(), lr=0.1)

#训练模型
num_epochs = 5
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()
        optimizer.zero_grad()
        l.backward()
        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))

;