首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在计算Logistic损失函数的值和梯度时避免数值溢出

在计算Logistic损失函数的值和梯度时避免数值溢出
EN

Stack Overflow用户
提问于 2013-11-20 01:39:58
回答 2查看 4.1K关注 0票数 5

我目前正在尝试实现一个机器学习算法,其中涉及到逻辑损失函数在MATLAB中。不幸的是,由于数值溢出,我遇到了一些困难。

通常,对于给定的输入s,逻辑函数的值是:

代码语言:javascript
复制
 log(1 + exp(s))

物流损失函数的斜率为:

代码语言:javascript
复制
 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值的平均值是:

代码语言:javascript
复制
 L = 1/N * sum(log(1+exp(X*beta)),1)

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

代码语言:javascript
复制
 dL = 1/N * sum((exp(X*beta)./(1+exp(X*beta))' X, 1)'

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

我的问题是,这些表达式不断产生数值溢出。这个问题实际上来自这样一个事实:当exp(s)=Infs>1000exp(s)=0s<-1000.

我正在寻找一个解决方案,这样s就可以接受浮点算法中的任何值。理想情况下,我也非常希望有一种解决方案,使我能够以矢量化/高效的方式评估值和梯度。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-11-20 02:04:33

下面的近似如何?

-对于计算L,如果s很大,那么exp(s)将比1大得多:

代码语言:javascript
复制
1 + exp(s) ≅ exp(s)

因此

代码语言:javascript
复制
log(1 + exp(s)) ≅ log(exp(s)) = s.

如果s很小,那么使用exp()的泰勒级数

代码语言:javascript
复制
exp(s) ≅ 1 + s

并使用log()的Taylor级数

代码语言:javascript
复制
log(1 + exp(s)) ≅ log(2 + s) ≅ log(2) + s / 2.

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

代码语言:javascript
复制
exp(s) ./ (1 + exp(s)) ≅ 1

对于小型s

代码语言:javascript
复制
exp(s) ./ (1 + exp(s)) ≅ 1/2 + s / 4.

-计算L的代码可以如下所示:

代码语言:javascript
复制
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)
票数 9
EN

Stack Overflow用户

发布于 2013-11-20 02:27:15

我找到了关于这个问题的一篇好文章

切入大量的词语,我们可以将论点简化为声明原来的表达式

代码语言:javascript
复制
log(1 + exp(s)) 

可以重写为

代码语言:javascript
复制
log(exp(s)*(exp(-s) + 1))
= log(exp(s)) + log(exp(-s) + 1)
= s + log(exp(-s) + 1)

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

代码语言:javascript
复制
function LL = logistic(s)
if s<0
  LL = log(1 + exp(s));
else
  LL = s + logistic(-s);

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

编辑到您的问题的核心-使这个矢量化,并允许计算斜率以及。让我们一次来一次:

代码语言:javascript
复制
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)));

为了达到你想要的平均水平:

代码语言:javascript
复制
L = logisticVec(X*beta) / N;

斜率有点棘手;注意,我相信您的表达式可能有一个错误(缺少一个乘法符号)。

代码语言:javascript
复制
dL/dbeta = sum(X * exp(X*beta) ./ (1 + exp(X*beta))) / N;

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

代码语言:javascript
复制
dL = sum(X ./ (exp(-X*beta) + 1)) / N;

再次,溢出已经消失,我们剩下的是下溢--但是由于下溢值已经添加了1,由此造成的错误是微不足道的。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20085768

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档