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

从零搭建Numpy神经网络时遭遇矩阵乘法维度不匹配错误的解决咨询

问题描述

本人学习神经网络数学原理后,尝试用Numpy从零搭建神经网络,网络结构为:3节点输入层→2节点隐藏层1→2节点隐藏层2→1节点输出层;隐藏层采用ReLu激活函数,输出层采用Sigmoid激活函数。实现代码如下:

import numpy as np
import pandas as pd

W1 = np.random.rand(2, 3) # Weight matrices
W2 = np.random.rand(2, 2)
W3 = np.random.rand(1, 2)

B1 = np.random.rand(2, 1) # Bias vectors
B2 = np.random.rand(2, 1)
B3 = np.random.rand(1, 1)

ReLu = lambda x : np.maximum(x, 0)
Sigmoid = lambda x : 1/ (1+np.exp(-x))

def forward_prop(inputs):

    Z1 = W1@inputs + B1
    A1 = ReLu(Z1)
    
    Z2 = W2@A1 + B2
    A2 = ReLu(Z2)
    
    Z3 = W3@A2 + B3
    A3 = Sigmoid(Z3)
        
    return Z1, A1, Z2, A2, Z3, A3

d_relu = lambda x : x>0
d_sigmoid = lambda x : np.exp(-x) / (1+np.exp(-x))**2

def back_prop(Z1, A1, Z2, A2, Z3, A3, X, Y):
    
    #derivatives
    dC_dA3 = 2*A3 - 2*Y
    
    dA3_dZ3 = d_sigmoid(Z3)
    dZ3_dW3 = A2
    dZ3_dB3 = 1
    dZ3_dA2 = W3
    
    dA2_dZ2 = d_relu(Z2)
    dZ2_dW2 = A1
    dZ2_dB2 = 1
    dZ2_dA1 = W2
    
    dA1_dZ1 = d_relu(Z1)
    dZ1_dW1 = X
    dZ1_dB1 = 1
    
    dC_dW3 = dC_dA3 @ dA3_dZ3 @ dZ3_dW3.T
    dC_dB3 = dC_dA3 @ dA3_dZ3 * dZ3_dB3
    dC_dA2 = dC_dA3 @ dA3_dZ3 @ dZ3_dA2
    dC_dW2 = dC_dA2 @ dA2_dZ2 @ dZ2_dW2.T
    dC_dB2 = dC_dA2 @ dA2_dZ2 * dZ2_dB2
    dC_dA1 = dC_dA2 @ dA2_dZ2 @ dZ2_dA1 # Problem is here
    dC_dW1 = dC_dA1 @ dA1_dZ1 @ dZ1_dW1.T
    dC_dB1 = dC_dA1 @ dA1_dZ1 * dZ1_dB1
    
    return dC_dW1, dC_dB1, dC_dW2, dC_dB2, dC_dW3, dC_dB3

data = pd.read_csv('light_dark_font_training_set.csv')
x = data.iloc[:, :-1].values
y = data.iloc[:, -1].values

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=1/3)

n = x_train.shape[0]
L = 0.05
epochs = 100_000

for i in range(epochs):

    idx = np.random.choice(n, 1, replace=False)
    x_sample = x_train[idx].transpose()
    y_sample = y_train[idx]
    
    z1, a1, z2, a2, z3, a3 = forward_prop(x_sample)
    w1, b1, w2, b2, w3, b3 = back_prop(z1, a1, z2, a2, z3, a3, x_sample, y_sample)
    
    W1 -= L*w1
    W2 -= L*w2
    W3 -= L*w3
    
    B1 -= L*b1
    B2 -= L*b2
    B3 -= L*b3
    
    if i%10000 == 0:
        print(i)

运行代码时出现如下维度不匹配的ValueError:

ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_11036/3060626554.py in <module>
      6 
      7     z1, a1, z2, a2, z3, a3 = forward_prop(x_sample)
----> 8     w1, b1, w2, b2, w3, b3 = back_prop(z1, a1, z2, a2, z3, a3, x_sample, y_sample)
      9 
     10     W1 -= L*w1

~\AppData\Local\Temp/ipykernel_11036/566612658.py in back_prop(Z1, A1, Z2, A2, Z3, A3, X, Y)
     22     dC_dW2 = dC_dA2 @ dA2_dZ2 @ dZ2_dW2.T
     23     dC_dB2 = dC_dA2 @ dA2_dZ2 * dZ2_dB2
---> 24     dC_dA1 = dC_dA2 @ dA2_dZ2 @ dZ2_dA1# Problem is here
     25     dC_dW1 = dC_dA1 @ dA1_dZ1 @ dZ1_dW1.T
     26     dC_dB1 = dC_dA1 @ dA1_dZ1 * dZ1_dB1

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc     signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 1)
错误原因及解决方法

核心错误原因

反向传播时链式法则的矩阵乘法顺序、维度处理完全错误。代码中错误地将权重矩阵直接参与梯度传递,且乘法顺序不符合列向量的梯度计算逻辑,导致矩阵维度无法对齐,触发报错。

具体修正方案

1. 重构反向传播梯度计算逻辑

替换原back_prop函数,确保所有梯度维度与对应权重/偏置匹配:

def back_prop(Z1, A1, Z2, A2, Z3, A3, X, Y):
    # 损失对输出层激活值的导数
    dC_dA3 = 2 * A3 - 2 * Y
    # 输出层Sigmoid的导数(逐元素计算)
    dA3_dZ3 = d_sigmoid(Z3)
    # 损失对输出层Z值的导数(逐元素相乘)
    dC_dZ3 = dC_dA3 * dA3_dZ3

    # 输出层权重、偏置的梯度
    dC_dW3 = dC_dZ3 @ A2.T
    dC_dB3 = dC_dZ3

    # 损失对隐藏层2激活值的导数(权重矩阵转置后参与计算)
    dC_dA2 = W3.T @ dC_dZ3
    # 隐藏层2ReLU的导数
    dA2_dZ2 = d_relu(Z2)
    # 损失对隐藏层2Z值的导数
    dC_dZ2 = dC_dA2 * dA2_dZ2

    # 隐藏层2权重、偏置的梯度
    dC_dW2 = dC_dZ2 @ A1.T
    dC_dB2 = dC_dZ2

    # 损失对隐藏层1激活值的导数
    dC_dA1 = W2.T @ dC_dZ2
    # 隐藏层1ReLU的导数
    dA1_dZ1 = d_relu(Z1)
    # 损失对隐藏层1Z值的导数
    dC_dZ1 = dC_dA1 * dA1_dZ1

    # 隐藏层1权重、偏置的梯度
    dC_dW1 = dC_dZ1 @ X.T
    dC_dB1 = dC_dZ1

    return dC_dW1, dC_dB1, dC_dW2, dC_dB2, dC_dW3, dC_dB3

2. 修复ReLU导数的类型问题

原d_relu返回布尔数组,转为浮点型避免计算异常:

d_relu = lambda x : np.where(x > 0, 1.0, 0.0)

3. 补充缺失的导入

代码中使用了train_test_split但未导入,需添加:

from sklearn.model_selection import train_test_split

修正说明

  • 所有梯度维度均与对应权重/偏置的维度严格匹配,彻底解决矩阵乘法维度冲突;
  • 梯度传递时使用权重矩阵的转置,符合列向量输入下的链式法则逻辑;
  • 用逐元素乘法(*)结合激活函数导数与损失对Z值的导数,用矩阵乘法(@)计算权重梯度,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Madhavan K M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:24:53