【转载】深度学习笔记——详解损失函数

news2024/9/26 5:22:08

原文链接: https://blog.csdn.net/weixin_53765658/article/details/136360033
CSDN账号: Purepisces
github账号: purepisces
希望大家可以Star Machine Learning Blog https://github.com/purepisces/Wenqing-Machine_Learning_Blog

损失函数

根据您使用的神经网络类型和数据类型,不同的损失函数可能会变得有用,例如分类问题的交叉熵损失,回归问题的均方误差。了解这些损失函数是如何计算的,以及它们将如何用于更新您的网络是很重要的。

损失类

类属性:

  • A A A:存储模型预测以计算反向传播。
  • Y Y Y:存储期望输出以计算反向传播。

类方法:

  • f o r w a r d forward forward

    • 参数: A A A(模型预测), Y Y Y(期望输出)
    • 返回值:损失值 L L L
    • 描述:计算并返回标量损失值 L L L,量化网络输出和期望输出之间的不匹配。
  • b a c k w a r d backward backward

    • 返回值: d L d A dLdA dLdA(模型输出变化如何影响损失 L L L
    • 描述:计算并返回 d L d A dLdA dLdA,表示模型输出 A A A 的变化如何影响损失 L L L。它使得可以进行反向传播的下游计算。

请考虑以下类结构:

class Loss:
        def forward(self, A, Y):
            self.A = A
            self.Y = Y
            self.    # todo(根据需要存储额外的属性)
            N      = # todo,这是 A 和 Y 的第一维度
            C      = # todo,这是 A 和 Y 的第二维度
            # todo
            
            return L

        def backward(self):
            dLdA = # 待办事项

            return dLdA
代码名称数学符号类型形状含义
N N N N标量-批量大小
C C C C标量-类别数目
A A A A矩阵 N × C N \times C N×C模型输出
Y Y Y Y矩阵 N × C N \times C N×C真实值
L L L L标量-损失值
dLdA ∂ L ∂ A \frac{\partial L}{\partial A} AL矩阵 N × C N \times C N×C模型输出变化如何影响损失

注意:在回归任务的上下文中,对应于类别数目的维度 C C C 简化为 1。这是因为回归问题涉及预测单个连续变量,而不是从多个类别中选择。相反,在分类场景中, C C C 代表每个输入可以被分类的不同类别或类别的总数,因此可以根据具体问题而变化。

损失函数拓扑在下图中可视化:

在这里插入图片描述

示例

在此示例中,我们将演示如何在具有3个类别的分类任务中使用 L o s s Loss Loss 类。假设我们的批量大小( N N N)为2,这意味着我们一次处理两个示例。

模型输出(Logits)

模型输出,表示为 A A A,是每个类别的logits。对于我们的示例,批量大小为2且有3个类别, A A A 可能如下所示:

A = [ 5 1 − 1 − 2 6 0 ] A = \begin{bmatrix} 5 & 1 & -1\\ -2 & 6 & 0 \end{bmatrix} A=[521610]

这些logits代表每个类别的原始分数,在应用softmax函数之前。

真实值(Y)

真实值 Y Y Y 以独热编码(one-hot encoded)格式表示:

Y = [ 1 0 0 0 0 1 ] Y = \begin{bmatrix} 1 & 0 & 0\\ 0 & 0 & 1 \end{bmatrix} Y=[100001]

这里,第一行 [ 1 , 0 , 0 ] [1, 0, 0] [1,0,0] 表示第一个示例属于第1类,第二行 [ 0 , 0 , 1 ] [0, 0, 1] [0,0,1] 表示第二个示例属于第3类。

在损失计算中使用 A A A Y Y Y

损失函数使用logits A A A 和真实值 Y Y Y 来计算损失值 L L L。例如,使用交叉熵损失函数会首先对logits应用softmax函数以获得概率,然后通过将这些预测概率与 Y Y Y 中的实际标签进行比较来计算每个单独示例的损失。随后,这些单独的损失在批次中的所有示例上平均,以产生损失的单一标量值, L L L

L o s s Loss Loss 类中的 f o r w a r d forward forward 方法负责使用 A A A(作为logits)和 Y Y Y 来计算这个标量损失值 L L L。接着, b a c k w a r d backward backward 方法计算损失对于logits的梯度,表示为 ∂ L ∂ A \frac{\partial L}{\partial A} AL。这个梯度对于反向传播过程至关重要,使得在训练期间可以更新模型参数。

详解均方误差损失函数:

均方误差(MSE,Mean Squared Error)是回归问题中评估预测误差的一种广泛使用的指标。在回归中,目标是预测连续值,例如根据房屋的特征(如面积、位置、卧室数量等)估计房屋的价格。

MSE 损失前向方程

计算从计算模型预测( A A A)与实际真值( Y Y Y)之间的平方误差( S E SE SE)开始:

S E ( A , Y ) = ( A − Y ) ⊙ ( A − Y ) SE(A, Y) = (A - Y) \odot (A - Y) SE(A,Y)=(AY)(AY)

接下来,我们确定平方误差之和( S S E SSE SSE)。这里, ι N \iota_N ιN ι C \iota_C ιC 分别表示大小为 N N N C C C 的、填充有 1 的列向量:

S S E ( A , Y ) = ι N T ⋅ S E ( A , Y ) ⋅ ι C SSE(A,Y) = \iota_{N}^{T} \cdot SE(A,Y) \cdot \iota_{C} SSE(A,Y)=ιNTSE(A,Y)ιC

这个操作将 S E ( A , Y ) SE(A, Y) SE(A,Y) 矩阵中的所有元素求和,该矩阵的维度为 N × C N \times C N×C。通过 ι N T \iota_{N}^{T} ιNT 的乘法在行间聚合错误,随后通过 ι C \iota_{C} ιC 的乘法将这些在列间求和,产生一个单一标量的总误差。

然后计算每个组件的均方误差( M S E MSE MSE)损失:

M S E L o s s ( A , Y ) = S S E ( A , Y ) N ⋅ C MSELoss(A, Y) = \frac{SSE(A, Y)}{N \cdot C} MSELoss(A,Y)=NCSSE(A,Y)

MSE 损失反向方程

在反向传播过程中,需要计算 MSE 损失相对于模型输出( A A A)的梯度,以更新模型参数:

M S E L o s s . b a c k w a r d ( ) = 2 ⋅ ( A − Y ) N ⋅ C MSELoss.backward() = 2 \cdot \frac{(A - Y)}{N \cdot C} MSELoss.backward()=2NC(AY)

MSE 损失的导数

MSE 损失函数定义为:

M S E L o s s ( A , Y ) = 1 N ⋅ C ∑ i = 1 N ∑ j = 1 C ( A i j − Y i j ) 2 MSELoss(A, Y) = \frac{1}{N \cdot C} \sum\limits_{i=1}^{N} \sum\limits_{j=1}^{C} (A_{ij} - Y_{ij})^2 MSELoss(A,Y)=NC1i=1Nj=1C(AijYij)2

其中:

A A A:模型预测值。

Y Y Y:真实值。

N N N:批次中的样本数量。

C C C:每个样本的输出维度,回归任务中通常为 1。

为了更新模型参数(在这个例子中,通过反向传播),我们需要知道 A A A 的变化如何影响损失。这由损失函数相对于 A A A 的导数给出,表示为 ∂ M S E L o s s ∂ A \frac{\partial MSELoss}{\partial A} AMSELoss

∂ M S E L o s s ∂ A = 2 ⋅ ( A − Y ) N ⋅ C \frac{\partial MSELoss}{\partial A} = 2 \cdot \frac{(A - Y)}{N \cdot C} AMSELoss=2NC(AY)

梯度 ∂ M S E L o s s ∂ A \frac{\partial MSELoss}{\partial A} AMSELoss 指向损失函数最陡增加的方向。通过向相反方向移动(即,从预测 A A A 中减去这个梯度),我们可以减少损失,这是训练模型的目标。

总之, M S E L o s s . b a c k w a r d ( ) MSELoss.backward() MSELoss.backward() 2 ⋅ ( A − Y ) N ⋅ C 2 \cdot \frac{(A - Y)}{N \cdot C} 2NC(AY) 公式是通过对预测 A A A 求 MSE 损失函数的导数得到的,考虑了平方误差和平均操作。这个梯度在优化过程中被用来调整模型参数,以最小化损失。

import numpy as np

class MSELoss:
    def forward(self, A, Y):
        # 为反向计算存储预测值(A)和真实值(Y)
        self.A = A
        self.Y = Y
        # 计算预测值和真实值之间的平方误差
        se = (A - Y) ** 2
        # 对平方误差求和以得到总的平方误差
        sse = np.sum(se)
        # 通过将总的平方误差除以元素数量来计算均方误差
        mse = sse / (A.shape[0] * A.shape[1])
        return mse

    def backward(self):
        # 计算损失相对于预测值(A)的梯度
        dLdA = 2 * (self.A - self.Y) / (self.A.shape[0] * self.A.shape[1])
        return dLdA

示例

让我们通过一个具体的例子来了解在回归场景中如何应用均方误差(MSE)损失。假设我们正试图基于一些特征来预测房屋价格。为了简单起见,我们将考虑一个案例,其中我们的模型基于多个特征(例如平方英尺面积和卧室数量)来预测两栋房屋的价格,因此我们的批量大小 N N N 为 2,特征数量 C C C 也为 2。

给定数据:

  • 模型输出 ( A A A):预测的两栋房屋的价格和卧室数量。假设模型对每栋房屋的预测如下(价格以美元计,卧室以数量计)。这可以表示为一个 2x2 矩阵(因为 N = 2 N=2 N=2 C = 2 C=2 C=2):

A = [ 300 , 000 3 500 , 000 4 ] A = \begin{bmatrix} 300,000 & 3 \\ 500,000 & 4 \end{bmatrix} A=[300,000500,00034]

这里,第一列代表两栋房屋的预测价格,第二列代表预测的卧室数量。

  • 真实值 ( Y Y Y):两栋房屋的实际价格和卧室数量。这也是一个 2x2 矩阵:

Y = [ 350 , 000 4 450 , 000 3 ] Y = \begin{bmatrix} 350,000 & 4 \\ 450,000 & 3 \end{bmatrix} Y=[350,000450,00043]

正向传播(计算 MSE 损失):

  1. 计算平方误差 ( S E SE SE):

S E ( A , Y ) = ( A − Y ) ⊙ ( A − Y ) = [ ( 300 , 000 − 350 , 000 ) 2 ( 3 − 4 ) 2 ( 500 , 000 − 450 , 000 ) 2 ( 4 − 3 ) 2 ] = [ 2500 × 1 0 6 1 2500 × 1 0 6 1 ] \begin{align} SE(A, Y) &= (A - Y) \odot (A - Y) \\ &= \begin{bmatrix} (300,000 - 350,000)^2 & (3 - 4)^2 \\ (500,000 - 450,000)^2 & (4 - 3)^2 \end{bmatrix} \\ &= \begin{bmatrix} 2500 \times 10^6 & 1 \\ 2500 \times 10^6 & 1 \end{bmatrix} \end{align} SE(A,Y)=(AY)(AY)=[(300,000350,000)2(500,000450,000)2(34)2(43)2]=[2500×1062500×10611]

  1. 平方误差之和 ( S S E SSE SSE):
    S E SE SE 中的所有元素相加:

S S E ( A , Y ) = ∑ S E ( A , Y ) = 2 × ( 2500 × 1 0 6 ) + 2 × 1 = 5000 × 1 0 6 + 2 SSE(A, Y) = \sum SE(A, Y) = 2 \times (2500 \times 10^6) + 2 \times 1 = 5000 \times 10^6 + 2 SSE(A,Y)=SE(A,Y)=2×(2500×106)+2×1=5000×106+2

  1. 均方误差 ( M S E MSE MSE):

M S E L o s s ( A , Y ) = S S E ( A , Y ) N ⋅ C = 5000 × 1 0 6 + 2 2 × 2 = 2500 × 1 0 6 + 1 2 MSELoss(A, Y) = \frac{SSE(A, Y)}{N \cdot C} = \frac{5000 \times 10^6 + 2}{2 \times 2} = \frac{2500 \times 10^6 + 1}{2} MSELoss(A,Y)=NCSSE(A,Y)=2×25000×106+2=22500×106+1

反向传播(计算梯度):

可以计算损失相对于预测值 ( A A A) 的梯度:

∂ M S E L o s s ∂ A = 2 ⋅ ( A − Y ) N ⋅ C = 2 ⋅ [ 300 , 000 − 350 , 000 3 − 4 500 , 000 − 450 , 000 4 − 3 ] 2 × 2 = 1 2 [ − 50 , 000 − 1 50 , 000 1 ] \begin{align} \frac{\partial MSELoss}{\partial A} &= 2 \cdot \frac{(A - Y)}{N \cdot C} \\ &= 2 \cdot \frac{\begin{bmatrix} 300,000 - 350,000 & 3 - 4 \\ 500,000 - 450,000 & 4 - 3 \end{bmatrix}}{2 \times 2} \\ &= \frac{1}{2} \begin{bmatrix} -50,000 & -1 \\ 50,000 & 1 \end{bmatrix} \end{align} AMSELoss=2NC(AY)=22×2[300,000350,000500,000450,0003443]=21[50,00050,00011]

这个梯度矩阵提供了如何调整每个预测(价格和卧室数量)以最小化损失的指导。负值表示需要增加预测值,正值表明需要减少预测值以减少误差。

详解交叉熵损失函数:

交叉熵损失是用于基于概率的分类问题最常用的损失函数之一。

交叉熵损失前向方程

首先,我们使用softmax函数将原始模型输出 A A A转换成由输入数值的指数决定的 C C C类的概率分布。

ι N \iota_N ιN ι C \iota_C ιC是大小为 N N N C C C的列向量,包含全部为1的值。

softmax ( A ) = σ ( A ) = exp ⁡ ( A ) ∑ j = 1 C exp ⁡ ( A i j ) \text{softmax}(A) = \sigma(A) = \frac{\exp(A)}{\sum\limits_{j=1}^{C} \exp(A_{ij})} softmax(A)=σ(A)=j=1Cexp(Aij)exp(A)

现在,A的每一行代表模型对概率分布的预测,而Y的每一行代表一个输入的目标分布。
然后,我们计算分布Ai相对于目标分布Yi的交叉熵H(A,Y),对于i = 1,…,N:

crossentropy = H ( A , Y ) = ( − Y ⊙ log ⁡ ( σ ( A ) ) ) ⋅ ι C \text{crossentropy} = H(A, Y) = (-Y \odot \log(\sigma(A))) \cdot \mathbf{\iota}_C crossentropy=H(A,Y)=(Ylog(σ(A)))ιC

记住,损失函数的输出是一个标量,但现在我们有一个大小为N的列矩阵。要将其转换为标量,我们可以使用所有交叉熵的和或平均值。

这里,我们选择使用平均交叉熵作为交叉熵损失,这也是PyTorch的默认设置:

sumcrossentropyloss : = ι N T ⋅ H ( A , Y ) = S C E ( A , Y ) \text{sumcrossentropyloss} := \mathbf{\iota}_N^T \cdot H(A, Y) = SCE(A, Y) sumcrossentropyloss:=ιNTH(A,Y)=SCE(A,Y)

meancrossentropyloss : = S C E ( A , Y ) N \text{meancrossentropyloss} := \frac{SCE(A, Y)}{N} meancrossentropyloss:=NSCE(A,Y)
在这里插入图片描述

交叉熵损失反向方程

xent.backward ( ) = σ ( A ) − Y N \text{xent.backward}() = \frac{\sigma(A) - Y}{N} xent.backward()=Nσ(A)Y

梯度的推导(我的证明)

要找到交叉熵损失相对于对数几率 A i A_i Ai的梯度,我们需要计算导数 ∂ H ∂ A i \frac{\partial H}{\partial A_i} AiH。这涉及到应用链式法则到对数和softmax函数的复合中。

注意对于一个对数几率 A i c A_{ic} Aic,softmax函数定义为:

σ ( A i c ) = e A i c ∑ j = 1 C e A i j \sigma(A_{ic}) = \frac{e^{A_{ic}}}{\sum\limits_{j=1}^{C} e^{A_{ij}}} σ(Aic)=j=1CeAijeAic

步骤1:应用链式法则

首先,注意我们需要对一个复合函数的导数应用链式法则,这个复合函数是softmax输出的对数:

H ( A i , Y i ) = − ∑ c = 1 C Y i c log ⁡ ( σ ( A i c ) ) H(A_i, Y_i) = -\sum_{c=1}^{C} Y_{ic} \log(\sigma(A_{ic})) H(Ai,Yi)=c=1CYiclog(σ(Aic))

∂ H ∂ A i c = ∂ ( − Y i 1 log ⁡ ( σ ( A i 1 ) ) − Y i 2 log ⁡ ( σ ( A i 2 ) ) − . . . − Y i C log ⁡ ( σ ( A i C ) ) ) ∂ A i c = ∂ ( − Y i 1 log ⁡ ( σ ( A i 1 ) ) ) ∂ A i c + ∂ ( − Y i 2 log ⁡ ( σ ( A i 2 ) ) ) ∂ A i c + . . . + ∂ ( − Y i C log ⁡ ( σ ( A i C ) ) ) ∂ A i c = − Y i 1 ∂ log ⁡ ( σ ( A i 1 ) ) ∂ A i c − Y i 2 ∂ log ⁡ ( σ ( A i 2 ) ) ∂ A i c − . . . − Y i C ∂ log ⁡ ( σ ( A i C ) ) ∂ A i c = − ∑ k = 1 C Y i k ∂ log ⁡ ( σ ( A i k ) ) ∂ A i c \begin{align*} \frac{\partial H}{\partial A_{ic}} &= \frac{\partial (-Y_{i1}\log(\sigma(A_{i1})) -Y_{i2}\log(\sigma(A_{i2}))-...-Y_{iC}\log(\sigma(A_{iC})))}{\partial A_{ic}} \\ &= \frac{\partial (-Y_{i1}\log(\sigma(A_{i1})))}{\partial A_{ic}} + \frac{\partial (-Y_{i2}\log(\sigma(A_{i2})))}{\partial A_{ic}} + ...+ \frac{\partial (-Y_{iC}\log(\sigma(A_{iC})))}{\partial A_{ic}} \\ &=-Y_{i1}\frac{\partial \log(\sigma(A_{i1}))}{\partial A_{ic}} -Y_{i2}\frac{\partial \log(\sigma(A_{i2}))}{\partial A_{ic}} -...-Y_{iC}\frac{\partial \log(\sigma(A_{iC}))}{\partial A_{ic}} \\ &=- \sum_{k=1}^{C} Y_{ik} \frac{\partial \log(\sigma(A_{ik}))}{\partial A_{ic}}\\ \end{align*} AicH=Aic(Yi1log(σ(Ai1))Yi2log(σ(Ai2))...YiClog(σ(AiC)))=Aic(Yi1log(σ(Ai1)))+Aic(Yi2log(σ(Ai2)))+...+Aic(YiClog(σ(AiC)))=Yi1Aiclog(σ(Ai1))Yi2Aiclog(σ(Ai2))...YiCAiclog(σ(AiC))=k=1CYikAiclog(σ(Aik))

∂ H ∂ A i c = − ∑ k = 1 C Y i k ∂ log ⁡ ( σ ( A i k ) ) ∂ A i c \frac{\partial H}{\partial A_{ic}} = - \sum_{k=1}^{C} Y_{ik} \frac{\partial \log(\sigma(A_{ik}))}{\partial A_{ic}} AicH=k=1CYikAiclog(σ(Aik))

步骤2:Softmax的对数的导数

log ⁡ ( σ ( A i k ) ) \log(\sigma(A_{ik})) log(σ(Aik))关于 A i c A_{ic} Aic的导数涉及两种情况:当 k = c k=c k=c和当 k ≠ c k \neq c k=c时。

k = c k=c k=c时,使用对数的导数 ∂ log ⁡ ( x ) ∂ x = 1 x \frac{\partial \log(x)}{\partial x} = \frac{1}{x} xlog(x)=x1和softmax的定义,我们得到:

∂ log ⁡ ( σ ( A i k ) ) ∂ A i c = ∂ log ⁡ ( σ ( A i c ) ) ∂ σ ( A i c ) ⋅ ∂ σ ( A i c ) ∂ A i c = 1 σ ( A i c ) ⋅ σ ( A i c ) ⋅ ( 1 − σ ( A i c ) ) = 1 − σ ( A i c ) \begin{align*} \frac{\partial \log(\sigma(A_{ik}))}{\partial A_{ic}} &= \frac{\partial \log(\sigma(A_{ic}))}{\partial \sigma(A_{ic})} \cdot \frac{\partial \sigma(A_{ic})}{\partial A_{ic}} \\ &= \frac{1}{\sigma(A_{ic})} \cdot \sigma(A_{ic}) \cdot (1 - \sigma(A_{ic})) \\ &= 1 - \sigma(A_{ic}) \end{align*} Aiclog(σ(Aik))=σ(Aic)log(σ(Aic))Aicσ(Aic)=σ(Aic)1σ(Aic)(1σ(Aic))=1σ(Aic)

k ≠ c k\neq c k=c时,导数涉及不同类的softmax函数,结果是:

∂ log ⁡ ( σ ( A i k ) ) ∂ A i c = ∂ log ⁡ ( σ ( A i k ) ) ∂ σ ( A i c ) ⋅ ∂ σ ( A i c ) ∂ A i c = 1 σ ( A i k ) ⋅ − σ ( A i k ) ⋅ σ ( A i c ) = − σ ( A i c ) \begin{align*} \frac{\partial \log(\sigma(A_{ik}))}{\partial A_{ic}} &= \frac{\partial \log(\sigma(A_{ik}))}{\partial \sigma(A_{ic})} \cdot \frac{\partial \sigma(A_{ic})}{\partial A_{ic}} \\ &= \frac{1}{\sigma(A_{ik})} \cdot -\sigma(A_{ik}) \cdot \sigma(A_{ic}) \\ &= -\sigma(A_{ic}) \end{align*} Aiclog(σ(Aik))=σ(Aic)log(σ(Aik))Aicσ(Aic)=σ(Aik)1σ(Aik)σ(Aic)=σ(Aic)

步骤3:合并情况

由于 Y i Y_i Yi对于真实类别只能为1,否则为0,这简化为:

∂ H ∂ A i c = − ∑ k = 1 C Y i k ∂ log ⁡ ( σ ( A i k ) ) ∂ A i c = o r { − 1 ( 1 − σ ( A i c ) ) = σ ( A i c ) − 1 , for  Y i c = 0 − 1 ( − σ ( A i c ) ) = σ ( A i c ) − 0 , for  Y i c = 1 = σ ( A i c ) − Y i c \begin{align*} \frac{\partial H}{\partial A_{ic}} &= - \sum_{k=1}^{C} Y_{ik} \frac{\partial \log(\sigma(A_{ik}))}{\partial A_{ic}} \\ &= or\begin{cases} -1 (1 - \sigma(A_{ic})) = \sigma(A_{ic}) - 1, & \text{for } Y_{ic} = 0 \\ -1(-\sigma(A_{ic})) = \sigma(A_{ic}) - 0, & \text{for } Y_{ic} = 1 \end{cases} \\ &= \sigma(A_{ic}) - Y_{ic} \end{align*} AicH=k=1CYikAiclog(σ(Aik))=or{1(1σ(Aic))=σ(Aic)1,1(σ(Aic))=σ(Aic)0,for Yic=0for Yic=1=σ(Aic)Yic

示例

让我给出一个具体的例子来说明它:

示例 1

考虑这个案例 Y = [ 1 , 0 , 0 ] Y = [1,0,0] Y=[1,0,0] A = [ 2 , 1 , − 1 ] A = [2, 1, -1] A=[2,1,1]

Y 11 = 1 , Y 12 = 0 , Y 13 = 0 Y_{11} = 1, Y_{12} = 0, Y_{13} = 0 Y11=1,Y12=0,Y13=0
A 11 = 2 , A 12 = 1 , A 13 = − 1 A_{11} = 2, A_{12} = 1, A_{13} = -1 A11=2,A12=1,A13=1

然后当计算

∂ H ∂ A 13 = − ∑ k = 1 C Y 1 k ∂ log ⁡ ( σ ( A 1 k ) ) ∂ A 13 = − Y 11 ∂ log ⁡ ( σ ( A 11 ) ) ∂ A 13 − Y 12 ∂ log ⁡ ( σ ( A 12 ) ) ∂ A 13 − Y 13 ∂ log ⁡ ( σ ( A 13 ) ) ∂ A 13 = − 1 ( − σ ( A 13 ) ) − 0 − 0 = σ ( A 13 ) − 0 = σ ( A 13 ) − Y 13 \begin{align*} \frac{\partial H}{\partial A_{13}} &= - \sum\limits_{k=1}^{C} Y_{1k} \frac{\partial \log(\sigma(A_{1k}))}{\partial A_{13}}\\ &=-Y_{11}\frac{\partial \log(\sigma(A_{11}))}{\partial A_{13}}-Y_{12}\frac{\partial \log(\sigma(A_{12}))}{\partial A_{13}}-Y_{13}\frac{\partial \log(\sigma(A_{13}))}{\partial A_{13}}\\ &= -1(-\sigma(A_{13}))-0-0 \\ &= \sigma(A_{13}) - 0 \\ &= \sigma(A_{13}) - Y _{13}\\ \end{align*} A13H=k=1CY1kA13log(σ(A1k))=Y11A13log(σ(A11))Y12A13log(σ(A12))Y13A13log(σ(A13))=1(σ(A13))00=σ(A13)0=σ(A13)Y13

示例 2

考虑这个案例 Y = [ 0 , 0 , 1 ] Y = [0,0,1] Y=[0,0,1] A = [ 2 , 1 , − 1 ] A = [2, 1, -1] A=[2,1,1]

Y 11 = 0 , Y 12 = 0 , Y 13 = 1 Y_{11} = 0, Y_{12} = 0, Y_{13} = 1 Y11=0,Y12=0,Y13=1
A 11 = 2 , A 12 = 1 , A 13 = − 1 A_{11} = 2, A_{12} = 1, A_{13} = -1 A11=2,A12=1,A13=1

然后当计算

∂ H ∂ A 13 = − ∑ k = 1 C Y 1 k ∂ log ⁡ ( σ ( A 1 k ) ) ∂ A 13 = − Y 11 ∂ log ⁡ ( σ ( A 11 ) ) ∂ A 13 − Y 12 ∂ log ⁡ ( σ ( A 12 ) ) ∂ A 13 − Y 13 ∂ log ⁡ ( σ ( A 13 ) ) ∂ A 13 = − 0 − 0 − 1 ( 1 − σ ( A 13 ) ) = σ ( A 13 ) − 1 = σ ( A 13 ) − Y 13 \begin{align*} \frac{\partial H}{\partial A_{13}} &= - \sum\limits_{k=1}^{C} Y_{1k} \frac{\partial \log(\sigma(A_{1k}))}{\partial A_{13}}\\ &=-Y_{11}\frac{\partial \log(\sigma(A_{11}))}{\partial A_{13}}-Y_{12}\frac{\partial \log(\sigma(A_{12}))}{\partial A_{13}}-Y_{13}\frac{\partial \log(\sigma(A_{13}))}{\partial A_{13}}\\ &= -0-0-1(1 - \sigma(A_{13})) \\ &= \sigma(A_{13}) - 1 \\ &= \sigma(A_{13}) - Y _{13}\\ \end{align*} A13H=k=1CY1kA13log(σ(A1k))=Y11A13log(σ(A11))Y12A13log(σ(A12))Y13A13log(σ(A13))=001(1σ(A13))=σ(A13)1=σ(A13)Y13

梯度的推导(YouTube的证明)
  • Softmax函数是一个向量。
  • 每个元素 e z k ∑ c = 1 C e z c \frac{e^{z_k}}{\sum\limits_{c=1}^{C} e^{z_c}} c=1Cezcezk由于分母的原因依赖于所有输入元素。
  • 向量关于向量的梯度是一个矩阵。
  • 为了简化和巩固这个概念,让我们通过查看一个大小为 3 3 3的向量来使其更具体:

( z 1 z 2 z 3 ) → ( e z 1 e z 1 + e z 2 + e z 3 e z 2 e z 1 + e z 2 + e z 3 e z 3 e z 1 + e z 2 + e z 3 ) = ( a 1 a 2 a 3 ) = ( y 1 ^ y 2 ^ y 3 ^ ) \begin{pmatrix} z_1\\ z_2\\ z_3 \end{pmatrix} \rightarrow \begin{pmatrix} \frac{e^{z_1}}{e^{z_1} + e^{z_2} + e^{z_3}}\\ \frac{e^{z_2}}{e^{z_1} + e^{z_2} + e^{z_3}}\\ \frac{e^{z_3}}{e^{z_1} + e^{z_2} + e^{z_3}} \end{pmatrix} = \begin{pmatrix} a_1\\ a_2\\ a_3 \end{pmatrix} = \begin{pmatrix} \hat{y_1}\\ \hat{y_2}\\ \hat{y_3} \end{pmatrix} z1z2z3 ez1+ez2+ez3ez1ez1+ez2+ez3ez2ez1+ez2+ez3ez3 = a1a2a3 = y1^y2^y3^

矩阵的对角元素会发生什么?我们有导数关于分子中相同元素。例如,对于 ∂ a 1 ∂ z 1 \frac{\partial a_1}{\partial z_1} z1a1我们得到:

∂ a 1 ∂ z 1 = e z 1 ( e z 1 + e z 2 + e z 3 ) − e z 1 e z 1 ( e z 1 + e z 2 + e z 3 ) ( e z 1 + e z 2 + e z 3 ) = e z 1 e z 1 + e z 2 + e z 3 ⋅ e z 1 + e z 2 + e z 3 − e z 1 e z 1 + e z 2 + e z 3 = a 1 ( 1 − a 1 ) \frac{\partial a_1}{\partial z_1} = \frac{e^{z_1}(e^{z_1} + e^{z_2} + e^{z_3}) - e^{z_1}e^{z_1}}{(e^{z_1} + e^{z_2} + e^{z_3})(e^{z_1} + e^{z_2} + e^{z_3})} = \frac{e^{z_1}}{e^{z_1} + e^{z_2} + e^{z_3}} \cdot \frac{e^{z_1}+e^{z_2}+e^{z_3}-e^{z_1}}{e^{z_1} + e^{z_2} + e^{z_3}} = a_1(1 - a_1) z1a1=(ez1+ez2+ez3)(ez1+ez2+ez3)ez1(ez1+ez2+ez3)ez1ez1=ez1+ez2+ez3ez1ez1+ez2+ez3ez1+ez2+ez3ez1=a1(1a1)

所以我们得到了非常接近于sigmoid导数的东西。

对角线元素以外的元素会发生什么?例如,对于 ∂ a 1 ∂ z 2 \frac{\partial a_1}{\partial z_2} z2a1我们得到:

∂ a 1 ∂ z 2 = 0 ⋅ ( e z 1 + e z 2 + e z 3 ) − e z 1 e z 2 ( e z 1 + e z 2 + e z 3 ) 2 = − e z 1 e z 1 + e z 2 + e z 3 ⋅ e z 2 e z 1 + e z 2 + e z 3 = − a 1 a 2 \frac{\partial a_1}{\partial z_2} = \frac{0 \cdot (e^{z_1} + e^{z_2} + e^{z_3}) - e^{z_1}e^{z_2}}{(e^{z_1} + e^{z_2} + e^{z_3})^2} = -\frac{e^{z_1}}{e^{z_1} + e^{z_2} + e^{z_3}} \cdot \frac{e^{z_2}}{e^{z_1} + e^{z_2} + e^{z_3}} = -a_1a_2 z2a1=(ez1+ez2+ez3)20(ez1+ez2+ez3)ez1ez2=ez1+ez2+ez3ez1ez1+ez2+ez3ez2=a1a2

对于我们的3x3矩阵,我们将得到:

∂ a ∂ z = ( a 1 ( 1 − a 1 ) − a 1 a 2 − a 1 a 3 − a 2 a 1 a 2 ( 1 − a 2 ) − a 2 a 3 − a 3 a 1 − a 3 a 2 a 3 ( 1 − a 3 ) ) \frac{\partial \mathbf{a}}{\partial \mathbf{z}} = \begin{pmatrix} a_1(1 - a_1) & -a_1a_2 & -a_1a_3 \\ -a_2a_1 & a_2(1 - a_2) & -a_2a_3 \\ -a_3a_1 & -a_3a_2 & a_3(1 - a_3) \end{pmatrix} za= a1(1a1)a2a1a3a1a1a2a2(1a2)a3a2a1a3a2a3a3(1a3)

对于损失相对于最终输出的导数 - 我们有一个标量相对于向量的导数,所以结果也将是一个向量:

∂ L ∂ a L = [ ∂ ∂ a L 1 ( − ∑ c = 1 C y c log ⁡ a L c ) ⋮ ∂ ∂ a L C ( − ∑ c = 1 C y c log ⁡ a L c ) ] = − [ y 1 a L 1 ⋮ y C a L C ] \frac{\partial \mathcal{L}}{\partial a_L} = \begin{bmatrix} \frac{\partial}{\partial a_{L1}} \left(-\sum\limits_{c=1}^{C} y_c \log a_{Lc}\right) \\ \vdots \\ \frac{\partial}{\partial a_{LC}} \left(-\sum\limits_{c=1}^{C} y_c \log a_{Lc}\right) \end{bmatrix} = - \begin{bmatrix} \frac{y_1}{a_{L1}} \\ \vdots \\ \frac{y_C}{a_{LC}} \end{bmatrix} aLL= aL1(c=1CyclogaLc)aLC(c=1CyclogaLc) = aL1y1aLCyC

记住对于每个1-hot向量 y y y,我们只有一个元素等于1,其余都是0。

回到我们具体的 3 × 3 3 \times 3 3×3例子,并把所有东西放在一起,我们得到:

∂ L ∂ z L = ∂ L ∂ a L ∂ a L ∂ z L = − [ y 1 a 1 y 2 a 2 y 3 a 3 ] ( a 1 ( 1 − a 1 ) − a 1 a 2 − a 1 a 3 − a 2 a 1 a 2 ( 1 − a 2 ) − a 2 a 3 − a 3 a 1 − a 3 a 2 a 3 ( 1 − a 3 ) ) = − [ y 1 − a 1 ( y 1 + y 2 + y 3 ) y 2 − a 2 ( y 1 + y 2 + y 3 ) y 3 − a 3 ( y 1 + y 2 + y 3 ) ] = a − y \begin{align} \frac{\partial \mathcal{L}}{\partial z_L} &= \frac{\partial \mathcal{L}}{\partial a_L} \frac{\partial a_L}{\partial z_L} \\ &= -\begin{bmatrix} \frac{y_1}{a_1} \\ \frac{y_2}{a_2} \\ \frac{y_3}{a_3} \end{bmatrix} \begin{pmatrix} a_1(1 - a_1) & -a_1a_2 & -a_1a_3 \\ -a_2a_1 & a_2(1 - a_2) & -a_2a_3 \\ -a_3a_1 & -a_3a_2 & a_3(1 - a_3) \end{pmatrix} \\ &= -\begin{bmatrix} y_1 - a_1(y_1 + y_2 + y_3) & y_2 - a_2(y_1 + y_2 + y_3) & y_3 - a_3(y_1 + y_2 + y_3) \end{bmatrix} \\ &= \mathbf{a} - \mathbf{y} \end{align} zLL=aLLzLaL= a1y1a2y2a3y3 a1(1a1)a2a1a3a1a1a2a2(1a2)a3a2a1a3a2a3a3(1a3) =[y1a1(y1+y2+y3)y2a2(y1+y2+y3)y3a3(y1+y2+y3)]=ay

注意这里的 a \mathbf{a} a y \mathbf{y} y是向量,而不是标量。

交叉熵损失的示例

为了说明交叉熵损失,让我们考虑一个具体的例子,用一个小数据集。假设我们有一个简单的分类问题,有三个类别(C=3),我们正在处理两个样本的批次( N = 2 N=2 N=2)。这两个样本的模型原始输出分数( A A A)和相应的真实标签( Y Y Y)可能如下所示:

  • 两个样本的原始模型输出( A A A):

    • 样本 1: [ 2.0 , 1.0 , 0.1 ] [2.0, 1.0, 0.1] [2.0,1.0,0.1]
    • 样本 2: [ 0.1 , 2.0 , 1.9 ] [0.1, 2.0, 1.9] [0.1,2.0,1.9]
  • 真实类别分布( Y Y Y,独热编码):

    • 样本 1: [ 0 , 1 , 0 ] [0, 1, 0] [0,1,0] (类别 2 是真实类别)
    • 样本 2: [ 1 , 0 , 0 ] [1, 0, 0] [1,0,0] (类别 1 是真实类别)

让我们逐步计算这个例子的交叉熵损失:

1. 应用 Softmax

首先,我们对原始输出应用 softmax 函数,以获得每个类别的预测概率。

对于样本 1,softmax 计算如下:
σ ( A 1 ) = [ e 2.0 e 2.0 + e 1.0 + e 0.1 , e 1.0 e 2.0 + e 1.0 + e 0.1 , e 0.1 e 2.0 + e 1.0 + e 0.1 ] \sigma(A_1) = \left[\frac{e^{2.0}}{e^{2.0} + e^{1.0} + e^{0.1}}, \frac{e^{1.0}}{e^{2.0} + e^{1.0} + e^{0.1}}, \frac{e^{0.1}}{e^{2.0} + e^{1.0} + e^{0.1}}\right] σ(A1)=[e2.0+e1.0+e0.1e2.0,e2.0+e1.0+e0.1e1.0,e2.0+e1.0+e0.1e0.1]

对于样本 2,类似地:
σ ( A 2 ) = [ e 0.1 e 0.1 + e 2.0 + e 1.9 , e 2.0 e 0.1 + e 2.0 + e 1.9 , e 1.9 e 0.1 + e 2.0 + e 1.9 ] \sigma(A_2) = \left[\frac{e^{0.1}}{e^{0.1} + e^{2.0} + e^{1.9}}, \frac{e^{2.0}}{e^{0.1} + e^{2.0} + e^{1.9}}, \frac{e^{1.9}}{e^{0.1} + e^{2.0} + e^{1.9}}\right] σ(A2)=[e0.1+e2.0+e1.9e0.1,e0.1+e2.0+e1.9e2.0,e0.1+e2.0+e1.9e1.9]

2. 计算交叉熵损失

接下来,我们计算每个样本的交叉熵损失。单个样本的损失由下式给出:
H ( A i , Y i ) = − ∑ c = 1 C Y i c log ⁡ ( σ ( A i c ) ) H(A_i, Y_i) = -\sum_{c=1}^{C} Y_{ic} \log(\sigma(A_{ic})) H(Ai,Yi)=c=1CYiclog(σ(Aic))

对于样本 1:
H ( A 1 , Y 1 ) = − [ 0 × log ⁡ ( σ ( A 11 ) ) + 1 × log ⁡ ( σ ( A 12 ) ) + 0 × log ⁡ ( σ ( A 13 ) ) ] H(A_1, Y_1) = -[0 \times \log(\sigma(A_{11})) + 1 \times \log(\sigma(A_{12})) + 0 \times \log(\sigma(A_{13}))] H(A1,Y1)=[0×log(σ(A11))+1×log(σ(A12))+0×log(σ(A13))]

对于样本 2:
H ( A 2 , Y 2 ) = − [ 1 × log ⁡ ( σ ( A 21 ) ) + 0 × log ⁡ ( σ ( A 22 ) ) + 0 × log ⁡ ( σ ( A 23 ) ) ] H(A_2, Y_2) = -[1 \times \log(\sigma(A_{21})) + 0 \times \log(\sigma(A_{22})) + 0 \times \log(\sigma(A_{23}))] H(A2,Y2)=[1×log(σ(A21))+0×log(σ(A22))+0×log(σ(A23))]

3. 计算平均交叉熵损失

最后,我们计算这些损失的平均值,以得到批次的平均交叉熵损失:
meancrossentropyloss = H ( A 1 , Y 1 ) + H ( A 2 , Y 2 ) 2 \text{meancrossentropyloss} = \frac{H(A_1, Y_1) + H(A_2, Y_2)}{2} meancrossentropyloss=2H(A1,Y1)+H(A2,Y2)

4. 交叉熵损失的反向传播

对于反向传播,交叉熵损失相对于应用 softmax 之前的原始模型输出的梯度由下式给出:
∂ Loss ∂ A = σ ( A ) − Y N \frac{\partial \text{Loss}}{\partial A} = \frac{\sigma(A) - Y}{N} ALoss=Nσ(A)Y

对于批次中的每个样本,我们计算:

  • 对于样本 1: σ ( A 1 ) − Y 1 2 \frac{\sigma(A_1) - Y_1}{2} 2σ(A1)Y1
  • 对于样本 2: σ ( A 2 ) − Y 2 2 \frac{\sigma(A_2) - Y_2}{2} 2σ(A2)Y2

这给了我们需要通过网络反向传播的梯度。

基于计算:

  • 两个样本的 softmax 概率大约为:

    • 样本 1: [ 0.659 , 0.242 , 0.099 ] [0.659, 0.242, 0.099] [0.659,0.242,0.099]
    • 样本 2: [ 0.073 , 0.487 , 0.440 ] [0.073, 0.487, 0.440] [0.073,0.487,0.440]
  • 两个样本的交叉熵损失为:

    • 样本 1: 1.417
    • 样本 2: 2.620
  • 这个批次的平均交叉熵损失大约为 2.019。

  • 损失相对于原始模型输出( A A A)的梯度为:

    • 对于样本 1: [ 0.330 , − 0.379 , 0.049 ] [0.330, -0.379, 0.049] [0.330,0.379,0.049]
    • 对于样本 2: [ − 0.464 , 0.243 , 0.220 ] [-0.464, 0.243, 0.220] [0.464,0.243,0.220]

这些结果给出了我们使用 softmax 函数得到的每个类别的预测概率,每个样本的个别交叉熵损失,批次的整体平均交叉熵损失,以及反向传播所需的梯度。梯度中的负值指示了我们应该调整模型参数以减少损失的方向,而正值则建议相反的方向。

class CrossEntropyLoss:
    def softmax(self, x):
        # 通过在每个输入向量中减去最大值来改善 softmax 的数值稳定性。
        # 这通过指数化大的正数来防止潜在的溢出。
        e_x = np.exp(x - np.max(x, axis=1, keepdims=True))
        return e_x / e_x.sum(axis=1, keepdims=True)

    def forward(self, A, Y):
        self.A = A
        self.Y = Y
        self.softmax = self.softmax(A)
        crossentropy = -Y * np.log(self.softmax)
        # 在批次上平均损失
        L = np.sum(crossentropy) / A.shape[0]
        return L

    def backward(self):
        # 计算损失相对于对数(预 softmax 激活)A的梯度
        # 这个梯度还包括在批次上的平均
        dLdA = (self.softmax - self.Y) / self.A.shape[0]
        return dLdA

参考资料:

  • 在YouTube上观看视频
  • CMU_11785_深度学习导论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1486446.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kubectl 命令行管理K8S(下)

目录 声明式资源管理方式 介绍 命令 修改yaml文件指定的资源 离线修改 在线修改 YAML 语法格式 查看 api 资源版本标签 编辑yaml配置清单生成资源 编写yaml文件 yaml创建Deployment yaml创建service服务对外提供访问并测试 yaml创建Pod 生成模板 pod模板 serivc…

【降维算法UMAP】调参获得更适合的低维图

目录 UMAP降维介绍 UMAP的主要步骤 1. 学习高维空间中数据点间的距离 2. 构建高维图 local_connectivity参数 n_neighbors参数 3. 构建低维图 计算最小距离 min_dist超参数 最小化成本函数 R语言中的RunUMAP函数 关键参数 Reference UMAP降维介绍 为什么要降维&am…

最长上升子序列(LIS)简介及其例题分析

一.最长上升子序列(LIS)的相关知识 1.最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些情况求的是最长非降序子序列,二者区别就是序列中是否可以有相等的数。假设我们有一个序…

[数据结构]栈

1.栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出的原则。 压栈:栈的插入操作叫做进栈/压栈/入栈&#…

【UEFI实战】BIOS中的openssl

BIOS中的openssl openssl是一个密码库或者密码工具,在密码学基础_hex string is too short, padding with zero bytes t-CSDN博客介绍了基本的密码学概念已经openssl工具的使用,而这里将介绍BIOS下如何使用openssl。 在开源的BIOS代码库EDK中包含一个C…

数据结构作业复盘1:字符串疑难杂症小汇总(字符串赋值,指针数组...)

学校里开始上数据结构了,一开始是从C语言一些相关的基础开始讲起。第一次作业主要是字符串相关的基础知识以及编程题目。先做了一部分,整理了一下一些字符串隐含的知识和一些易误易混的概念,算是给自己的一个复盘和归纳。 strcpy函数相关 首…

Linux系统编程之多线程

目录 1、进程与线程 2、线程的优势与使用理由 3、多线程的使用 3.1 线程的使用 1.线程创建函数 2.线程退出函数 3.线程的等待 4.线程脱离 5. 线程ID获取及比较 6.示例 3.2 互斥锁的应用 1.互斥锁相关API 2.示例 3.3 条件变量的使用 1. 创建及销毁条件变量 2. 等待…

数字化转型导师坚鹏:证券公司数字化领导力提升之道

证券公司数字化领导力提升之道 ——融合中西智慧,践行知行合一思想,实现知行果合一 课程背景: 很多证券公司存在以下问题: 不知道证券公司数字化思维如何提升? 不清楚证券公司数字化领导力模型内涵?…

加密与安全_探索数字证书

文章目录 Pre概述使用keytool生成证书使用Openssl生成证书 (推荐)证书的吊销小结 Pre PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证 PKI - 04 证书授权颁发机构(CA) & 数字证书 PKI - 数字签名与数字证…

土壤侵蚀量化评估

根据之前的文章,已经算出了R、K、LS、C、P 现在计算土壤侵蚀,将几个前期制作好的因子的TIFF文件,用栅格计算器相乘 发现局部地区存在轻度侵蚀,大部分区域是微度侵蚀 然后对比了一下范围 其中的几个因子都在文献范围内,说明计算结果并未出错,可能就是研究区正常范围和结…

《数字图像处理(MATLAB版)》相关算法代码及其分析(1)

目录 1 自适应中值滤波算法 1.1 函数定义 1.2 输入参数检查 1.3 初始化 1.4 自适应中值滤波过程 1.5 处理剩余未处理的像素 1.6 总结 2 计算输入数组的平均值 2.1 函数定义 2.2 注释 2.3 输入验证 2.4 计算平均值 2.5 总结 3 基于高斯模型的贝叶斯分类器 3.1 函…

【搭建 Hbase 集群】

搭建 Hbase 集群 一、准备工作二、三台服务器之间的 SSH 免密登录1.修改hosts文件添加DNS映射2.在每台服务器上生成 SSH 密钥对3.将公共密钥(通常为 ~/.ssh/id_rsa.pub)复制到目标服务器上4.从本地使用 SSH 命令无需密码连接到目标服务器 二、安装JDK1.执…

Linux/Docker 修改系统时区

目录 1. Linux 系统1.1 通过 timedatectl 命令操作1.2 直接修改 /etc/localtime 文件 2. Docker 容器中的 Linux 操作环境: CentOS / AlmaOSMySQL Docker 镜像 1. Linux 系统 1.1 通过 timedatectl 命令操作 使用 timedatectl list-timezones 命令列出可用的时区…

Learning from Unlabeled 3D Environments forVision-and-Language Navigation

这篇论文是关于高级指令的 摘要 在视觉和语言导航 (VLN) 中,实体代理需要按照自然语言指令在真实的 3D 环境中进行导航。现有 VLN 方法的一个主要瓶颈是缺乏足够的训练数据,导致对未见过的环境的泛化效果不理想。虽然 VLN 数据通常是手动收集的&#x…

2024年 前端JavaScript Web APIs 第一天 笔记

1.1 -声明变量const优先 1.2 -DOM树和DOM对象 1.3 -获取DOIM元素 1.4 -DOM修改元素内容以及年会抽奖 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content&quo…

初识面相对象深入理解、构造方法--学习JavaEE的day12

day12 一、初识面相对象深入理解 需求&#xff1a; 创建人类的对象&#xff0c;并操作对象 分析&#xff1a; 人类 - Person 属性&#xff1a;name、sex、age 方法&#xff1a;eat、sleep 场景&#xff1a;创建多个对象&#xff0c;去操作对象 public class Person {//成员变…

9、taocms代码审计

一、XSS 1、DOM型xss 限制 无复现 payload: aa)alert(1)( 触发的参数&#xff1a;name代码 根据路由找到对应的文件&#xff0c;在api.php里接受全局变量action&#xff0c;最终赋值给$m,判断 如果$m不在数组就结束&#xff0c;新建方法复制给$model。检查类的方法是否存…

2024 年广东省职业院校技能大赛(高职组)“云计算应用”赛项样题 2

#需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; 某企业根据自身业务需求&#…

【全局异常处理记录】⭐️通过自定义全局处理器有效统一各种异常并记录

目录 前言 方案 示例 测试 总结 前言 朋友们大家好啊&#xff0c;随着项目的进行&#xff0c;接口也是越来越多了&#xff0c;每个接口无论调用成功与否&#xff0c;都要有相应的应对措施&#xff0c;总不能出错的时候返回一堆异常信息给调用者&#xff0c;所以每个接口都…

Python算法100例-3.2 水仙花数

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序6.问题拓展7.巧用字符串技巧 1&#xff0e;问题描述 输出所有的“水仙花数”。所谓的“水仙花数”是指一个三位数&#xff0c;其各位数字的立方和等于该…