【问题标题】:Efficient exponentials with small base具有小基数的有效指数
【发布时间】:2012-10-06 02:42:48
【问题描述】:

我需要执行一次 softmax 操作。也就是说,给定从 -inf 到 +inf 的一系列n 实数值,我通过对每个值取幂并除以指数之和将它们转化为概率:

for (i = 0; i < n; i++)
    p_x[i] = exp(x[i]) / sum_exp(x, n)

(不要从字面上理解代码,我不是在总结所有exp 的每次迭代!)

在某些极端情况下(使用 8 字节双精度),当值超过 700 时,我会遇到溢出问题。我知道我可以使用另一个 base 来代替 e,但是,我担心调用 pow 会比 exp 慢得多(速度对我来说很重要)。

解决这个问题的最快方法是什么?

【问题讨论】:

  • 不要害怕 pow 变慢。 基准测试!如果你不能衡量,你就不能改进。
  • 如果你害怕pow,那exp2呢?它执行2^x 而不是e^x
  • 我对@9​​87654331@、expexp2(我不知道)进行了基准测试。 exp 似乎比 pow 快 40~50 倍,比 exp2 快 6~7 倍。嗯,已经是这样了。
  • 700 与 +Inf 相比似乎并不极端。你能进一步限制你的域吗?
  • 事实上,我发现从每个指数中减去一个常数值更容易、更有效。这样,结果保持不变。后来才注意到,使用不同的基数会产生不同的概率。

标签: c math


【解决方案1】:

将每个数字用作 64 位浮点数中的 52 位尾数。这只是掩蔽然后转换的问题。

#include <stdio.h>

int main(int argc, char *argv[])
{
  long long val = 1234567890;
  long long mval = val & ~0xfff0000000000000ULL;
  float fval = *((float*)&mval);
  printf("%f", fval);
}

【讨论】:

    【解决方案2】:
    b^x = e^(x * ln b)
    

    因此,使用较小的基数 b 相当于在应用 exp 之前将您的值乘以 ln b,然后在最后再除。

    【讨论】:

      猜你喜欢
      • 2013-02-08
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 2020-07-23
      相关资源
      最近更新 更多