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

使用Numpy实现两层神经网络遇异常:所有Y输出值相同,求排查

问题:手动用Numpy搭建两层神经网络,输出所有Y值均相同

我尝试仅使用Numpy搭建一个两层神经网络,网络结构为:第一层含2个sigmoid激活神经元,输出层含1个sigmoid激活神经元,但算法输出的所有Y值均相同,请问问题出在哪里?

使用的数据集为结构化表格数据,代码如下:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def sigmoid(z):
    return 1/(1+np.exp(-z))

def crossentropy(Y,y):
    return -(Y*np.log(y)+(1-Y)*np.log(1-y))

path = 'D:/DS&ML/ML/data.csv'
data = pd.read_csv(path)
data = np.asarray(data)
x = data[:,0:3]
Y = data [:,3:]
x = np.c_[x, np.ones(len(x))]
m = len(x)
a = 0.015
loss = []
# Layer 1 parameters
t11 = np.random.rand(len(x[1]),1)
t12 = np.random.rand(len(x[1]),1)
# Layer 2 parameters
t21 = np.random.rand(3,1)

for i in range(200):
    # Layer 1 Forward Prop
    z11 = np.matmul(x,t11)
    z12 = np.matmul(x,t12)
    a11 = sigmoid(z11)
    a12 = sigmoid(z12)
    a1 = np.c_[a11,a12,np.ones(m)]

    #Layer 2 Forward Prop
    z21 = np.matmul(a1,t21)
    a21 = sigmoid(z21)

    #Loss Calculation
    J = (1/m)*np.sum(crossentropy(Y,a21))
    loss.append(J)
    
    # Layer 2 Back Prop
    dt21 = (a/m)*np.sum((a21-Y)*a1,axis=0).reshape(3,1)
        
    # Layer 1 Back Prop
    da1 = (np.matmul((a21-Y),a1))[:,0:2]
    da11 = da1[:,0:1]*sigmoid(z11)*(1-sigmoid(z11))
    da12 = da1[:,1:2]*sigmoid(z12)*(1-sigmoid(z12))
    dt11 = (a/m)*np.sum((da11)*x,axis=0).reshape(4,1)
    dt12 = (a/m)*np.sum((da12)*x,axis=0).reshape(4,1)

    # Updating Parameters
    t11 = t11-dt11
    t12 = t12-dt12
    t21 = t21-dt21

plt.plot(loss)
plt.show()

核心问题排查

1. 反向传播梯度计算错误(最关键)

反向传播逻辑多处错误,导致权重无法得到有效更新:

  • 第一层误差计算完全错误:正确逻辑是先计算输出层误差delta2 = a21 - Y(交叉熵+ sigmoid输出的梯度可简化,无需额外乘sigmoid导数),再通过输出层权重传递误差到第一层,结合第一层激活值的导数计算梯度。
    错误代码:
    da1 = (np.matmul((a21-Y),a1))[:,0:2]
    
    正确计算方式:
    delta2 = a21 - Y
    delta11 = delta2 * t21[0] * a11 * (1 - a11)
    delta12 = delta2 * t21[1] * a12 * (1 - a12)
    
  • 梯度求和逻辑的前提是误差计算正确,否则即使求和方式对,结果也无效。

2. 输入特征未做归一化

sigmoid在输入绝对值过大时会进入饱和区(输出趋近0或1),此时导数趋近0,权重几乎无法更新。如果输入特征尺度差异大,会导致z值直接饱和,所有输出趋同。
解决:先对输入做标准化:

# 先归一化,再添加偏置项
x = (x - np.mean(x, axis=0)) / np.std(x, axis=0)
x = np.c_[x, np.ones(len(x))]

3. 权重初始化不合理

用np.random.rand()生成0-1均匀分布权重,容易让sigmoid初始就进入饱和区,导致梯度消失。建议用Xavier初始化适配输入维度:

t11 = np.random.randn(len(x[1]),1) * np.sqrt(1/len(x[1]))
t12 = np.random.randn(len(x[1]),1) * np.sqrt(1/len(x[1]))
t21 = np.random.randn(3,1) * np.sqrt(1/3)

4. 迭代次数不足

200次迭代对于神经网络来说太少,尤其是初始化或学习率不合适时,模型还未开始收敛,可尝试增加到10000次左右。

5. 学习率可能不合适

当前a=0.015可能偏小,导致权重更新过慢;也可能偏大导致震荡。可尝试调整为0.1或0.001,结合loss曲线观察效果。

修正后的反向传播核心代码

for i in range(10000):
    # 前向传播部分不变
    z11 = np.matmul(x,t11)
    z12 = np.matmul(x,t12)
    a11 = sigmoid(z11)
    a12 = sigmoid(z12)
    a1 = np.c_[a11,a12,np.ones(m)]

    z21 = np.matmul(a1,t21)
    a21 = sigmoid(z21)

    J = (1/m)*np.sum(crossentropy(Y,a21))
    loss.append(J)
    
    # 修正后的反向传播
    delta2 = a21 - Y
    dt21 = (a/m) * np.sum(delta2 * a1, axis=0).reshape(3,1)
    
    delta11 = delta2 * t21[0] * a11 * (1 - a11)
    delta12 = delta2 * t21[1] * a12 * (1 - a12)
    
    dt11 = (a/m) * np.sum(delta11 * x, axis=0).reshape(4,1)
    dt12 = (a/m) * np.sum(delta12 * x, axis=0).reshape(4,1)

    # 参数更新
    t11 -= dt11
    t12 -= dt12
    t21 -= dt21

内容的提问来源于stack exchange,提问作者Pragadeesh S B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:50:59