在 Java 中加速数学计算

Speeding up Math calculations in Java

提问人:Simon 提问时间:5/22/2010 最后编辑:ZaidSimon 更新时间:1/19/2018 访问量:13827

问:

我有一个用 Java 编写的神经网络,它使用定义如下的 sigmoid 传递函数:

private static double sigmoid(double x)
{
    return 1 / (1 + Math.exp(-x));
}

这在使用网络的训练和计算过程中被多次调用。有什么方法可以加快速度吗?这并不是说它很慢,只是它被大量使用,所以这里的小优化将是一个很大的整体收益。

Java 神经网络 数学优化

评论

3赞 DaveJohnston 5/22/2010
x 的值是否曾经重复,或者每次调用方法时它们是否总是不同?
0赞 Matthew Flaschen 5/22/2010
另外,结果需要有多准确?
0赞 Simon 5/22/2010
@Dave - 取决于所需的精度,但它们都是浮点数,因此非常独特
2赞 Refactor 5/23/2010
您是否对程序进行了分析,以了解改进它将显着提高整体性能?
1赞 Philip Guin 8/14/2012
@Refactor 加快计算速度实际上是 NN 蛋头中的一个常见话题,所以我发现这种非常幽默的响应是多么刻板的 StackOverflowish :)

答:

1赞 Femaref 5/22/2010 #1

从数学的角度来看,我认为没有任何优化它的可能性。

24赞 tangens 5/22/2010 #2

对于神经网络,您不需要 sigmoid 函数的确切值。因此,您可以预先计算 100 个值并重用最接近输入的值,或者更好的是(如注释所述)从相邻值进行插值。

本文介绍了如何做到这一点(链接是从 s-lott 的答案中窃取的)。

这是 sigmoid 函数:Sigmoid function graph

如您所见,只有 -10 < x < 10 的值才有趣。而且,正如另一条评论所说,该函数是对称的。您只需要存储一半的值。


编辑:很抱歉,我在这里显示了错误的图表。我已经纠正了它。

评论

1赞 nico 5/22/2010
如果您想要更高的精度,也许超过 100 个。恕我直言,一个包含 5000 个(甚至可能是 1000 个)值的查找表绝对足够。
2赞 Jouni K. Seppänen 5/22/2010
为了获得更高的精度,最好在最接近的两个值之间进行线性插值。
2赞 Peter Lawrey 5/22/2010
问题是对称的,所以你只需要一半的值。计算另一边是微不足道的。
1赞 Ha. 5/22/2010
这是一个完全不同功能的图。erf(x) 很难计算,exp(x) 则不然。
0赞 Zaid 5/22/2010
@Ha : 不错的收获。这看起来像双极 S 形函数。OP 中的 sigmoid 函数具有水平渐近线 0 和 1。
1赞 duffymo 5/22/2010 #3

这是一个非常流畅的函数,因此查找和插值方案可能绰绰有余。

当我在 的范围内绘制函数时,我在极端情况下得到 5 位精度。这对您的应用来说足够好吗?-10 <= x <= 10

6赞 JustJeff 5/22/2010 #4

如果你有很多节点的 x 值在 -10..+10 框之外,你可以省略计算这些值,例如,像这样。

if( x < -10 )
    y = 0;
else if( x > 10 )
    y = 1;
else
    y = 1 / (1 + Math.exp(-x));
return y;

当然,这会产生每次计算的条件检查开销,因此只有在您有很多饱和节点时才值得。

另一件值得一提的事情是,如果你使用的是反向传播,并且你必须处理函数的斜率,最好是分段计算,而不是“按书面”计算。

我现在不记得斜率了,但这就是我所说的,以双极 S 形体为例。而不是以这种方式计算

y = (1 - exp(-x)) / (1 + exp(-x));

它命中了 exp() 两次,您可以将昂贵的计算缓存在临时变量中,如下所示

temp = exp(-x);
y = (1 - temp) / (1 + temp);

在BP网中有很多地方可以使用这种东西。