作业二·Softmax实现多分类

Softmax实现多分类

一、基本原理

1.1 决策函数

1.1.1 表达式

对于多类问题,类别标签 y ∈ 1 , 2 , ⋯   , C y \in {1,2,\cdots,C} y1,2,,C可以有C个取值,给定一个样本x,则Softmax回归预测的属于c的条件概率是:
p ( y = c ∣ x ) = softmax ⁡ ( w c T x ) = e w c T x ∑ c i = 1 C e w c i T x p(y=c|x) = \operatorname{softmax}(w^T_cx) = \frac{e^{w_c^Tx}}{\sum_{c_i = 1}^{C}e^{w_{c_i}^Tx}} p(y=cx)=softmax(wcTx)=ci=1CewciTxewcTx
其中 w c w_c wc是第c类的权重向量。使用条件概率最大的类别,作为最终的预测 y ^ \hat{y} y^,因此决策函数表达为:
y ^ = a r g m a x c = 1 C p ( y = c ∣ x ) = a r g m a x c = 1 C w c T x \hat{y} = \mathop{\mathrm{argmax}}\limits_{c = 1}^{C}{p(y=c|x)} = \mathop{\mathrm{argmax}}\limits_{c = 1}^{C}{w_c^Tx} y^=c=1argmaxCp(y=cx)=c=1argmaxCwcTx
决策函数使用矩阵表示:
y ^ = e W T x 1 C T e W T x \hat{y} = \frac{e^{W^Tx}}{1_C^T e ^{W^Tx}} y^=1CTeWTxeWTx
其中, W = [ w 1 , ⋯   , w C ] W =[w1,\cdots,w_C] W=[w1,,wC]是由C个类的权重向量组成的矩阵, 1 C 1_C 1C为C维的全1向量, y ^ \hat{y} y^为一个C维向量,第c个元素的值是第c类的预测条件概率

1.1.2 具体分析

x x x是一个五维向量,记为:
x = [ x 1 x 2 x 3 x 4 1 ] x = \begin{bmatrix} x1 \\ x2 \\ x3 \\ x4 \\ 1 \end{bmatrix} x= x1x2x3x41

对于第 i i i个样本(总样本数为N), x i x^i xi的矩阵表示为:

x ( i ) = [ x 1 i x 2 i x 3 i x 4 i 1 ] x^{(i)} = \begin{bmatrix} x^i_1 \\ x^i_2 \\ x^i_3 \\ x^i_4 \\ 1 \end{bmatrix} x(i)= x1ix2ix3ix4i1

用c维的one-hot向量 y ∈ 0 , 1 C y\in{0,1}^C y0,1C来表示标签类别,以C=3为例,假设第 i i i样本属于第二类,则该点的标签值为

y ( i ) = [ 0 1 0 ] y^{(i)} = \begin{bmatrix} 0 \\ 1 \\ 0 \end{bmatrix} y(i)= 010

对五维向量x,需要将样本分成三类,有以下权重向量

W = [ w 11 w 12 w 13 w 21 w 22 w 23 w 31 w 32 w 33 w 41 w 42 w 43 w 51 w 52 w 53 ] W = \begin{bmatrix} w_{11} & w_{12} & w_{13}\\ w_{21} & w_{22} & w_{23}\\ w_{31} & w_{32} & w_{33}\\ w_{41} & w_{42} & w_{43}\\ w_{51} & w_{52} & w_{53}\\ \end{bmatrix} W= w11w21w31w41w51w12w22w32w42w52w13w23w33w43w53

获得Softmax对第 i i i个样本分类的矢量表达式:
y ^ i = softmax ⁡ ( W T x ( i ) ) = e W T x ( i ) 1 C T e W T x ( i ) \hat{y}^i = \operatorname{softmax}(W^Tx^{(i)}) = \frac{e^{W^Tx^{(i)}}}{1_C^T e ^{W^Tx^{(i)}}} y^i=softmax(WTx(i))=1CTeWTx(i)eWTx(i)

即取出概率最大的作为预测的类别

1.2 风险函数

使用交叉熵损失,对于第i个样本(总样本数为N)的损失函数为(矩阵表示):
R ( W ) = − 1 N ∑ i = 1 N ( y ( i ) ) T l o g y ^ ( i ) R(W) = -\frac{1}{N}\sum_{i=1}^{N}(y^{(i)})^T log {\hat{y}}^{(i)} R(W)=N1i=1N(y(i))Tlogy^(i)
其实就是一个求内积的过程,在对所有样本求和。

1.3 梯度函数

对于第i个样本,其梯度函数表示为(矩阵表示):
∂ L ( i ) ( W ) ∂ W = − x ( i ) ( y ( i ) − y ^ ( i ) ) T \frac{\partial L^{(i)}(W)}{\partial W} = -x^{(i)} ( y^{(i)}-\hat{y}^{(i)} )^T WL(i)(W)=x(i)(y(i)y^(i))T
因此,如果采用全批梯度下降法,那么参数的更新过程为:

初始化 W 0 ← 0 W_0 \leftarrow 0 W00,然后通过下式进行迭代更新:
W t + 1 ← W t + α ( 1 N ∑ i = 1 N x ( i ) ( y ( i ) − y ^ ( i ) ) T ) W_{t+1} \leftarrow W_t + \alpha(\frac{1}{N}\sum_{i=1}^{N}x^{(i)} ( y^{(i)}-\hat{y}^{(i)} )^T) Wt+1Wt+α(N1i=1Nx(i)(y(i)y^(i))T)

二、代码实现

2.1 Iris数据读取

import csv
import numpy as np
from matplotlib import pyplot as plt
# 样本数据的抽取
with open('iris.data') as csv_file:
    data = list(csv.reader(csv_file, delimiter=','))

label_map = {
    'Iris-setosa': 0,
    'Iris-versicolor': 1,
    'Iris-virginica':2
}
# 使用Softmax解决多分类问题

# 抽取样本
X = np.array([[float(x) for x in s[:-1]] for s in data[:150]], np.float32) # X是一个四维数据
Y = np.array([[label_map[s[-1]]] for s in data[:150]], np.float32) 

# 将 Y 转换为可以用0、1表示的向量
tmp = np.zeros((Y.shape[0],3)) # 寄存器
for i in range(Y.shape[0]):
    if Y[i] == 0:
        tmp[i] = [1,0,0]
    if Y[i] == 1:
        tmp[i] = [0,1,0]
    if Y[i] == 2:
        tmp[i] = [0,0,1]
Y = tmp

# 分割数据集

# 将数据集按照8:2划分为训练集和测试集
train_idx = np.random.choice(150, 120, replace=False)

test_idx = np.array(list(set(range(150)) - set(train_idx)))

# train-训练集 test-测试集
X_train, Y_train = X[train_idx], Y[train_idx]
b = np.ones((X_train.shape[0],1)) # 添加常数项
X_train = np.hstack((X_train, b))
X_test, Y_test = X[test_idx], Y[test_idx]
b = np.ones((X_test.shape[0],1)) # 添加常数项
X_test = np.hstack((X_test, b))

2.2 训练和测试

##########################
# 决策函数 decision function
def softmax(x,w):
    x = x.reshape(x.shape[0],1) # 转化为列向量
    a = (w.T)@x
    a = a - max(a) # 防止数据上溢出
    return np.exp(a)/(np.sum(np.exp(a)))

##########################


##########################
# 交叉熵损失函数 loss function
def loss(x,y,w):
    sum = 0; # 初始化

    for i in range(x.shape[0]):
        y_hat = softmax(x[i],w) # 预测值
        sum += np.dot(y[i],np.log(y_hat))

    return -sum/x.shape[0] # 求均值

##########################


##########################
# 梯度函数 optimizer
def gradient(x,y,w):
    # 这里注意,一维数组无法进行转置,只能先变成二维数组
    y_hat = softmax(x,w) # 预测值
    y = y.reshape(y.shape[0],1) # 变为二维矩阵
    error = (y-y_hat)
    x = x.reshape(x.shape[0],1)
    return -x @ error.T # 返回该样本点所在的梯度值
    

##########################

##########################
# 训练函数 train function
def train(x,y,w,lr=0.05,epoch=300): # 学习率是0.05,最大的迭代次数是epoch=300
    train_err = []
    test_err = []
    for i in range(epoch):
        reg = np.zeros((w.shape[0],w.shape[1])); # 存储梯度值的寄存器初始化
        if loss(x,y,w) > 0:
            for j in range(x.shape[0]):
                reg += gradient(x[j],y[j],w) # 获得所有样本梯度的累加
            reg = reg/x.shape[0] # 获得梯度均值
            w = w - lr*reg # 损失值大于0,计算梯度,更新权值
        test_err.append(test(X_test, Y_test,w))
        train_err.append(test(X_train,Y_train,w))
        # print('epoch:',i,'train error:',train_err[-1],'test error:',test_err[-1])
    return w,train_err,test_err
##########################


##########################
# 定义测试函数 Tset Function
def test(x,y,w):
    right = 0
    for i in range(x.shape[0]):
        max = np.argmax(softmax(x[i],w)) # 最大值所在位置
        max_y = np.argmax(y[i]) # 找到y中1的位置,就是所属的分类类别
        if max == max_y:
            right += 1
    return 1- right/x.shape[0]
##########################


w = np.ones((X_train.shape[1],Y_train.shape[1]))
w,train_err,test_err = train(X_train,Y_train,w) 
print(w)
print('最终训练误差和测试误差','train error:',train_err[-1],'test error:',test_err[-1])
# 绘制训练误差 train error
plt.plot(train_err)
plt.title('Softmax')
plt.xlabel('epoch')
plt.ylabel('train error')
plt.ylim((-0.3, 1))
plt.grid()
plt.show()

[[ 1.3960391   1.26663754  0.33732336]
 [ 1.98074793  0.6978966   0.32135547]
 [-0.41965035  1.14600963  2.27364073]
 [ 0.33760001  0.69904297  1.96335702]
 [ 1.20345149  1.14126093  0.65528758]]
最终训练误差和测试误差 train error: 0.01666666666666672 test error: 0.09999999999999998

请添加图片描述

# 绘制测试误差test error
plt.plot(test_err)
plt.title('Softmax')
plt.xlabel('epoch')
plt.ylabel('test error')
plt.ylim((-0.3, 1))
plt.grid()
plt.show()


请添加图片描述

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值