You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

神经网络梯度计算:*与np.dot()的使用场景困惑

神经网络反向传播中元素级乘法(*)与矩阵点积(np.dot())的适用场景

问题背景

在学习神经网络训练的过程中,我遇到了一个问题:针对如下代码,无法明确何时使用*进行元素级乘法,何时使用np.dot()进行矩阵点积,由于两者输出结果存在差异,明确其适用场景至关重要。

def loss_gradients(forward_info: Dict[str, ndarray], 
                   weights: Dict[str, ndarray]) -> Dict[str, ndarray]:
    '''
    Compute the partial derivatives of the loss with respect to each of the parameters in the neural network.
    '''    
    dLdP = -(forward_info['y'] - forward_info['P'])
    
    dPdM2 = np.ones_like(forward_info['M2'])

    dLdM2 = dLdP * dPdM2
  
    dPdB2 = np.ones_like(weights['B2'])

    dLdB2 = (dLdP * dPdB2).sum(axis=0)
    
    dM2dW2 = np.transpose(forward_info['O1'], (1, 0))
    
    dLdW2 = np.dot(dM2dW2, dLdP)

    dM2dO1 = np.transpose(weights['W2'], (1, 0)) 

    dLdO1 = np.dot(dLdM2, dM2dO1)
    
    dO1dN1 = sigmoid(forward_info['N1']) * (1- sigmoid(forward_info['N1']))
    
    dLdN1 = dLdO1 * dO1dN1
    
    dN1dB1 = np.ones_like(weights['B1'])
    
    dN1dM1 = np.ones_like(forward_info['M1'])
    
    dLdB1 = (dLdN1 * dN1dB1).sum(axis=0)
    
    dLdM1 = dLdN1 * dN1dM1
    
    dM1dW1 = np.transpose(forward_info['X'], (1, 0)) 

    dLdW1 = np.dot(dM1dW1, dLdM1)

    loss_gradients: Dict[str, ndarray] = {}
    loss_gradients['W2'] = dLdW2
    loss_gradients['B2'] = dLdB2.sum(axis=0)
    loss_gradients['W1'] = dLdW1
    loss_gradients['B1'] = dLdB1.sum(axis=0)
    
    return loss_gradients

一、元素级乘法(*,等价于np.multiply)

适用场景

当你需要对形状完全相同的两个张量,执行逐位置对应相乘的操作时使用,这对应链式法则里"逐元素传递梯度"的逻辑,常见于激活函数导数计算、损失对中间张量的直接梯度传递。

代码中的对应示例

  1. 激活函数导数计算:

    dO1dN1 = sigmoid(forward_info['N1']) * (1- sigmoid(forward_info['N1']))
    

    sigmoid的导数公式是σ'(x) = σ(x)*(1-σ(x)),需要对每个元素单独计算,因此用元素级乘法。

  2. 梯度逐元素传递:

    dLdM2 = dLdP * dPdM2
    dLdN1 = dLdO1 * dO1dN1
    

    这里dLdP与dPdM2、dLdO1与dO1dN1的形状完全一致,通过逐元素相乘,将损失梯度传递到前一个中间张量。

  3. 偏置梯度的中间计算:

    dLdB2 = (dLdP * dPdB2).sum(axis=0)
    

    dPdB2是和偏置B2同形状的全1矩阵,先和dLdP逐元素相乘,再沿着样本维度(axis=0)求和,得到所有样本对偏置的梯度总和(因为偏置在所有样本中共享)。


二、矩阵点积(np.dot())

适用场景

当你需要执行**线性代数中的矩阵乘法(或向量内积)**时使用,对应链式法则里"维度收缩、跨层传递梯度"的逻辑,主要用于计算权重参数的梯度——需要将前一层的激活张量与当前层的梯度张量进行矩阵乘法,以匹配权重的维度。

代码中的对应示例

  1. 输出层权重梯度计算:

    dM2dW2 = np.transpose(forward_info['O1'], (1, 0))
    dLdW2 = np.dot(dM2dW2, dLdP)
    
    • O1的形状是[样本数, 隐藏层维度],转置后dM2dW2为[隐藏层维度, 样本数]
    • dLdP的形状是[样本数, 输出层维度]
    • 两者点积后得到[隐藏层维度, 输出层维度]的结果,正好匹配权重W2的形状。
  2. 隐藏层激活梯度传递:

    dM2dO1 = np.transpose(weights['W2'], (1, 0)) 
    dLdO1 = np.dot(dLdM2, dM2dO1)
    
    • W2的形状是[隐藏层维度, 输出层维度],转置后dM2dO1为[输出层维度, 隐藏层维度]
    • dLdM2的形状是[样本数, 输出层维度]
    • 点积后得到[样本数, 隐藏层维度]的结果,匹配隐藏层激活O1的形状,实现梯度从输出层传递到隐藏层。
  3. 输入层权重梯度计算:

    dM1dW1 = np.transpose(forward_info['X'], (1, 0)) 
    dLdW1 = np.dot(dM1dW1, dLdM1)
    

    逻辑和输出层权重梯度一致,通过输入张量的转置与隐藏层梯度点积,得到输入层权重W1的梯度。


关键区分总结

  • 形状要求:
    • *要求两个张量形状完全一致;
    • np.dot()要求第一个张量的最后一维长度,等于第二个张量的倒数第二维长度(符合矩阵乘法规则:(m,n) · (n,p) = (m,p))。
  • 数学意义:
    • *是Hadamard积(逐元素相乘);
    • np.dot()是线性代数中的矩阵乘法/内积。

内容的提问来源于stack exchange,提问作者Soham Ghodake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:34:54