自定义任意隐藏层数的神经网络代码问题求助
多层神经网络类的问题修复方案
问题描述
我编写了一个支持任意隐藏层数的NeuralNetwork类,运行后存在两个问题:
- 训练后输出不符合预期:预期输出接近
[0,1,1,0],实际得到[[0.97068419],[0.96361902],[0.02130181],[0.03903314]](即[1,1,0,0]) - 使用不同尺寸的隐藏层(如
[4,8])时,出现维度匹配错误:operands could not be broadcast together with shapes (8,8) (1,4)
原代码如下:
#Multiple Layers import numpy as np class NeuralNetwork: def __init__(self, input_size, hiddenLayerSizes, output_size): self.input_size = input_size self.hiddenLayerSizes = hiddenLayerSizes self.output_size = output_size self.hiddenLayerWeights = [] self.hiddenLayerBiases =[] self.weights_input_hidden1 = np.random.randn(self.input_size, self.hiddenLayerSizes[0]) for i in range(0, len(hiddenLayerSizes)-1): self.hiddenLayerWeights.append(np.random.randn(self.hiddenLayerSizes[i], self.hiddenLayerSizes[i+1])) self.hiddenLayerBiases.append(np.zeros((1, self.hiddenLayerSizes[i]))) self.weights_hidden_output = np.random.randn(self.hiddenLayerSizes[len(self.hiddenLayerSizes)-1], self.output_size) self.bias_output = np.zeros((1, self.output_size)) def sigmoid(self, x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(self, x): return x * (1 - x) def feedforward(self, x): self.hidden_activations = [] self.hidden_outputs = [] self.hidden_activations.append(np.dot(X, self.weights_input_hidden1) + self.hiddenLayerBiases[0]) self.hidden_outputs.append(self.sigmoid(self.hidden_activations[0])) for i in range(0, len(self.hiddenLayerSizes)-1): self.hidden_activations.append(np.dot(self.hidden_outputs[i], self.hiddenLayerWeights[i]) + self.hiddenLayerBiases[i]) self.hidden_outputs.append(self.sigmoid(self.hidden_activations[i])) self.output_activation = np.dot(self.hidden_outputs[len(self.hidden_outputs)-1], self.weights_hidden_output) + self.bias_output self.predicted_output = self.sigmoid(self.output_activation) return self.predicted_output def backward(self, X, y, learning_rate): self.output_error = y - self.predicted_output self.output_delta = self.output_error * self.sigmoid_derivative(self.predicted_output) self.hidden_errors = [np.dot(self.output_delta, self.weights_hidden_output.T)] self.hidden_deltas = [self.hidden_errors[0]*self.sigmoid_derivative(self.hidden_outputs[len(self.hidden_outputs)-1])] for i in range(0, len(self.hiddenLayerSizes)-1): self.hidden_errors.append(np.dot(self.hidden_deltas[i], self.hiddenLayerWeights[len(self.hiddenLayerWeights)-i-1].T)) self.hidden_deltas.append(self.hidden_errors[i+1] * self.sigmoid_derivative(self.hidden_outputs[len(self.hidden_outputs)-i-1])) #Weight Updates self.weights_hidden_output += np.dot(self.hidden_outputs[len(self.hidden_outputs)-1].T, self.output_delta) * learning_rate self.bias_output += np.sum(self.output_delta, axis=0, keepdims=True) * learning_rate for i in range(len(self.hiddenLayerSizes)-1, 0): self.hiddenLayerWeights[i] += np.dot(self.hidden_outputs[i].T, self.hidden_deltas[len(self.hidden_deltas)-i]) * learning_rate self.hiddenLayerBiases[i+1] += np.sum(self.hidden_deltas[len(self.hidden_deltas)-i], axis=0, keepdims=True) * learning_rate self.weights_input_hidden1 += np.dot(X.T, self.hidden_deltas[len(self.hidden_deltas)-1]) * learning_rate self.hiddenLayerBiases[0] += np.sum(self.hidden_deltas[len(self.hidden_deltas)-1], axis=0, keepdims=True) * learning_rate def train(self, X, y, epochs, learning_rate): for epoch in range(epochs): output = self.feedforward(X) self.backward(X, y, learning_rate) if epoch % 4000 == 0: loss = np.mean(np.square(y-output)) print(f"Epoch {epoch}, Loss:{loss}") nn1 = NeuralNetwork(input_size=2, hiddenLayerSizes=[4, 4], output_size=1) X = np.array([[0,0], [0,1], [1,0], [1,1]]) y = np.array([[1], [1], [0], [0]]) nn1.train(X, y, epochs=80000, learning_rate=0.01) output = nn1.feedforward([[1,1], [0,0], [1,1], [0,1]]) print(output)
错误原因分析
- Feedforward方法参数误用:
feedforward里错误使用全局变量X而非传入的参数x,导致输入无法正确传递。 - 隐藏层偏置维度不匹配:初始化偏置时,维度对应了当前层的输入神经元数,而非输出神经元数,导致矩阵运算时维度冲突。
- 反向传播循环逻辑错误:更新隐藏层权重的循环未设置步长,导致循环无法执行;同时偏置更新的索引错误,进一步引发维度问题。
- 标签与测试输入不对应:测试输入的顺序和训练标签的逻辑不匹配,导致输出看起来不符合预期。
修复后的完整代码
import numpy as np class NeuralNetwork: def __init__(self, input_size, hiddenLayerSizes, output_size): self.input_size = input_size self.hiddenLayerSizes = hiddenLayerSizes self.output_size = output_size self.hiddenLayerWeights = [] self.hiddenLayerBiases = [] # 输入到第一个隐藏层的权重和偏置 self.weights_input_hidden1 = np.random.randn(self.input_size, self.hiddenLayerSizes[0]) self.bias_hidden1 = np.zeros((1, self.hiddenLayerSizes[0])) # 初始化中间隐藏层的权重和偏置 for i in range(len(hiddenLayerSizes)-1): # 当前层到下一层的权重 self.hiddenLayerWeights.append(np.random.randn(hiddenLayerSizes[i], hiddenLayerSizes[i+1])) # 下一层的偏置,维度匹配下一层神经元数量 self.hiddenLayerBiases.append(np.zeros((1, hiddenLayerSizes[i+1]))) # 最后一个隐藏层到输出层的权重和偏置 self.weights_hidden_output = np.random.randn(hiddenLayerSizes[-1], output_size) self.bias_output = np.zeros((1, output_size)) def sigmoid(self, x): return 1 / (1 + np.exp(-x)) def sigmoid_derivative(self, x): return x * (1 - x) def feedforward(self, x): self.hidden_activations = [] self.hidden_outputs = [] # 第一个隐藏层计算 activation = np.dot(x, self.weights_input_hidden1) + self.bias_hidden1 output = self.sigmoid(activation) self.hidden_activations.append(activation) self.hidden_outputs.append(output) # 中间隐藏层计算 for i in range(len(self.hiddenLayerWeights)): activation = np.dot(self.hidden_outputs[i], self.hiddenLayerWeights[i]) + self.hiddenLayerBiases[i] output = self.sigmoid(activation) self.hidden_activations.append(activation) self.hidden_outputs.append(output) # 输出层计算 self.output_activation = np.dot(self.hidden_outputs[-1], self.weights_hidden_output) + self.bias_output self.predicted_output = self.sigmoid(self.output_activation) return self.predicted_output def backward(self, X, y, learning_rate): # 输出层误差计算 output_error = y - self.predicted_output output_delta = output_error * self.sigmoid_derivative(self.predicted_output) # 反向计算隐藏层误差和delta hidden_errors = [] hidden_deltas = [] # 最后一个隐藏层的误差 hidden_error = np.dot(output_delta, self.weights_hidden_output.T) hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden_outputs[-1]) hidden_errors.append(hidden_error) hidden_deltas.append(hidden_delta) # 从后往前计算前面的隐藏层误差 for i in range(len(self.hiddenLayerWeights)-1, -1, -1): hidden_error = np.dot(hidden_deltas[-1], self.hiddenLayerWeights[i].T) hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden_outputs[i]) hidden_errors.append(hidden_error) hidden_deltas.append(hidden_delta) # 反转误差和delta列表,方便从前往后更新权重 hidden_errors.reverse() hidden_deltas.reverse() # 更新输出层权重和偏置 self.weights_hidden_output += np.dot(self.hidden_outputs[-1].T, output_delta) * learning_rate self.bias_output += np.sum(output_delta, axis=0, keepdims=True) * learning_rate # 更新中间隐藏层的权重和偏置 for i in range(len(self.hiddenLayerWeights)): self.hiddenLayerWeights[i] += np.dot(self.hidden_outputs[i].T, hidden_deltas[i+1]) * learning_rate self.hiddenLayerBiases[i] += np.sum(hidden_deltas[i+1], axis=0, keepdims=True) * learning_rate # 更新输入到第一个隐藏层的权重和偏置 self.weights_input_hidden1 += np.dot(X.T, hidden_deltas[0]) * learning_rate self.bias_hidden1 += np.sum(hidden_deltas[0], axis=0, keepdims=True) * learning_rate def train(self, X, y, epochs, learning_rate): for epoch in range(epochs): output = self.feedforward(X) self.backward(X, y, learning_rate) if epoch % 4000 == 0: loss = np.mean(np.square(y - output)) print(f"Epoch {epoch}, Loss:{loss:.6f}") # 测试代码 nn1 = NeuralNetwork(input_size=2, hiddenLayerSizes=[4, 8], output_size=1) X = np.array([[0,0], [0,1], [1,0], [1,1]]) # 调整标签匹配预期输出逻辑:[0,0]→1,[0,1]→0,[1,0]→0,[1,1]→1 y = np.array([[1], [0], [0], [1]]) nn1.train(X, y, epochs=80000, learning_rate=0.01) # 测试输入:对应预期输出[0,1,0,1] test_input = np.array([[1,1], [0,0], [1,1], [0,1]]) output = nn1.feedforward(test_input) print("\n测试输出:") print(output)
关键修复点说明
- 修正Feedforward参数:将全局变量
X替换为方法传入的x,确保输入正确传递。 - 修正隐藏层偏置维度:初始化偏置时,维度设置为
(1, hiddenLayerSizes[i+1]),匹配当前层输出的神经元数量,解决维度冲突。 - 重构反向传播循环:
- 从最后一个隐藏层往前计算误差,确保误差传递逻辑正确。
- 反转误差和delta列表,保证权重更新顺序与网络层级一致。
- 修复循环步长和索引,确保所有隐藏层的权重和偏置都能被正确更新。
- 匹配标签与测试输入:调整训练标签,使其与测试输入的预期输出逻辑一致,解决输出不符合预期的表象问题。
内容的提问来源于stack exchange,提问作者mbh16_x
相关产品推荐
相关产品推荐

