如何修复Logistic Regression实现过程中出现的NaN值问题?
我来帮你搞定这个Logistic Regression训练中出现NaN损失的问题——这是自定义实现里很常见的数值稳定性坑,咱们一步步拆解解决:
问题根源分析
出现NaN的核心原因是数值计算溢出和log(0)的极端情况:
- 当
sigmoid(z)的结果趋近于1时,1-y_head会无限接近0,此时np.log(1-y_head)会变成负无穷;当sigmoid(z)趋近于0时,np.log(y_head)也会变成负无穷,这两种情况都会让损失计算直接出现NaN。 - 另外,你的学习率设置(0.01)可能对当前高维度(16384维)的数据集来说过高,导致参数更新幅度过大,z值迅速变得极端,进一步触发上述问题。
具体解决方案
1. 优化Sigmoid函数的数值稳定性
原来的sigmoid实现在z值很大时会出现数值溢出,我们可以通过分支计算避免这个问题:
def sigmoid(z): # 分情况计算,防止正负极端值导致的溢出 return np.where(z >= 0, 1 / (1 + np.exp(-z)), np.exp(z) / (1 + np.exp(z)))
2. 给损失函数加“安全垫”,避免log(0)
在计算损失前,把y_head的取值限制在一个极小的区间内,彻底避免取对数时遇到0:
def forward_backward_propagation(w,b,x_train,y_train): # 前向传播 z = np.dot(w.T,x_train) + b y_head = sigmoid(z) # 用epsilon限制y_head的范围,防止log(0) epsilon = 1e-10 y_head = np.clip(y_head, epsilon, 1 - epsilon) loss = -(1-y_train)*np.log(1-y_head)-y_train*np.log(y_head) cost = (np.sum(loss))/x_train.shape[1] # x_train.shape[1]用于缩放 # 反向传播 derivative_weight = (np.dot(x_train,((y_head-y_train).T)))/x_train.shape[1] derivative_bias = np.sum(y_head-y_train)/x_train.shape[1] gradients = {"derivative_weight": derivative_weight,"derivative_bias": derivative_bias} return cost,gradients
这里np.clip会把所有y_head的值强制限定在[1e-10, 0.9999999999]之间,完美规避log(0)的问题。
3. 降低学习率
高维度数据集对学习率更敏感,你当前的0.01可能过高,尝试先降到0.001或者0.0001:
logistic_regression(x_train, y_train, x_test, y_test,learning_rate = 0.001, num_iterations = 700)
如果还是有波动,可以尝试动态衰减学习率(比如每迭代200次就把学习率减半),不过先从静态降低开始验证。
4. 微调初始权重
你的初始权重是0.01,对于16384维的输入来说,可能导致初始z值偏大,试试更小的初始值:
def initialize_weights_and_bias(dimension): w = np.full((dimension,1),0.001) b = 0.0 return w, b
5. 确认归一化效果
虽然你做了归一化,但可以再检查下x_train的取值范围是否严格在[0,1]之间:
print("x_train min:", np.min(x_train)) print("x_train max:", np.max(x_train))
如果不在这个区间,说明归一化步骤可能有疏漏,需要重新排查。
验证效果
按照上面的修改后,重新运行训练函数,你应该能看到损失值稳定下降,不会再出现NaN的情况了。
内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu
相关产品推荐
相关产品推荐

