用Python神经网络做预测,训练出来的权值和阈值都是nan值,误差越训练越大,求解?

论文题目选的这方面,自己也的确没有基础,参考了别人的代码,结果就悲剧了 = =
代码和数据,在这里: http://bbs.csdn.net/topics/392171719
请大家帮忙看看,感激不尽!
用Python神经网络做预测,训练出来的权值和阈值都是nan值,误差越训练越大,求解?

17 回复

梯度爆炸了吧


这问题我遇到过,八成是梯度爆炸了。NaN值出现通常是因为计算过程中数值溢出,比如激活函数输入值太大导致指数运算溢出。

给你个能跑的解决方案:

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        # 初始化权重 - 使用Xavier初始化防止梯度爆炸
        self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2.0 / input_size)
        self.b1 = np.zeros((1, hidden_size))
        self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2.0 / hidden_size)
        self.b2 = np.zeros((1, output_size))
    
    def relu(self, x):
        return np.maximum(0, x)
    
    def forward(self, X):
        # 前向传播
        self.z1 = np.dot(X, self.W1) + self.b1
        self.a1 = self.relu(self.z1)
        self.z2 = np.dot(self.a1, self.W2) + self.b2
        return self.z2  # 回归问题用线性输出
    
    def train(self, X, y, learning_rate=0.001, epochs=1000):
        m = X.shape[0]
        
        for epoch in range(epochs):
            # 前向传播
            output = self.forward(X)
            
            # 计算损失 - 用MSE
            loss = np.mean((output - y) ** 2)
            
            # 反向传播
            d_output = 2 * (output - y) / m
            
            # 梯度裁剪 - 防止梯度爆炸的关键
            d_output = np.clip(d_output, -1, 1)
            
            dW2 = np.dot(self.a1.T, d_output)
            db2 = np.sum(d_output, axis=0, keepdims=True)
            
            d_a1 = np.dot(d_output, self.W2.T)
            d_a1[self.a1 <= 0] = 0  # ReLU导数
            
            dW1 = np.dot(X.T, d_a1)
            db1 = np.sum(d_a1, axis=0, keepdims=True)
            
            # 更新参数
            self.W1 -= learning_rate * dW1
            self.b1 -= learning_rate * db1
            self.W2 -= learning_rate * dW2
            self.b2 -= learning_rate * db2
            
            if epoch % 100 == 0:
                print(f"Epoch {epoch}, Loss: {loss:.6f}")
        
        return self.W1, self.b1, self.W2, self.b2

# 使用示例
if __name__ == "__main__":
    # 生成示例数据
    np.random.seed(42)
    X = np.random.randn(100, 3)
    y = np.random.randn(100, 1)
    
    # 数据标准化 - 很重要!
    X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
    y = (y - np.mean(y)) / np.std(y)
    
    # 创建和训练网络
    nn = NeuralNetwork(input_size=3, hidden_size=5, output_size=1)
    weights = nn.train(X, y, learning_rate=0.01, epochs=1000)
    
    print("\n训练完成,权重非NaN验证:")
    for name, param in zip(['W1', 'b1', 'W2', 'b2'], weights):
        print(f"{name}: 包含NaN值 - {np.any(np.isnan(param))}")

核心就三件事:权重用Xavier初始化、数据必须标准化、梯度记得裁剪。学习率从0.01开始试,大了容易炸。

标准化数据,初始化权重,裁剪梯度。

搜索了一下,梯度爆炸好像是深度神经网络才会出现的,我这个才一个隐层也会炸吗?= =,请问具体怎么解决呢?

只试过 tensorflow 的,楼主提供代码哪里写了梯度下降,我并没有看懂,是 dw 那几行么。。。还有这种是不应该用 dummy variable ??把属性拓展到列,是哪个属性就在哪一列标 1。还发现一个问题是楼主应该想训练出那个表上各个属性的权重吧?为啥输入层就俩 w,俩 b

python 的话,有 nan 值可能是因为你数据本来就有 nan,然后在做矩阵计算的时候传染得所有数都变成了 nan

昨天新学了个词 过拟合?

Nan 的话看看迭代的时候数据是不是有除零异常

梯度爆炸了。

有没有随机初始化到一个小值啊,有没有矩阵求解时候低秩啊,信息太少不好诊断

numpy 的 nan 会传播的,检查一下开始有没有 nan 吧

我看 BP 算法中,对偏置项 b 的更新 db 貌似不应该乘以矩阵吧。直接用 delta 就行了。

更新权重的时候,为什么要用+=

还有,你那不是归一化,只能算 CategoricalEncode

我也是菜鸟,我看原 bolg 的代码对输入和输出都做了归一化,你的输出没有归一化导致求出的 loss 太大吧

我建议你用正经的框架写,比如 TensorFlow,而不是 NumPy 手撸,不然浪费你我的时间。

原因是这样的,你作为初学者,写出来的代码,无论是命名方式还是结构性都太差了(和违反 Neural Network 业内的 Best Practice ),懂的人看你的代码就好像 C++ 的老手看初学者仿照谭浩强的教材写出来的代码那么痛苦。

https://www.tensorflow.org

学习率太大了。

这种数据应该先用 statsmodels 或 sklearn 中的模型试试看。这里有 boston 房价的例子:

http://cs.smith.edu/dftwiki/index.php/Tutorial:_Playing_with_the_Boston_Housing_Data

对于分类数据你需要进行 one hot 编码,例如 http://blog.csdn.net/bitcarmanlee/article/details/51472816

回到顶部