您发生这种情况的可能原因有两个。
数据未标准化
这是因为当您将 sigmoid / logit 函数应用于您的假设时,输出概率几乎全部约为 0 或全部 1,并且使用您的成本函数,log(1 - 1)
or log(0)
将产生-Inf
。成本函数中所有这些单独项的累积最终将导致NaN
.
具体来说,如果y = 0
对于训练示例,如果您的假设的输出是log(x)
where x
是一个非常小的数字,接近于 0,检查成本函数的第一部分会给我们0*log(x)
并且实际上会产生NaN
。同样,如果y = 1
对于训练示例,如果您的假设的输出也是log(x)
where x
是一个非常小的数字,这又会给我们0*log(x)
并将产生NaN
。简而言之,假设的输出要么非常接近 0,要么非常接近 1。
这很可能是由于每个特征的动态范围差异很大,因此是你的假设的一部分,特别是加权和x*theta
对于每个训练示例,您都会给出非常大的负值或正值,如果您将 sigmoid 函数应用于这些值,您将非常接近 0 或 1。
解决这个问题的一种方法是正常化在使用梯度下降进行训练之前矩阵中的数据。典型的方法是用零均值和单位方差进行标准化。给定一个输入特征x_k
where k = 1, 2, ... n
你在哪里n
特征,新的标准化特征x_k^{new}
可以通过以下方式找到:
m_k
是特征的均值k
and s_k
是特征的标准差k
。这也称为标准化数据。您可以在我在这里给出的另一个答案中阅读有关此内容的更多详细信息:这段用于标准化数据的代码是如何工作的? https://stackoverflow.com/questions/28689807/how-does-this-code-for-standardizing-data-work/28690441#28690441
因为您使用线性代数方法进行梯度下降,所以我假设您已经在数据矩阵前面添加了一列全数。知道了这一点,我们可以像这样标准化你的数据:
mX = mean(x,1);
mX(1) = 0;
sX = std(x,[],1);
sX(1) = 1;
xnew = bsxfun(@rdivide, bsxfun(@minus, x, mX), sX);
每个特征的平均值和标准差存储在mX
and sX
分别。您可以通过阅读我上面链接到您的帖子来了解此代码的工作原理。我不会在这里重复这些内容,因为这不是本文的范围。为了确保正确的标准化,我将第一列的平均值和标准差分别设置为 0 和 1。xnew
包含新的标准化数据矩阵。使用xnew
用你的梯度下降算法代替。现在,一旦找到参数,就可以执行任何预测must使用与测试实例的平均值和标准差对任何新测试实例进行归一化训练集。由于学习的参数与训练集的统计数据有关,因此您还必须对要提交给预测模型的任何测试数据应用相同的转换。
假设您有新的数据点存储在名为的矩阵中xx
,您将进行标准化,然后执行预测:
xxnew = bsxfun(@rdivide, bsxfun(@minus, xx, mX), sX);
现在您已经有了这个,您可以执行您的预测:
pred = sigmoid(xxnew*theta) >= 0.5;
您可以将阈值 0.5 更改为您认为最好的值,以确定示例属于正类还是负类。
学习率太大
正如您在评论中提到的,一旦对数据进行标准化,成本似乎是有限的,但经过几次迭代后突然变为 NaN。标准化只能让你走到这一步。如果你的学习率或alpha
太大,每次迭代都会朝着最小值的方向超调,从而使每次迭代的成本振荡甚至发散,这就是正在发生的情况。在您的情况下,成本在每次迭代时都会发散或增加,以至于它太大以至于无法使用浮点精度表示。
因此,另一种选择是降低学习率alpha
直到您看到成本函数在每次迭代中都在减小。确定最佳学习率的一种流行方法是对一系列对数间隔值执行梯度下降alpha
看看最终的成本函数值是多少,然后选择导致最小成本的学习率。
假设成本函数是凸的,结合使用上面的两个事实应该可以让梯度下降很好地收敛。对于逻辑回归来说,它肯定是这样的。