这篇文是为了记录看过的另一篇文章的激活函数,更详细内容可以看神经网络中常见的激活函数-神经网络激活函数 (51cto.com)
各激活函数代码如下:
import numpy as np #来源于https://www.51cto.com/article/719563.html #激活函数的选择:一般建议SELU > ELU > Leaky ReLU > ReLU> tanh > sigmoid,但是,如果网络的体系结构阻止自归一化,那么 ELU 可能是比 SELU #更好的选择。如果速度很重要,Leaky ReLU 将是比慢很多的 ELU 更好的选择。 #1.sigmoid函数 def sigmoid(x): s=1/(1+np.exp(-x)) return s #2.HardSigmoid def HardSigmoid(x): y=[] for i in x: if i<-2.5: y_i=0 elif i>-2.5 and i<2.5: y_i=0.2*i+0.5 else: y_i=1 y.append(y_i) return y #3.Swish:f ( x ) = x ⋅ s i g m o i d ( b x ); Swish 在深层模型上的效果优于 ReLU def Swish(x): b=1.0 return x/(1+np.exp(-b*x)) #4.maxout #5.Relu def relu(x): s = np.where(x < 0, 0, x) return s #6.Leaky_ReLU def Leaky_ReLU(x): α=0.8 s = np.where(x >= 0, x, α*x) return s #7.SELU:能够对神经网络进行自归一化,归一化就是首先减去均值,然后除以标准差。因此,经过归一化之后,网络的组件(权重、偏置和激活)的均值为 0,标准差 # 为 1,而这正是 SELU 激活函数的输出值。通过归一化,网络参数会被初始化一个正态分布。 def SELU(x,alpha=1.6732632423543772848170429916717,scale=1.0507009873554804934193349852946): y = [] for i in x: if i >= 0: y_i = scale * i else: y_i = scale * alpha * (np.exp(i) - 1) y.append(y_i) return y #8.GELU:GELU是某些函数(比如双曲正切函数 tanh)与近似数值的组合 def tanh(x): s1 = np.exp(x) - np.exp(-x) s2 = np.exp(x) + np.exp(-x) s = s1 / s2 return s def GELU(x): gelu =0.5 * x * (1 + tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * np.power(x, 3)))) return gelu #9.Tanh函数:即双曲正切函数,比sigmoid函数更受欢迎,能为多层神经网络提供更好的性能。 #Tanh函数的最大优点是输出值以 0为中心,即关于坐标原点对称,分属为正数和负数两大类别,函数及其导数都是单调的,收敛速度比sigmoid快,从而可以减 # 少迭代次数。这使得它具有了Sigmoid函数的优势,又克服了某些不足。但是,“梯度消失”的问题都还存在,进而导致收敛速度变慢。 def Tanh(x): s1 = np.exp(x) - np.exp(-x) s2 = np.exp(x) + np.exp(-x) s = s1 / s2 return s #10.softmax:比较适合作为多分类模型的激活函数,一般会与交叉熵损失函数相配。 def softmax(x): x_exp = np.exp(x) x_sum = np.sum(x_exp, axis=0, keepdims=True) s = x_exp / x_sum return s if __name__ == '__main__': x=np.array([1,2,3]) #1.sigmoid函数 sigmoid_out=sigmoid(x) print("\n................1.sigmoid_out...............") print(sigmoid_out) # 2.HardSigmoid HardSigmoid_out = HardSigmoid(x) print("\n................2.HardSigmoid_out...............") print(HardSigmoid_out) # 3.Swish Swish_out = Swish(x) print("\n................3.Swish_out...............") print(Swish_out) # 5.Relu Relu_out = relu(x) print("\n................5.Relu_out...............") print(Relu_out) # 6.Leaky_ReLU Leaky_ReLU_out = Leaky_ReLU(x) print("\n................6.Leaky_ReLU_out...............") print(Leaky_ReLU_out) # 7.SELU SELU_out = SELU(x) print("\n................7.SELU_out...............") print(SELU_out) #8.GELU GELU_out = GELU(x) print("\n................8.GELU_out...............") print(GELU_out) # 9.Tanh Tanh_out = Tanh(x) print("\n................9.Tanh_out...............") print(Tanh_out) # 10.softmax softmax_out = softmax(x) print("\n................10.softmax_out...............") print(softmax_out)
激活函数的选择
以终为始,激活函数的选择也是为最终的任务目标服务的。不存在普遍适用各种神经网络的万能的激活函数,在选择激活函数的时候,要考虑不同的条件限制,例如,如果函数可导,求导数的计算难度如何?函数光滑程度如何?输出是否保持标准化?网络的收敛速度如何?等等。
一般地,在用于分类器时,Sigmoid函数及其组合通常效果更好。为了避免梯度消失问题,又需要避免使用Sigmoid和TanH。如果是回归模型,在输出层上可以使用线性激活函数。如果是浅层神经网络,如不超过4层的,可选择使用多种激励函数,没有太大的影响。如果网络中存在大量未激活神经元,可以考虑leaky ReLU函数。
ReLU函数是应用比较广泛的激活函数,可以作为默认选项。深度学习往往需要大量时间来处理大量数据,模型的收敛速度是尤为重要的所以要尽量选择输出具有zero-centered特点的激活函数以加快模型的收敛速度。
一个经验上的建议是:SELU > ELU > Leaky ReLU > ReLU> tanh > sigmoid,但是,如果网络的体系结构阻止自归一化,那么 ELU 可能是比 SELU 更好的选择。如果速度很重要,Leaky ReLU 将是比慢很多的 ELU 更好的选择。
更重要的是,激活函数仍在发展,需要跟踪业界的最新进展,并勇于探索和创新。
一句话小结
激活函数是神经网络中的重要参数,一般地,Sigmoid 系列用于二分类任务输出层,softmax系列用于多分类任务输出层,tanh系列用于模型隐藏层,Relu系列用于回归任务以及卷积神经网络隐藏层。但事无绝对,而且,新研究的激活函数仍在涌现。
附,reddit上有一张激活函数的图,挺有意思的!