【问题标题】:Avoiding numerical overflow when calculating the value AND gradient of the Logistic loss function计算 Logistic 损失函数的值 AND 梯度时避免数值溢出
【发布时间】:2013-12-03 20:17:05
【问题描述】:

我目前正在尝试在 MATLAB 中实现涉及 logistic loss function 的机器学习算法。不幸的是,由于数值溢出,我遇到了一些麻烦。

一般来说,对于给定的输入s,逻辑函数的值为:

 log(1 + exp(s))

逻辑损失函数的斜率为:

 exp(s)./(1 + exp(s)) = 1./(1 + exp(-s))

在我的算法中,s = X*beta 的值。这里X 是一个矩阵,具有N 数据点和P 每个数据点的特征(即size(X)=[N,P]),beta 是P 系数的向量,每个特征使得size(beta)=[P 1]。

我对计算给定值beta 的 Logistic 函数的平均值和梯度特别感兴趣。

Logistic 函数 w.r.t 对beta 的平均值为:

 L = 1/N * sum(log(1+exp(X*beta)),1)

Logistic 函数的斜率平均值 w.r.t. b 的值是:

 dL = 1/N * sum((exp(X*beta)./(1+exp(X*beta))' X, 1)'

注意size(dL) = [P 1].

我的问题是这些表达式不断产生数字溢出。问题实际上来自以下事实:exp(s)=Inf 时 s>1000 和 exp(s)=0 时 s<-1000.

我正在寻找一种解决方案,使s 可以采用浮点运算中的任何值。理想情况下,我也非常感谢能够让我以矢量化/有效方式评估值和梯度的解决方案。

【问题讨论】:

  • 我知道有两个文件可以解决您的两个问题。有关高精度浮点,请参阅this。请参阅this 处理任意大的数字
  • Berk U.:其中一个答案对您有帮助吗?
  • @A.Donda 他们很有见地,但没有处理下溢问题。我找到了另一个答案,我很快就会发布!
  • 嗯,但是我给出了大小 s 的近似值,这样可以避免下溢。如果不是,请详细评论。

标签: matlab floating-point numerical-methods logistic-regression numerical-stability


【解决方案1】:

以下近似值如何:

– 计算L,如果s很大,那么exp(s)会比1大很多:

1 + exp(s) ≅ exp(s)

因此

log(1 + exp(s)) ≅ log(exp(s)) = s.

如果s很小,那么使用exp()的Taylor series

exp(s) ≅ 1 + s

并使用泰勒级数的 log()

log(1 + exp(s)) ≅ log(2 + s) ≅ log(2) + s / 2.

– 用于计算dL,用于大型s

exp(s) ./ (1 + exp(s)) ≅ 1

对于小号s

exp(s) ./ (1 + exp(s)) ≅ 1/2 + s / 4.

– 计算L 的代码可能如下所示:

s = X*beta;
l = log(1+exp(s));
ind = isinf(l);
l(ind) = s(ind);
ind = (l == 0);
l(ind) = log(2) + s(ind) / 2;
L = 1/N * sum(l,1)

【讨论】:

  • 宾果游戏。实际上,您可以严格限制 s 需要多大才能使您的第二个等式在浮点算术中保持不变。 (当然,这完全是矫枉过正,但它为为什么这样做是合法的提供了一个非常可靠的理由。)
  • @tmyklebu,有趣,没想到。
【解决方案2】:

我找到了a good article about this problem。

通过大量的文字,我们可以将论证简化为陈述原始表达式

log(1 + exp(s)) 

可以改写为

log(exp(s)*(exp(-s) + 1))
= log(exp(s)) + log(exp(-s) + 1)
= s + log(exp(-s) + 1)

这会阻止上溢的发生——它不会阻止下溢,但是到发生的时候,你就有了答案(即s)。你不能只用它来代替原来的,因为它仍然会给你带来问题。但是,我们现在有了可以编写一个准确且不会产生上溢/下溢的函数的基础:

function LL = logistic(s)
if s<0
  LL = log(1 + exp(s));
else
  LL = s + logistic(-s);

我认为这保持了相当好的准确性。

EDIT 现在回答您的问题 - 使其矢量化,并允许计算斜率。让我们一次拿这些:

function LL = logisticVec(s)
  LL = zeros(size(s));
  LL(s<0) = log(1 + exp(s(s<0)));
  LL(s>=0) = s(s>=0) + log(1 + exp(-s(s>=0)));

要获得您想要的平均值:

L = logisticVec(X*beta) / N;

斜坡有点棘手;请注意,我相信您的表达式中可能有错字(缺少乘号)。

dL/dbeta = sum(X * exp(X*beta) ./ (1 + exp(X*beta))) / N;

如果我们将顶部和底部除以exp(X*beta),我们得到

dL = sum(X ./ (exp(-X*beta) + 1)) / N;

再一次,溢出消失了,我们留下了下溢 - 但由于下溢的值添加了1,因此产生的错误是微不足道的。

【讨论】:

  • 您也需要处理 s 非常负面的情况,并且您会遇到完全相同的问题。
  • 是的。这基本上是log sum of exponentials。
猜你喜欢
  • 1970-01-01
  • 2016-07-01
  • 2017-05-30
  • 2020-03-16
  • 2023-02-26
  • 1970-01-01
  • 2016-11-29
  • 2018-04-13
  • 1970-01-01
相关资源
最近更新 更多