从零搭建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
相关产品推荐
相关产品推荐

