Debugging 为什么逻辑回归中较高的学习率会产生NaN成本? 总结

Debugging 为什么逻辑回归中较高的学习率会产生NaN成本? 总结,debugging,machine-learning,octave,logistic-regression,Debugging,Machine Learning,Octave,Logistic Regression,我正在使用Octave和Ling垃圾邮件语料库构建垃圾邮件与火腿电子邮件的分类器;我的分类方法是逻辑回归 较高的学习率会导致计算成本的NaN值,但不会破坏/降低分类器本身的性能 我的尝试 NB:我的数据集已经使用平均归一化进行了归一化。 当我尝试选择学习速率时,我从0.1和400次迭代开始。这导致了以下绘图: 1-图1 当he行在几次迭代后完全消失时,这是由于产生了NaN值;我原以为这会导致参数值不正确,从而导致精度不高,但在检查精度时,我发现测试集的精度为95%(这意味着梯度下降显然仍在发挥

我正在使用Octave和Ling垃圾邮件语料库构建垃圾邮件与火腿电子邮件的分类器;我的分类方法是逻辑回归

较高的学习率会导致计算成本的NaN值,但不会破坏/降低分类器本身的性能

我的尝试 NB:我的数据集已经使用平均归一化进行了归一化。 当我尝试选择学习速率时,我从0.1和400次迭代开始。这导致了以下绘图:

1-图1

当he行在几次迭代后完全消失时,这是由于产生了NaN值;我原以为这会导致参数值不正确,从而导致精度不高,但在检查精度时,我发现测试集的精度为95%(这意味着梯度下降显然仍在发挥作用)。我检查了学习率和迭代次数的不同值,以查看图表是如何变化的:

2-图2

线条不再消失,这意味着没有NaN值,但准确率为87%,大大降低了

我又做了两次测试,迭代次数更多,学习率略高,在这两次测试中,图形都如预期的那样随着迭代次数的增加而减少,但准确率约为86-88%。那里也没有南

我意识到我的数据集是扭曲的,只有481封垃圾邮件和2412封火腿邮件。因此,我计算了这些不同组合的FScore,希望发现后面的组合具有更高的FScore,并且精度是由于倾斜。事实也并非如此——我已将我的结果总结在一个表格中:

3-表格

因此,不存在过度拟合和倾斜似乎不是问题;我不知道现在该怎么办

我能想到的唯一一件事是,我对精确度和FScore的计算是错误的,或者我对行“消失”的初始调试是错误的

编辑:这个问题至关重要,它是关于为什么选择的学习率会出现NaN值。因此,我暂时采取的降低学习率的措施并没有真正回答我的问题——我一直认为较高的学习率只是分散而不是汇聚,不会产生NaN值。

我的代码 My main.m代码(从文件获取数据集的条形图):

我的gradDescent.m代码:

function [optimParams] = gradDescent(features, labels, learningRate, iterations, paramStart, featuresCV, labelsCV)

x_axis = [];
J_axis = [];
J_CV = [];

params = paramStart;

for i=1:iterations,
  [cost, grad] = costFunction(features, labels, params);
  [cost_CV] = costFunction(featuresCV, labelsCV, params);

  params = params - (learningRate.*grad);

  x_axis = [x_axis;i];
  J_axis = [J_axis;cost];
  J_CV = [J_CV;cost_CV];
endfor

graphics_toolkit("gnuplot")
plot(x_axis, J_axis, 'r', x_axis, J_CV, 'b');
legend("Training", "Cross-Validation");
xlabel("Iterations");
ylabel("Cost");
title("Cost as a function of iterations");

optimParams = params;
endfunction
My costFunction.m代码:

function [cost, grad] = costFunction(features, labels, params)
  numRecords = length(labels);

  hypothesis = sigmoid(features*params);

  cost = (-1/numRecords)*sum((labels).*log(hypothesis)+(1-labels).*log(1-hypothesis));

  grad = (1/numRecords)*(features'*(hypothesis-labels));
endfunction
我的predict.m代码:

function [accuracy, precision, recall] = predict(features, labels, params, threshold)
numRecords=length(labels);

predictions = sigmoid(features*params)>threshold;

correct = predictions == labels;

truePositives = sum(predictions == labels == 1);
falsePositives = sum((predictions == 1) != labels);
falseNegatives = sum((predictions == 0) != labels);

precision = truePositives/(truePositives+falsePositives);
recall = truePositives/(truePositives+falseNegatives);

accuracy = 100*(sum(correct)/numRecords);
endfunction
到期信用: 一个很大的帮助是这个答案:所以这个问题有点重复,但我没有意识到,一开始也不明显。。。我将尽我所能解释为什么解决方案也有效,以避免简单地复制答案

解决方案: 问题实际上是我的数据中出现的0*log(0)=NaN结果。为了解决这个问题,在我计算成本时,它变成了:

cost = (-1/numRecords)*sum((labels).*log(hypothesis)+(1-labels).*log(1-hypothesis+eps(numRecords, 1)));
(关于变量值等,请参见问题,仅当这一行发生变化时,包含其余变量似乎是多余的)

说明: eps()函数的定义如下:

返回一个标量、矩阵或N维数组,其元素均为 eps,该机精度高

更准确地说,eps是任意两个相邻的 机器浮点系统中的数字。此数字为 显然是系统依赖的。在支持IEEE浮动的计算机上 点运算,eps约为2.2204e-16,用于双精度 单精度为1.1921e-07

当使用多个参数调用时,前两个参数是 作为行数、列数和任何其他参数 指定其他矩阵尺寸。可选参数类 指定返回类型,可以是“双精度”或“单精度”

这意味着将这个值添加到由Sigmoid函数计算的值上(它以前非常接近0,所以被认为是0)意味着它是最接近0的值,而不是0,使得log()不返回-Inf

在学习率为0.1、迭代次数为2000/1000/400的情况下进行测试时,绘制了完整的图形,检查时未生成NaN值

注意:如果有人想知道,在这之后,精确度和FScores没有变化,因此精确度确实很高,尽管在计算成本时存在错误,但学习率较高。

学分到期: 一个很大的帮助是这个答案:所以这个问题有点重复,但我没有意识到,一开始也不明显。。。我将尽我所能解释为什么解决方案也有效,以避免简单地复制答案

解决方案: 问题实际上是我的数据中出现的0*log(0)=NaN结果。为了解决这个问题,在我计算成本时,它变成了:

cost = (-1/numRecords)*sum((labels).*log(hypothesis)+(1-labels).*log(1-hypothesis+eps(numRecords, 1)));
(关于变量值等,请参见问题,仅当这一行发生变化时,包含其余变量似乎是多余的)

说明: eps()函数的定义如下:

返回一个标量、矩阵或N维数组,其元素均为 eps,该机精度高

更准确地说,eps是任意两个相邻的 机器浮点系统中的数字。此数字为 显然是系统依赖的。在支持IEEE浮动的计算机上 点运算,eps约为2.2204e-16,用于双精度 单精度为1.1921e-07

当使用多个参数调用时,前两个参数是 作为行数、列数和任何其他参数 指定其他矩阵尺寸。可选参数类 指定返回类型,可以是“双精度”或“单精度”

这意味着将这个值添加到由Sigmoid函数计算的值上(它以前非常接近0,所以被认为是0)意味着它是最接近0的值,而不是0,使得log()不返回-Inf

<