激活函数(activation function)运行时激活神经网络中某一部分神经元,将激活神经元的信息输入到下一层神经网络中。神经网络之所以能处理非线性问题,这归功于激活函数的非线性表达能力。激活函数需要满足数据的输入和输出都是可微的,因为在进行反向传播的时候,需要对激活函数求导。
在TensorFlow中也内置了许多的激活函数,安装好TensorFlow之后可以在tensorflow-->python-->ops-->nn.py文件中看到激活函数
接下来主要介绍一些常用的激活函数如:sigmoid、tanh、relu、dropout等。
sigmoid函数也被称为S型函数,它可以将整个实数区间映射到(0,1)区间,因此经常被用来计算概率,它也是在传统神经网络中被经常使用的一种激活函数。
x = tf.constant([[-1,-2],[3,4],[5,6]],dtype=tf.float32)
sess = tf.Session()
print(sess.run(tf.sigmoid(x)))
sigmoid激活函数的优点:输出的映射区间(0,1)内单调连续,非常适合用作输出层,并且比较容易求导。
sigmoid激活函数的缺点:它具有软饱和性,即当输入x趋向于无穷的时候,它的导数会趋于0,导致很容易产生梯度消失。
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
if __name__ == "__main__":
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.log_sigmoid(x))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
tanh是双曲正切函数,它将整个实数区间映射到了(-1,1),tanh函数也具有软饱和性。它的输出是以0为中心,tanh的收敛速度比sigmoid要快,由于存在软饱和性,所以tanh也存在梯度消失的问题。
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.tanh(x))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
relu激活函数现在是最受欢迎的激活函数,经常被使用在神经网络中。relu函数的定义:f(x)=max(x,0)
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.nn.relu(x))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
relu函数在x<0时,输出始终为0。由于x>0时,relu函数的导数为1,所以relu函数能够在x>0时保持梯度不断衰减,从而缓解梯度消失的问题,还能加快收敛速度,还能是神经网络具有稀疏性表达能力,这也是relu激活函数能够被使用在深层神经网络中的原因。由于当x<0时,relu函数的导数为0,导致对应的权重无法更新,这样的神经元被称为"神经元死亡"。
在TensorFlow中还包括了relu函数的扩展函数如:relu6和crelu,除此之外还有leaky relu、PRelu、RRelu等。
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.nn.relu6(x))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.nn.crelu(x))
print(y)
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.nn.softplus(x))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
x = tf.constant(np.arange(-10,10),dtype=tf.float32)
sess = tf.Session()
y = sess.run(tf.nn.leaky_relu(x,alpha=0.2))
print(y)
plt.plot(np.arange(-10,10),y)
plt.show()
dropout函数会以一个概率为keep_prob来决定神经元是否被抑制。如果被抑制,该神经元输出为0,如果不被抑制则该神经元的输出为输入的1/keep_probbe倍,每个神经元是否会被抑制是相互独立的。神经元是否被抑制还可以通过调节noise_shape来调节,当noise_shape[i] == shape(x)[i],x中的元素是相互独立的。如果shape(x)=[k,l,m,n](k表示数据的个数,l表示数据的行数,m表示数据的列,n表示通道),当noise_shape=[k,1,1,n],表示数据的个数与通道是相互独立的,但是与数据的行和列是有关联的,即要么都为0,要么都为输入的1/keep_prob倍。
x = tf.constant(np.array([np.arange(-5,5)]),dtype=tf.float32)
sess = tf.Session()
#元素之间互不干扰
y = sess.run(tf.nn.dropout(x,keep_prob=0.5))
print(y)
#元素之间互不干扰
y = sess.run(tf.nn.dropout(x,keep_prob=0.5,noise_shape=[1,10]))
print(y)
#元素之间存在关联
y = sess.run(tf.nn.dropout(x,keep_prob=0.5,noise_shape=[1]))
print(y)