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

请求帮助理解并修正ReLU多层感知机的反向传播与权重更新函数

修正ReLU-MLP反向传播与权重更新的问题

核心错误分析

你的代码问题集中在反向传播梯度计算(缺失ReLU导数、维度不匹配)和权重更新逻辑混乱,具体如下:

  • 未计算ReLU导数:反向传播时,隐藏层和输出层的ReLU激活必须乘以对应梯度(x>0时为1,否则为0),否则梯度传递完全失效。
  • 梯度维度不匹配:w2_grad、w1_grad计算方式错误,导致后续更新时出现索引越界或无效梯度。
  • 权重更新逻辑错误:偏置b的更新复用权重梯度索引,两者维度不匹配,是索引越界的直接原因。

分步修正代码

1. 添加ReLU导数函数

实现ReLU的导数,用于反向传播的梯度传递:

def relu_derivative(self, x):
    return np.where(x > 0, 1, 0)

2. 修正反向传播函数

重新计算各层误差与梯度,加入ReLU导数影响,修正维度匹配问题:

def backward(self, x, y):
    # 缓存前向传播中间结果,避免重复计算
    hidden_input = self.forward(x, self.w1, self.b1)
    hidden_output = self.relu(hidden_input)
    output_input = self.forward(hidden_output, self.w2, self.b2)
    pred = self.relu(output_input)
    
    # 输出层误差与梯度
    output_error = 2 * (pred - y)  # MSE损失的导数
    output_delta = output_error * self.relu_derivative(output_input)
    
    # 隐藏层误差与梯度
    hidden_error = np.dot(output_delta, self.w2.T)
    hidden_delta = hidden_error * self.relu_derivative(hidden_input)
    
    # 计算权重与偏置梯度
    w2_grad = np.outer(hidden_output, output_delta)
    b2_grad = output_delta
    w1_grad = np.outer(x, hidden_delta)
    b1_grad = hidden_delta
    
    # 直接更新参数,无需单独封装复杂逻辑
    self.w2 -= self.LR * w2_grad
    self.b2 -= self.LR * b2_grad
    self.w1 -= self.LR * w1_grad
    self.b1 -= self.LR * b1_grad

3. 调整超参数与初始化

原迭代次数太少,XOR问题需更多迭代收敛;权重初始化中心化到[-0.5,0.5),避免初始激活全为正:

def __init__(self):
    self.input_size = 2
    self.hidden_size = 4
    self.output_size = 1
    
    # 中心化初始化,加快收敛
    self.w1 = np.random.random((self.input_size, self.hidden_size)) - 0.5
    self.w2 = np.random.random((self.hidden_size, self.output_size)) - 0.5
    self.b1 = np.random.random(self.hidden_size) - 0.5
    self.b2 = np.random.random(self.output_size) - 0.5
    
    self.ITERS = 10000  # 增加迭代次数
    self.LR = 0.1
    self.alpha = 0.01  # 原代码未使用,保留备用

完整修正代码

import numpy as np

class MLP:
    def __init__(self):
        self.input_size = 2
        self.hidden_size = 4
        self.output_size = 1
        
        self.w1 = np.random.random((self.input_size, self.hidden_size)) - 0.5
        self.w2 = np.random.random((self.hidden_size, self.output_size)) - 0.5
        self.b1 = np.random.random(self.hidden_size) - 0.5
        self.b2 = np.random.random(self.output_size) - 0.5
        
        self.ITERS = 10000
        self.LR = 0.1
        self.alpha = 0.01

    def predict(self, x, return_hidden=False):
        hidden_input = self.forward(x, self.w1, self.b1)
        hidden_output = self.relu(hidden_input)
        if return_hidden:
            return hidden_output
        output_input = self.forward(hidden_output, self.w2, self.b2)
        output = self.relu(output_input)
        return output

    def forward(self, l1, w, b):
        return np.dot(l1, w) + b

    def train(self, X, Y):
        for _ in range(self.ITERS):
            total_loss = 0
            for x, y in zip(X, Y):
                pred = self.predict(x)
                total_loss += (pred - y)**2
                self.backward(x, y)
            # 每1000次迭代打印损失,监控收敛
            if _ % 1000 == 0:
                print(f"Iteration {_}, Loss: {total_loss/len(X):.4f}")

    def backward(self, x, y):
        hidden_input = self.forward(x, self.w1, self.b1)
        hidden_output = self.relu(hidden_input)
        output_input = self.forward(hidden_output, self.w2, self.b2)
        pred = self.relu(output_input)
        
        output_error = 2 * (pred - y)
        output_delta = output_error * self.relu_derivative(output_input)
        
        hidden_error = np.dot(output_delta, self.w2.T)
        hidden_delta = hidden_error * self.relu_derivative(hidden_input)
        
        w2_grad = np.outer(hidden_output, output_delta)
        b2_grad = output_delta
        w1_grad = np.outer(x, hidden_delta)
        b1_grad = hidden_delta
        
        self.w2 -= self.LR * w2_grad
        self.b2 -= self.LR * b2_grad
        self.w1 -= self.LR * w1_grad
        self.b1 -= self.LR * b1_grad

    def relu(self, x):
        return np.where(x > 0, x, 0)
    
    def relu_derivative(self, x):
        return np.where(x > 0, 1, 0)

# XOR数据集
X = np.array([
    [0, 0],
    [1, 0],
    [0, 1],
    [1, 1]
])
Y = np.array([[0], [1], [1], [0]])

model = MLP()
model.train(X, Y)

# 测试预测结果
for x in X:
    pred = model.predict(x)
    target = Y[np.where((X==x).all(axis=1))[0]][0][0]
    print(f"Input: {x}, Prediction: {pred[0]:.4f}, Target: {target}")

关键说明

  • 权重中心化初始化:避免初始阶段所有ReLU激活值为正,梯度单一导致收敛缓慢。
  • 中间结果缓存:反向传播时直接计算前向结果,保证中间值一致性,同时提升效率。
  • 损失监控:通过打印损失值,直观观察模型是否在正常收敛。

内容的提问来源于stack exchange,提问作者Dvorak'sPadawan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:02:32