在做机器学习的时候经常一个卷积层后跟一个avtivation层,主要的参数是relu 和softmax.

激活函数Activations

激活函数可以通过设置单独的激活层实现,也可以在构造层对象时通过传递activation参数实现。

from keras.layers import Activation, Dense

model.add(Dense(64))
model.add(Activation('tanh'))

等价于

model.add(Dense(64, activation='tanh'))

也可以通过传递一个逐元素运算的Theano/TensorFlow/CNTK函数来作为激活函数:

from keras import backend as K

def tanh(x):
    return K.tanh(x)

model.add(Dense(64, activation=tanh))
model.add(Activation(tanh))

预定义激活函数

  • softmax:对输入数据的最后一维进行softmax,输入数据应形如(nb_samples, nb_timesteps, nb_dims)(nb_samples,nb_dims)
  • elu
  • selu: 可伸缩的指数线性单元(Scaled Exponential Linear Unit),参考Self-Normalizing Neural Networks
  • softplus
  • softsign
  • relu
  • tanh
  • sigmoid
  • hard_sigmoid
  • linear

高级激活函数

对于简单的Theano/TensorFlow/CNTK不能表达的复杂激活函数,如含有可学习参数的激活函数,可通过高级激活函数实现,如PReLU,LeakyReLU等

ReLU 主要用在神经网络中的隐藏层作为激活函数,很少用在输出层,输出层可用sigmoid或softmax等。
主要解决的问题是避免随着网络层数增加引起的梯度消失问题,当自变量较大时sigmoid函数的导数较小。

主要应用的的参数是relu 和softmax.

先重点讲下relu.

f(x)=max(0,x)

f(x)=0,x<0

f(x)=x,x>0

因此:relu把<0,丢掉,>0保存。

在卷积之后用relu就是对结果的一次筛选,把提取出来的特征做一次筛选,剔除小于0的一部分。

例子:

x = Convolution2D(20, 5, 5, init='glorot_uniform', activation='linear', weights=None, border_mode='valid',
                          subsample=(1, 1), dim_ordering='default',
                          W_regularizer=l1l2(l1=self.train_params['reg_weight_l1'],
                                             l2=self.train_params['reg_weight_l2']), b_regularizer=None,
                          activity_regularizer=None, W_constraint=None, b_constraint=None, bias=True,
                          name='block1_conv1')(img_input)
img_input卷积后的输出把它做一次筛选。
x = Activation(activation='relu', name='block1_act1')(x)

 

有时候经常需要多次重复这个过程,比如,多次卷积都relu.

下面具体对比下同样做筛选的其他几个方法。

第一个问题:为什么引入非线性激励函数?

如果不用激励函数(相当于激励函数是f(x)=x),在这种情况下,每一层的输出都是上一层的线性函数,无论神经网络有多少层,输出都是输入的线性组合,这与一个隐藏层的效果相当(这种情况就是多层感知机MPL)。

但当我们需要进行深度神经网络训练(多个隐藏层)的时候,如果激活函数仍然使用线性的,多层的隐藏函数与一层的隐藏函数作用的相当的,就失去了深度神经网络的意义,所以引入非线性函数作为激活函数。

 

对比激活函数Sigmoid、ReLu,tanh

 

Sigmoid函数

 

 

Activation 使用leakrelu activation._激活函数

Sigmoid函数是深度学习领域开始时使用频率最高的激活函数,它是便于求导的平滑函数,能够将输出值压缩到0-1范围之内。

 

Activation 使用leakrelu activation._卷积_02

 

但是Sigmoid函数有3大缺点:

  • 容易出现梯度消失

优化神经网络的方法是Back Propagation,即导数的后向传递:先计算输出层对应的loss,然后将loss以导数的形式不断向上一层网络传递,修正相应的参数,达到降低loss的目的。但当x较大或较小时,导数接近0;并且Sigmoid函数导数的最大值是0.25,导数在每一层至少会被压缩为原来的1/4。正是因为这两个原因,从输出层不断向输入层反向传播训练时,导数很容易逐渐变为0,使得权重和偏差参数无法被更新,导致神经网络无法被优化。

  • 输出不是zero-centered

Sigmoid函数的输出值恒大于0,假设后层的输入都是非0的信号,在反向传播过程中,weight要么是都往正方向更新,要么都往负方向更新,按照图中所示的阶梯式更新,并非好的优化路径,计算量较大,模型收敛的速度减慢。

Activation 使用leakrelu activation._神经网络_03

  • 幂运算相对耗时

相对于前两项,这其实并不是一个大问题,我们目前是具备相应计算能力的,但之后我们会看到,在ReLU函数中,计算机需要做的仅仅是一个thresholding,相对于幂运算来讲会快很多。

 

 

tanh函数

 

Activation 使用leakrelu activation._激活函数_04

 

Activation 使用leakrelu activation._神经网络_05

 

  • 优点
    全程可导;输出区间为-1到1;解决了zero-centered的输出问题。

 

  • 缺点
    梯度消失的问题和幂运算的问题仍然存在。

ReLU函数

 

 

ReLU函数(Rectified Linear Units)其实就是一个取最大值函数,注意这并不是全区间可导的,但是我们可以取次梯度(subgradient)。

 

Activation 使用leakrelu activation._卷积_06

 

 

Activation 使用leakrelu activation._卷积_07

 

 

 

 

  • 优点
  • 解决了梯度消失的问题 (在正区间)
  • 计算速度非常快,只需要判断输入是否大于0
  • 收敛速度远快于sigmoid和tanh
  • Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生
  • 缺点
  • 输出不是zero-centered
  • Dead ReLU Problem
    Dead ReLU Problem指的是某些神经元可能永远不会被激活,导致相应的参数永远不能被更新。有两个主要原因可能导致这种情况产生: (1) 非常不幸的参数初始化,这种情况比较少见 (2) 学习速率太高导致在训练过程中参数更新太大,不幸使网络进入这种状态。解决方法是可以采用Xavier初始化方法,以及避免将学习速率设置太大或使用adagrad等自动调节学习速率的算法。

 

尽管存在这两个问题,ReLU目前仍是最常用的激活函数。

现在也有一些对relu的改进,比如prelu,random relu等,在不同的数据集上会有一些训练速度上或者准确率上的改进,在此就不展开讨论了。

 

再重点讲下softmax,作为一种回归,解决多分类问题,主要用于输出层,挑选出唯一的结果

 softmax函数形式如下: 

  

Activation 使用leakrelu activation._激活函数_08

对比另外一个逻辑回归sigmoid将一个real value映射到(0,1)的区间(当然也可以是(-1,1)),这样可以用来做二分类。 
而softmax把一个k维的real value向量(a1,a2,a3,a4….)映射成一个(b1,b2,b3,b4….)其中bi是一个0-1的常数,然后可以根据bi的大小来进行多分类的任务,如取权重最大的一维,达到挑选最终结果的效用。

例子:

在tensorflow的项目中一个地方出现:

tcdcn方法里面:最终输出的时候,if not self.hyper_params['as_fcn']:情况下,一个test

# landmarks
            x3 = Dense(self.output_params['output_dim_lmks'], init='glorot_uniform', activation='linear',
                       weights=None, W_regularizer=None,
                       b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None,
                       bias=True, name='top1_fc2_3')(x)
最终的landmark点回归,的到唯一的输出。
            x1 = Activation('softmax', name='top1_cls_output')(x1)

 

 

syn-cnn方法中:

class SynergisticClsBboxLmk(Synergistic):
    """
    Synergistic-like CNN model
        - for classification
        - for bounding box prediction
        - for landmark prediction
差不多哈

 # landmarks
            x3 = Dense(self.output_params['output_dim_lmks'], init='glorot_uniform', activation='linear',
                       weights=None, W_regularizer=None,
                       b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None,
                       bias=True, name='top1_fc2_3')(x)

            x1 = Activation('softmax', name='top1_cls_output')(x1)