防止sigmoid和tanh激活函数溢出的C++实现

引言

上一期,我们介绍了softmax函数的C++实现,但是考虑到sigmoid和tanh函数也是带 e e e的次幂,所以现在我们来考虑该函数的防止溢出实现。

sigmoid函数

原理

该函数的公式为:
1 1 + e − x \frac{1}{1+e^{-x}} 1+ex1
x ≥ 0 x\geq 0 x0的时候, e − x ≤ 1 e^{-x} \leq 1 ex1,不会溢出,但是在 x < 0 x < 0 x<0的时候,就有可能溢出了。所以在 x < 0 x<0 x<0时,我们可以做如下变换:
1 1 + e − x = 1 ⋅ e x ( 1 + e − x ) ⋅ e x = e x e x + 1 \frac{1}{1+e^{-x}}=\frac{1\cdot e^x}{(1+e^{-x})\cdot e^x}=\frac{e^x}{e^x+1} 1+ex1=(1+ex)ex1ex=ex+1ex
这样 e x < 1 e^x<1 ex<1,也不会溢出了。

实现

    double sigmoid(double x)
    {
        if (x > 0)
            return 1.0 / (1.0 + exp(-x));
        else
            return exp(x) / (1.0 + exp(x));
    }

tanh函数

原理

该函数的公式为:
e x − e − x e x + e − x \frac{e^x-e^{-x}}{e^x+e^{-x}} ex+exexex
那么在 x x x很大或者很小时,都有可能溢出,所以我们分开考虑。

1、 x ≥ 0 x\geq0 x0

这时 e x e^x ex可能溢出, e − x < 1 e^{-x}<1 ex<1不会溢出。我们进行如下变换:
e x − e − x e x + e − x = e − x ⋅ ( e x − e − x ) e − x ⋅ ( e x + e − x ) = 1 − e − 2 x 1 + e − 2 x \frac{e^x-e^{-x}}{e^x+e^{-x}}=\frac{e^{-x}\cdot (e^x-e^{-x})}{e^{-x}\cdot (e^x+e^{-x})}=\frac{1-e^{-2x}}{1+e^{-2x}} ex+exexex=ex(ex+ex)ex(exex)=1+e2x1e2x

1、 x < 0 x<0 x<0

这时 e − x e^{-x} ex可能溢出, e x < 1 e^{x}<1 ex<1不会溢出。我们进行如下变换:
e x − e − x e x + e − x = e x ⋅ ( e x − e − x ) e x ⋅ ( e x + e − x ) = e 2 x − 1 e 2 x + 1 \frac{e^x-e^{-x}}{e^x+e^{-x}}=\frac{e^{x}\cdot (e^x-e^{-x})}{e^{x}\cdot (e^x+e^{-x})}=\frac{e^{2x}-1}{e^{2x}+1} ex+exexex=ex(ex+ex)ex(exex)=e2x+1e2x1
这样就都不会溢出了。

实现

    double tanh(double x)
    {
        if(x > 0)
            return (1-exp(-2*x))/(1+exp(-2*x));
        else
            return (exp(2*x)-1)/(1+exp(2*x));
    }