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

反向传播实现报错:权重与权重增量维度不匹配问题排查

反向传播实现维度不匹配问题排查与修复

问题背景

我正在遵循《15 Steps to Implement a Neural Net》指南实现神经网络,目前卡在第12步的backpropagation(反向传播)实现环节。运行代码时触发ValueError,提示weights和weights_delta维度不匹配:weights形状为(5,3),weights_delta形状为(3,3),无法执行加法操作。

相关代码

import numpy as np
# 假设activation_function、activation_function_derivative、evaluate_error、outputs_to_classes、PLOT_GRAPHS、plt已定义

def feed_forward(inputs, weights, biases):
    net = np.matmul(np.hstack((inputs, biases)), weights)
    output = activation_function(net)
    return (output, net)

def initialize_weights(width, height, max_weight):
    return (np.random.random((width, height)) * np.random.randint(-max_weight, max_weight + 1, (width, height)))

def backpropagation(inputs, weights, learning_rate, biases, number_of_samples_for_backpropagation, target_outputs):
    random_sample_index = np.random.randint(0, inputs.shape[0], size=number_of_samples_for_backpropagation)
    random_sample = inputs[random_sample_index, :]
    print("random_sample.shape:")
    print(random_sample.shape)
    target_outputs = target_outputs[random_sample_index, :]
    print("target_outputs.shape:")
    print(target_outputs.shape)
    biases = biases[random_sample_index, :]
    print("biases.shape:")
    print(biases.shape)
    
    outputs, net = feed_forward(random_sample, weights, biases)
    print("weights.shape:")
    print(weights.shape)
    print("outputs.shape:")
    print(outputs.shape)
    print("net.shape:")
    print(net.shape)
    
    error_vector = target_outputs - outputs
    print("error_vector.shape:")
    print(error_vector.shape)
    
    delta = np.multiply(error_vector, activation_function_derivative(net))
    print("delta.shape:")
    print(delta.shape)
    
    weights_delta = learning_rate * np.kron(outputs.T, delta)
    
    print("outputs.T.shape:")
    print(outputs.T.shape)
    print("np.kron(outputs.T, delta).shape:")
    print(np.kron(outputs.T, delta).shape)
    
    weights = weights + weights_delta
    
    return weights

def train(training_set_features, training_set_targets, number_of_samples_for_backpropagation, val_set_features, val_set_targets, test_set_features, test_set_targets):
    number_of_columns_train_features = training_set_features.shape[1]
    number_of_columns_train_targets = training_set_targets.shape[1]
    max_weight = 0.5
    weights = initialize_weights(number_of_columns_train_features + 1, number_of_columns_train_targets, max_weight)
    
    number_of_rows_train = training_set_features.shape[0]
    biases_train = np.ones(shape=(number_of_rows_train, 1))
    number_of_rows_val = val_set_features.shape[0]
    biases_val = np.ones(shape=(number_of_rows_val, 1))
    number_of_rows_test = test_set_features.shape[0]
    biases_test = np.ones(shape=(number_of_rows_test, 1))
    
    # training parameters
    number_of_epochs = 500
    learning_rate = 0.1
    
    train_errors = []
    train_classification_errors = []
    val_errors = []
    val_classification_errors = []
    test_errors = []
    test_classification_errors = []
    
    current_epoch_number = 0
    while (current_epoch_number < number_of_epochs):
        weights = backpropagation(training_set_features, weights, learning_rate, biases_train, number_of_samples_for_backpropagation, training_set_targets)
        if (PLOT_GRAPHS == True):
            train_error, train_classification_error = evaluate_error(training_set_features, weights, training_set_targets, outputs_to_classes(training_set_targets), biases_train)
            val_error, val_classification_error = evaluate_error(val_set_features, weights, val_set_targets, outputs_to_classes(val_set_targets), biases_val)
            test_error, test_classification_error = evaluate_error(test_set_features, weights, test_set_targets, outputs_to_classes(test_set_targets), biases_test)
            
            train_errors.append(train_error)
            train_classification_errors.append(train_classification_error)
            val_errors.append(val_error)
            val_classification_errors.append(val_classification_error)
            test_errors.append(test_error)
            test_classification_errors.append(test_classification_error)
        
        current_epoch_number = current_epoch_number + 1
        
    if (PLOT_GRAPHS == True):
            plt.plot(train_errors, label="Train errors")
            plt.plot(train_classification_errors, label="Train classification errors")
            plt.plot(val_errors, label="Validation errors")
            plt.plot(val_classification_errors, label="Validation classification errors")
            plt.plot(test_errors, label="Test errors")
            plt.plot(test_classification_errors, label="Test classification errors")
            plt.legend(loc="upper left")
    
    train_error, train_classification_error = evaluate_error(training_set_features, weights, training_set_targets, outputs_to_classes(training_set_targets), biases_train)
    val_error, val_classification_error = evaluate_error(val_set_features, weights, val_set_targets, outputs_to_classes(val_set_targets), biases_val)
    test_error, test_classification_error = evaluate_error(test_set_features, weights, test_set_targets, outputs_to_classes(test_set_targets), biases_test)
    
    # debug prints
    print("train_errors:")
    print(train_errors)
    print("train_classification_errors:")
    print(train_classification_errors)
    print("val_errors:")
    print(val_errors)
    print("val_classification_errors:")
    print(val_classification_errors)
    print("test_errors:")
    print(test_errors)
    print("test_classification_errors:")
    print(test_classification_errors)
    
    return (weights, train_error, train_classification_error, val_error, val_classification_error, test_error, test_classification_error)

NUMBER_OF_SAMPLES_FOR_BACKPROPAGATION = 1

# 假设iris_train_features等已加载
# train(iris_train_features.values, iris_train_targets.values, NUMBER_OF_SAMPLES_FOR_BACKPROPAGATION, iris_val_features.values, iris_val_targets.values, iris_test_features.values, iris_test_targets.values)

报错信息

random_sample.shape:
(1, 4)
target_outputs.shape:
(1, 3)
biases.shape:
(1, 1)
weights.shape:
(5, 3)
outputs.shape:
(1, 3)
net.shape:
(1, 3)
error_vector.shape:
(1, 3)
delta.shape:
(1, 3)
outputs.T.shape:
(3, 1)
np.kron(outputs.T, delta).shape:
(3, 3)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In [105], line 1
----> 1 train(iris_train_features.values, iris_train_targets.values, NUMBER_OF_SAMPLES_FOR_BACKPROPAGATION, iris_val_features.values, iris_val_targets.values, iris_test_features.values, iris_test_targets.values)

Cell In [103], line 27, in train(training_set_features, training_set_targets, number_of_samples_for_backpropagation, val_set_features, val_set_targets, test_set_features, test_set_targets)
     25 current_epoch_number = 0
     26 while (current_epoch_number < number_of_epochs):
---> 27     weights = backpropagation(training_set_features, weights, learning_rate, biases_train, number_of_samples_for_backpropagation, training_set_targets)
     28     if (PLOT_GRAPHS == True):
     29         train_error, train_classification_error = evaluate_error(training_set_features, weights, training_set_targets, outputs_to_classes(training_set_targets), biases_train)

Cell In [102], line 36, in backpropagation(inputs, weights, learning_rate, biases, number_of_samples_for_backpropagation, target_outputs)
     33 print("np.kron(outputs.T, delta).shape:")
     34 print(np.kron(outputs.T, delta).shape)
---> 36 weights = weights + weights_delta
     38 return weights

ValueError: operands could not be broadcast together with shapes (5,3) (3,3) 

问题分析与修复

核心错误

误用np.kron(克罗内克积)计算权重更新量,不符合反向传播的权重梯度计算逻辑。正确的做法是使用包含偏置的输入层矩阵与delta的外积,因为权重矩阵的每一列对应输出节点的权重,梯度由输入和输出误差项(delta)共同决定。

修改后的backpropagation函数

def backpropagation(inputs, weights, learning_rate, biases, number_of_samples_for_backpropagation, target_outputs):
    random_sample_index = np.random.randint(0, inputs.shape[0], size=number_of_samples_for_backpropagation)
    random_sample = inputs[random_sample_index, :]
    target_outputs = target_outputs[random_sample_index, :]
    biases = biases[random_sample_index, :]
    
    # 获取拼接了偏置的输入矩阵(和feed_forward逻辑一致)
    input_with_bias = np.hstack((random_sample, biases))
    outputs, net = feed_forward(random_sample, weights, biases)
    
    error_vector = target_outputs - outputs
    delta = np.multiply(error_vector, activation_function_derivative(net))
    
    # 正确计算权重更新量:输入转置 × delta,再乘以学习率
    # 单个样本时,input_with_bias是(1,5),delta是(1,3),转置后相乘得到(5,3),和weights形状匹配
    weights_delta = learning_rate * np.matmul(input_with_bias.T, delta)
    
    weights = weights + weights_delta
    
    return weights

关键修改点说明

  1. 获取带偏置的输入矩阵:和feed_forward中逻辑一致,用np.hstack((random_sample, biases))得到形状为(1,5)的输入矩阵(对应5个输入节点:4个特征+1个偏置)。
  2. 替换权重更新计算:用np.matmul(input_with_bias.T, delta)代替np.kron,得到的weights_delta形状为(5,3),和原weights的形状完全匹配,可正常执行加法操作。
  3. 移除冗余调试打印(可选):若无需调试,可去掉所有shape打印语句,简化代码。

验证逻辑

对于单个样本:

  • input_with_bias.T形状为(5,1)
  • delta形状为(1,3)
  • 矩阵乘法后得到(5,3)的weights_delta,和weights的(5,3)形状一致,解决维度不匹配问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:45:41