基于Softmax多分类+全批量梯度下降,实现三分类

本文章是笔者在大三时的《模式识别》课程作业,如今将此作业上传供网友学习。

1 S o f t m a x {Softmax} Softmax多分类的基本原理

1.1 S o f t m a x {Softmax} Softmax模型

s o f t m a x {softmax} softmax多分类器,一种基于 s o f t m a x {softmax} softmax函数的分类器,它可以预测一个样本属于每个样本的概率。 s o f t m a x {softmax} softmax一般用于神经网络的输出层,叫做 s o f t m a x {softmax} softmax层。
s o f t m a x {softmax} softmax函数适用于处理多分类问题,应用广泛的逻辑函数就是 s o f t m a x softmax softmax函数在二分类情形下的特例。 s o f t m a x softmax softmax函数将一个 n n n维的输入向量映射为n维的向量,使得输出向量的各元素取值在0到1之间,且所有元素之和为1,即所得到的向量可以作为事件发生的概率。
记函数的输入向量为: Z = ( z 1 , z 2 , ⋯   , z n ) ⊤ Z = (z_1,z_2,\cdots,z_n)^\top Z=(z1,z2,,zn),则函数值为:
s o f t m a x ( X ) = ( e x 1 ∑ i = 1 n e x i , e x 2 ∑ i = 1 n e x i , ⋯   , e x n ∑ i = 1 n e x i ) ⊤ softmax(X) =(\frac{e^{x_1}}{\sum_{i=1}^{n}e^{x_i}},\frac{e^{x_2}}{\sum_{i=1}^{n}e^{x_i}},\cdots,\frac{e^{x_n}}{\sum_{i=1}^{n}e^{x_i}})^\top softmax(X)=(i=1nexiex1,i=1nexiex2,,i=1nexiexn)

1.2 多分类模型

 对一个激活函数为 s o f t m a x softmax softmax的单个神经元,记输入是一个有m个样本的数据,且每一个数据有n维:
X = [ x 10 x 11 x 12 ⋯ x 1 n x 20 x 21 x 22 ⋯ x 2 n ⋮ ⋮ ⋮ ⋱ ⋮ x m 0 x m 1 x m 2 ⋯ x m n ] X=\left[ \begin{matrix} x_{10} & x_{11} & x_{12} & \cdots & x_{1n} \\ x_{20} & x_{21} & x_{22} & \cdots & x_{2n} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ x_{m0} & x_{m1} & x_{m2} & \cdots & x_{mn} \\ \end{matrix} \right] X= x10x20xm0x11x21xm1x12x22xm2x1nx2nxmn
 其中, X \mathbf{X} X第一列数据全部为1,是人为加入的bias项,表示模型带有偏置(即考虑截距项)。 X i j ( 1 ≤ i ≤ m , 1 ≤ j ≤ n ) X_{ij}(1\leq i\leq m,1\leq j\leq n) Xij(1im,1jn)表示第i个样本的第j个特征的值。
该样本对应的真实类别为:
Y = [ y 11 y 12 ⋯ y 1 k y 21 y 22 ⋯ y 2 k ⋮ ⋮ ⋱ ⋮ y m 1 y m 2 ⋯ y m k ] Y=\left[ \begin{matrix} y_{11} & y_{12} & \cdots & y_{1k} \\ y_{21} & y_{22} & \cdots & y_{2k} \\ \vdots & \vdots & \ddots & \vdots \\ y_{m1} & y_{m2} & \cdots & y_{mk} \\ \end{matrix} \right] Y= y11y21ym1y12y22ym2y1ky2kymk
 Y的每一行只有一个值为1,其它全为0。 y i j = 1 ( 1 ≤ i ≤ m , 1 ≤ j ≤ k ) y_{ij}=1 (1\leq i\leq m,1\leq j\leq k) yij=1(1im,1jk)表示第i个样本对应的类别为第j类。
记待估计的参数为
Ω = [ ω 01 ω 02 ⋯ ω 0 k ω 11 ω 12 ⋯ ω 1 k ω 21 ω 22 ⋯ ω 2 k ⋮ ⋮ ⋱ ⋮ ω n 1 ω n 2 ⋯ ω n k ] \Omega = \left[ \begin{matrix} \omega_{01} & \omega_{02} & \cdots & \omega_{0k} \\ \omega_{11} & \omega_{12} & \cdots & \omega_{1k} \\ \omega_{21} & \omega_{22} & \cdots & \omega_{2k} \\ \vdots & \vdots & \ddots & \vdots \\ \omega_{n1} & \omega_{n2} & \cdots & \omega_{nk} \\ \end{matrix} \right] Ω= ω01ω11ω21ωn1ω02ω12ω22ωn2ω0kω1kω2kωnk
 记softmax函数的自变量为:
Z = [ z 11 z 12 ⋯ z 1 k z 21 z 22 ⋯ z 2 k ⋮ ⋮ ⋱ ⋮ z m 1 z m 2 ⋯ z m k ] Z = \left[ \begin{matrix} z_{11} & z_{12} & \cdots & z_{1k} \\ z_{21} & z_{22} & \cdots & z_{2k} \\ \vdots & \vdots & \ddots & \vdots \\ z_{m1} & z_{m2} & \cdots & z_{mk} \\ \end{matrix} \right] Z= z11z21zm1z12z22zm2z1kz2kzmk
 Z是模型输入数据的加权求和,即 z i j = ∑ k = 0 n x i k ω k j z_{ij} = \sum_{k=0}^{n}x_{ik}\omega_{kj} zij=k=0nxikωkj, Z = X Ω Z = X\Omega Z=XΩ
记:
Y ^ = s o f t m a x ( Z ) = [ y ^ 11 y ^ 12 ⋯ y ^ 1 k y ^ 21 y ^ 22 ⋯ y ^ 2 k ⋮ ⋮ ⋱ ⋮ y ^ m 1 y ^ m 2 ⋯ y ^ m k ] \hat{Y} = softmax(Z) = \left[ \begin{matrix} \hat{y}_{11} & \hat{y}_{12} & \cdots & \hat{y}_{1k} \\ \hat{y}_{21} & \hat{y}_{22} & \cdots & \hat{y}_{2k} \\ \vdots & \vdots & \ddots & \vdots \\ \hat{y}_{m1} & \hat{y}_{m2} & \cdots & \hat{y}_{mk} \\ \end{matrix} \right] Y^=softmax(Z)= y^11y^21y^m1y^12y^22y^m2y^1ky^2ky^mk
 其中 y ^ i j = e z i j ∑ p = 1 k e z i p \hat{y}_{ij} = \frac{e^{z_{ij}}}{\sum_{p=1}^{k}e^{z_{ip}}} y^ij=p=1kezipezij,表示模型眼中第 i i i个样本属于第 j j j类的概率。

1.3 代价函数

 定义模型的总代价函数为
C O S T ( X ) = − 1 m ∑ i = 0 m ( ∑ j = 1 k y i j ln ⁡ y ^ i j ) COST(X) = -\frac{1}{m}\sum_{i=0}^{m}(\sum_{j=1}^{k}y_{ij}\ln\hat{y}_{ij}) COST(X)=m1i=0m(j=1kyijlny^ij)
 将代价函数视为参数 Ω \Omega Ω的函数 J Ω J_{\Omega} JΩ,这就是我们要优化的目标。

 使用梯度下降求解目标函数极小值:
 由链式法则可知,
∂ J Ω ∂ ω p j = ∑ i = 1 m ∂ J Ω ∂ z i j ∂ z i j ∂ ω p j \frac{\partial J_\Omega}{\partial \omega_{pj}} = \sum_{i=1}^{m} \frac{\partial J_\Omega}{\partial z_{ij}}\frac{\partial z_{ij}}{\partial \omega_{pj}} ωpjJΩ=i=1mzijJΩωpjzij
 而
∂ J Ω ∂ z i p = ∂ ∑ q = 0 m ( − ∑ j = 1 k ln ⁡ y ^ q j ) ∂ z i p = − ∑ j = 1 k y i j y ^ i j ∂ y ^ i j ∂ z i p \frac{\partial J_\Omega}{\partial z_{ip}}=\frac{\partial \sum_{q=0}^{m}(-\sum_{j=1}^{k}\ln\hat{y}_{qj})}{\partial z_{ip}}= -\sum_{j=1}^{k}\frac{{y}_{ij}}{\hat{y}_{ij}}\frac{\partial\hat{y}_{ij}}{\partial z_{ip}} zipJΩ=zipq=0m(j=1klny^qj)=j=1ky^ijyijzipy^ij
 由于
∂ y ^ i j ∂ z i p = { = e z i j ∑ q = 1 k e z i q − e z i j e z i p ( ∑ q = 1 k e z i q ) 2 = y ^ i p − y ^ i p 2 j = p = − e z i j e z i p ( ∑ q = 1 k e z i q ) 2 = − y ^ i j y i p ^ j ≠ p \begin{equation} \frac{\partial\hat{y}_{ij}}{\partial z_{ip}}=\left\{ \begin{aligned} & =\frac{e^{z_{ij}}}{\sum_{q=1}^{k}e^{z_{iq}}}-\frac{e^{z_{ij}}e^{z_{ip}}}{(\sum_{q=1}^{k}e^{z_{iq}})^2}=\hat{y}_{ip}-\hat{y}_{ip}^2 &j=p \\ & =-\frac{e^{z_{ij}}e^{z_{ip}}}{(\sum_{q=1}^{k}e^{z_{iq}})^2}=-\hat{y}_{ij}\hat{y_ip} &j\neq p \\ \end{aligned} \right. \end{equation} zipy^ij= =q=1keziqezij(q=1keziq)2ezijezip=y^ipy^ip2=(q=1keziq)2ezijezip=y^ijyip^j=pj=p
将(3)式带入(2)式,由于 ∑ j = 1 k y i j = 1 \sum_{j=1}^{k}y_{ij}=1 j=1kyij=1,有
∂ J Ω ∂ z i p = y ^ i p − y i p \frac{\partial J_\Omega}{\partial z_{ip}}=\hat{y}_{ip}-y_{ip} zipJΩ=y^ipyip
考虑 z i p = ∑ q = 0 n x i q ω q p z_{ip}=\sum_{q=0}^{n}x_{iq}\omega_{qp} zip=q=0nxiqωqp,并将(4)式带入(1)式,得到:
∂ J Ω ∂ ω p j = ∑ i = 1 m ∂ J Ω ∂ z i j x i p = ∑ i = 1 m ( y ^ i j − y i j ) x i p \frac{\partial J_\Omega}{\partial \omega_{pj}}=\sum_{i=1}^{m}\frac{\partial J_\Omega}{\partial z_{ij}}x_{ip}=\sum_{i=1}^{m}(\hat{y}_{ij}-y_{ij})x_{ip} ωpjJΩ=i=1mzijJΩxip=i=1m(y^ijyij)xip

写回矩阵的形式,有:
∇ J Ω = [ J Ω ω 01 J Ω ω 02 ⋯ J Ω ω 0 k J Ω ω 11 J Ω ω 12 ⋯ J Ω ω 1 k ⋮ ⋮ ⋱ ⋮ J Ω ω n 1 J Ω ω n 2 ⋯ J Ω ω n k ] = [ ∑ i = 1 m x i 0 ( y ^ i 1 − y i 1 ) ∑ i = 1 m x i 0 ( y ^ i 2 − y i 2 ) ⋯ ∑ i = 1 m x i 0 ( y ^ i k − y i k ) ∑ i = 1 m x i 1 ( y ^ i 1 − y i 1 ) ∑ i = 1 m x i 1 ( y ^ i 2 − y i 2 ) ⋯ ∑ i = 1 m x i 1 ( y ^ i k − y i k ) ⋮ ⋮ ⋱ ⋯ ∑ i = 1 m x i n ( y ^ i 1 − y i 1 ) ∑ i = 1 m x i n ( y ^ i 2 − y i 2 ) ⋯ ∑ i = 1 m x i n ( y ^ i k − y i k ) ] \nabla J_\Omega = \left[ \begin{matrix} \frac{J_\Omega}{\omega_{01}} &\frac{J_\Omega}{\omega_{02}} & \cdots & \frac{J_\Omega}{\omega_{0k}} \\ \frac{J_\Omega}{\omega_{11}} &\frac{J_\Omega}{\omega_{12}} & \cdots & \frac{J_\Omega}{\omega_{1k}} \\ \vdots & \vdots & \ddots &\vdots \\ \frac{J_\Omega}{\omega_{n1}} &\frac{J_\Omega}{\omega_{n2}} & \cdots & \frac{J_\Omega}{\omega_{nk}} \\ \end{matrix} \right]=\left[ \begin{matrix} \sum_{i=1}^{m}x_{i0}(\hat{y}_{i1}-y_{i1}) & \sum_{i=1}^{m}x_{i0}(\hat{y}_{i2}-y_{i2}) & \cdots & \sum_{i=1}^{m}x_{i0}(\hat{y}_{ik}-y_{ik})\\ \sum_{i=1}^{m}x_{i1}(\hat{y}_{i1}-y_{i1}) & \sum_{i=1}^{m}x_{i1}(\hat{y}_{i2}-y_{i2}) & \cdots & \sum_{i=1}^{m}x_{i1}(\hat{y}_{ik}-y_{ik})\\ \vdots & \vdots & \ddots & \cdots \\ \sum_{i=1}^{m}x_{in}(\hat{y}_{i1}-y_{i1}) & \sum_{i=1}^{m}x_{in}(\hat{y}_{i2}-y_{i2}) & \cdots & \sum_{i=1}^{m}x_{in}(\hat{y}_{ik}-y_{ik})\\ \end{matrix} \right] JΩ= ω01JΩω11JΩωn1JΩω02JΩω12JΩωn2JΩω0kJΩω1kJΩωnkJΩ = i=1mxi0(y^i1yi1)i=1mxi1(y^i1yi1)i=1mxin(y^i1yi1)i=1mxi0(y^i2yi2)i=1mxi1(y^i2yi2)i=1mxin(y^i2yi2)i=1mxi0(y^ikyik)i=1mxi1(y^ikyik)i=1mxin(y^ikyik)
梯度已经求出来了,指定步长使用梯度下降方法求解即可。

1.4算法流程

  • 输入:训练数据集为 D = { ( x i , y i ) } i = 1 m D=\left\{(x_i,y_i) \right\}_{i=1}^{m} D={(xi,yi)}i=1m,其中, x i ∈ X ⊆ R n , y i ∈ Y x_i\in \boldsymbol{X}\subseteq \boldsymbol{R}^n,y_i\in \boldsymbol{Y} xiXRn,yiY;学习率 η ( 0 < η ⩽ 1 ) \eta( 0<\eta \leqslant 1) η(0<η1)
  • 过程:
    梯度下降算法迭代更新模型参数直至收敛,每一轮具体流程如下:
    ( 1 ) (1) (1)选取初值 w w w;
    ( 2 ) (2) (2)更新 w w w: 首先通过正向传播求得本轮训练样本预测值,然后反向传播更新模型参数:
    w p j ← w p j − η 1 m ∂ J Ω ∂ ω p j = w p j − e t a 1 m ∑ i = 1 m ( y ^ i j − y i j ) x i p w_{pj}\gets w_{pj}-\eta\frac{1}{m}\frac{\partial J_\Omega}{\partial \omega_{pj}}=w_{pj}-eta\frac{1}{m}\sum_{i=1}^{m}(\hat{y}_{ij}-y_{ij})x_{ip} wpjwpjηm1ωpjJΩ=wpjetam1i=1m(y^ijyij)xip
    ( 3 ) (3) (3)一直重复步骤2,直至模型参数收敛
  • 输出: w w w

2 三分类流程

# 导入所需库
import csv
import numpy as np
from matplotlib import pyplot as plt
import pylab
  • 读取Iris数据集,并查看部分数据
  • 抽取样本:取前两类样本(共150条),将数据集的4个属性作为自变量X。将数据集的3个类别映射为{0,1,2},作为因变量Y。
# 样本数据的抽取
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) 

使用One-Hot独热编码,并且抽取训练集和测试集

# 将 Y 转换为可以用0、1、2表示的向量
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))
# print(X_train)
# print(Y_train)

定义 S o f t m a x Softmax Softmax多分类class

class Softmax(object):  # 定义Softmax多分类class
    def __init__(self, X, Y,TX,TY,epoch,eta):  # X为训练集样本,Y是训练集结果, TX为测试集样本,TY是测试集结果,epoch是训练次数,eta是学习率
        if X.shape[0] != Y.shape[0]:  # 要求X,Y中的数目一样
            raise ValueError('Error,X and Y must be same when axis=0 ')
        else:  # 在类中储存参数
            self.X = X
            self.Y = Y
            self.TX = TX
            self.TY = TY
            self.epoch = epoch
            self.eta = eta
            self.m=self.X.shape[0]#m个数据样本
            self.n=self.X.shape[1]#n个特征
            self.k=self.Y.shape[1]#k个类别
    def softmax(self,x,w):
        a=x@w #(m*n)*(n*k),得到的a是一个(m*k)维矩阵
        if x.ndim==1:
            sum=np.sum(np.exp(a))#如果输入的是向量则直接求和
        else:
            sum=np.sum(np.exp(a),axis=1).reshape(x.shape[0],1)
            #如果输入的是矩阵,sum对行求和后输出向量,reshape将向量转化为矩阵,然后除法需要用到矩阵的广播运算
        return np.exp(a)/(sum)#,按行求和,其实得到的a就是y的预测值
    

    def loss(self,w):#损失函数在迭代过程中根本就用不到
        sum=0
        for i in range(self.m):
            y_hat=Softmax.softmax(self,self.X[i],w)
            sum += np.dot(self.Y[i],np.log(y_hat))
        return -sum/self.m    
    
    def grad(self,w):#计算出梯度矩阵
        Y_hat=Softmax.softmax(self,self.X,w)#所有样本的预测值,y_hat是m*k大小的矩阵
        error=Y_hat-self.Y
        # print(self.X.shape)
        # print(error.shape)
        gradient=self.X.T@error#定义梯度矩阵
        # print(gradient)
        return gradient

    
    def test(self,x,y,w):
        num=0
        for i in range(x.shape[0]):
            max_hat_index=np.argmax(Softmax.softmax(self,x[i],w))
            max_y_index=np.argmax(y[i])
            if max_hat_index==max_y_index:
                num += 1
        return 1-num/x.shape[0]


    def train(self):
        train_err=[]
        test_err=[]
        w = np.ones((self.n,self.k))
        for i in range(self.epoch):
            grad_reg=Softmax.grad(self,w)/self.m
            w=w-self.eta*grad_reg# 损失值大于0,计算梯度,更新权值
            # print(w)
            train_err.append(Softmax.test(self,self.X,self.Y,w))
            test_err.append(Softmax.test(self,self.TX,self.TY,w))
        return w,train_err,test_err

训练函数

epoch=500#迭代次数
eta=0.05#学习率
SOFT=Softmax(X_train, Y_train,X_test,Y_test,epoch, eta)
w,train_err,test_err = SOFT.train() 

结果输出和可视化

print("Softmax多分类模型参数:")
print(w)
print('最终训练误差和测试误差:')
print('train error:',train_err[-1])
print('test error:',test_err[-1])
plt.figure(figsize=(12, 6))#设置图片大小
plt.style.use('seaborn-darkgrid') # 设置画图的风格 
# 绘制训练误差 train error
plt.subplot(1, 2, 1)
plt.plot(train_err)
plt.title('Softmax')
plt.xlabel('epoch')
plt.ylabel('train error')
# 绘制测试误差test error
plt.subplot(1, 2, 2)
plt.plot(test_err)
plt.title('Softmax')
plt.xlabel('epoch')
plt.ylabel('test error')

输出结果

Softmax多分类模型参数:
[[ 1.46855411  1.40304271  0.12840318]
 [ 2.25369077  0.69785336  0.04845587]
 [-0.71491953  1.07995137  2.63496816]
 [ 0.21334229  0.49745047  2.28920724]
 [ 1.23399573  1.22614849  0.53985578]]
最终训练误差和测试误差:
train error: 0.025000000000000022
test error: 0.0
Text(0, 0.5, 'test error')

在这里插入图片描述

4 实验总结

4.1实验中遇到的状况

 在实验中,借鉴他人的代码时,因为大多数的代码都是将用到的部分全都写为了函数,我主要花费的精力是理解算法过程并将这些函数整合为一个类。

  • 而且遇到的代码主要是进行向量运算,我起初以为python和matlab一样,将向量也看作了矩阵,但是代码一直报错,最后通过输出样例,发现了python中向量和矩阵是不同的概念,基于此我将所有的函数都改为了既可以进行矩阵运算也可以进行向量运算,其实就是加了几句判断语句,但是发现这个问题耗费了大量的时间。
  • 另外因为测试函数的return 语句的缩进不对,导致测试误差和训练误差的数据一直是凌乱的数据,最后想要逐个输出误差时,发现了该问题。

4.2 实验感悟

  • S o f t m a x Softmax Softmax完成多分类的问题有了一个初步的认识,对其算法编程过程有了系统性的理解。
  • 了解道路三种梯度下降算法,明晰了三种算法的具体区别与优缺点(篇幅限制,未写在作业中),并使用了全批量梯度下降算法实现了三分类问题。
  • 对进行类的封装和增加函数的通用性方面的编程能力有了提升

5 借鉴博客

[1] 桃源梦 \quad 梯度下降处理softmax函数多分类问题 \quad https://www.cnblogs.com/Reader-Yu/p/10665239.html
[2] 明·煜 \quad 作业二·Softmax实现多分类 \quad https://blog.csdn.net/weixin_53195427/article/details/130358620?spm=1001.2014.3001.5502
[3] Twilight Sparkle. \quad 【机器学习笔记13】softmax多分类模型【上篇】完整流程与详细公式推导 \quad https://blog.csdn.net/qq_52466006/article/details/127525149
[4] Twilight Sparkle. \quad 机器学习笔记14】softmax多分类模型【下篇】从零开始自己实现softmax多分类器(含具体代码与示例数据集) \quad https://blog.csdn.net/qq_52466006/article/details/127555367

根据引用[2]中的描述,softmax回归是一种多分类算法,它使用softmax函数将输出映射到多维向量。在训练过程中,我们需要使用梯度下降算法来最小化损失函数。下面是softmax梯度下降算法的步骤: 1.初始化权重矩阵W和偏置向量b。 2.对于每个训练样本,计算其预测输出y_pred,即将输入x乘以权重矩阵W并加上偏置向量b,然后将结果输入softmax函数得到多维向量。 3.计算损失函数L,通常使用交叉熵损失函数。 4.计算损失函数对权重矩阵W和偏置向量b的梯度,即反向传播。 5.使用梯度下降算法更新权重矩阵W和偏置向量b,即W = W - learning_rate * dW,b = b - learning_rate * db,其中learning_rate是学习率,dW和db是损失函数对W和b的梯度。 6.重复步骤2到步骤5,直到达到停止条件,例如达到最大迭代次数或损失函数的变化量小于某个阈值。 下面是一个使用Python实现softmax梯度下降算法的例子: ```python import numpy as np # 定义softmax函数 def softmax(x): exp_x = np.exp(x) return exp_x / np.sum(exp_x, axis=1, keepdims=True) # 定义交叉熵损失函数 def cross_entropy_loss(y_pred, y_true): m = y_pred.shape[0] log_likelihood = -np.log(y_pred[range(m), y_true]) loss = np.sum(log_likelihood) / m return loss # 定义softmax梯度下降算法 def softmax_gradient_descent(X, y_true, num_classes, learning_rate, num_iterations): # 初始化权重矩阵W和偏置向量b m, n = X.shape W = np.zeros((n, num_classes)) b = np.zeros((1, num_classes)) # 梯度下降迭代 for i in range(num_iterations): # 计算预测输出y_pred z = np.dot(X, W) + b y_pred = softmax(z) # 计算损失函数L loss = cross_entropy_loss(y_pred, y_true) # 计算梯度 dW = np.dot(X.T, (y_pred - y_true)) db = np.sum(y_pred - y_true, axis=0, keepdims=True) # 更新权重矩阵W和偏置向量b W -= learning_rate * dW b -= learning_rate * db # 打印损失函数 if i % 100 == 0: print("Iteration %d, loss = %f" % (i, loss)) return W, b # 测试 X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) y_true = np.array([0, 1, 2, 1]) num_classes = 3 learning_rate = 0.1 num_iterations = 1000 W, b = softmax_gradient_descent(X, y_true, num_classes, learning_rate, num_iterations) print("W = ", W) print("b = ", b) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值