多层感知器(MLP)和激活函数


多层感知器(MLP)

    前几篇博文线性回归的原理和实现 和Softmax和交叉熵的原理和实现 都是单层神经网络,但是所谓深度学习是有深度的,因此这里介绍多层感知器(Multi Layer Perceptron)。MLP在单层神经网络的基础上引入了一到多个隐藏层(hidden layer),隐藏层位于输入层和输出层之间,如下图:

  1.png

    线性多层神经网络可以等价变换为单层神经网络,如下:

2.png

    这样无法表示复杂的映射。这个问题的根源在于全连接层只是对数据做仿射变换(affine transformation),而多个仿射变换的叠加仍然是一个仿射变换。解决问题的一个方法是引入非线性变换,例如对隐藏变量使用按元素运算的非线性函数进行变换,然后再作为下一个全连接层的输入。这个非线性函数被称为激活函数(activation function)。带隐层和激活函数的神经网络可以表示为:

15.png


激活函数

Sigmoid

    即著名的Logistic函数,sigmoid函数可以将元素的值变换到0和1之间。公式和曲线如下:

3.png

4.png

    导数和导函数曲线:

5.png

6.png

7.png

不足之处:

1.输出值在(0,1)之间,期望值为0.5,不符合均值为0的理想状态。当激活函数的均值不为0时,会导致收敛缓慢,会使得下一层的输入数据均值不为零。以 f=sigmoid(wx+b)为例, 假设输入均为正数(或负数),因为激活函数的输出均值大于零,那么对w的导数总是正数(或负数),这样在反向传播过程中要么都往正方向更新,要么都往负方向更新,导致有一种捆绑效果,使得收敛缓慢。

2.现有的梯度下降算法 严重依赖逐层的梯度计算值,当sigmoid函数输出值在(-inf,-5)或(5,+inf)之间时,梯度近似为0,会发生梯度消失的情况。


Tanh

    Tanh(双曲正切)函数可以将元素的值变换到-1和1之间。公式和曲线如下:

8.png

9.png

    导数和导函数曲线如下:

10.png

11.png

优缺点:优点:输出期望值为0。缺点:依然存在梯度消失的情况。


ReLU

    有关ReLU的原理可浏览《线性修正单元(ReLU)》。公式和曲线如下:

12.png

13.png

    当x=0时,设该函数导数为0,则导函数曲线如下:

14.png


Leaky ReLU

    是ReLU的改进,函数如下:

16.png

    优点:解决了梯度消失的问题。缺点:期望值不为0,a是固定的,合适的a值较难设定,导致实际使用时性能不稳定。


PReLU

    参数化ReLU,是LeakyReLU的改进,如下:

17.png

    将 Leaky Relu 函数中的超参数a设置为变量,被训练到最优,以解决a值较难设定的问题。

    优点:更大自由度。缺点:更大的过拟合风险,增加了参数数量。


RReLU

    随机ReLU,也是LeakyReLU的变体。斜率参数是在一个给定的范围内随机抽取的值。

20.png


CReLU

    公式:CReLU(x)=[ReLU(x), ReLU(−x)] 。输出维度会自动加倍。 比如 −3→[0,3 3→[3,0]。

 

ELU

21.png

22.png


SELU

23.png

    经过该激活函数后使得样本分布自动归一化到0均值和单位方差(自归一化,保证训练过程中梯度不会爆炸或消失,效果比Batch Normalization 要好) 。其实就是ELU乘了个lambda,关键在于这个lambda是大于1的。以前relu,prelu,elu这些激活函数,都是在负半轴坡度平缓,这样在activation的方差过大的时候可以让它减小,防止了梯度爆炸,但是正半轴坡度简单的设成了1。而selu的正半轴大于1,在方差过小的的时候可以让它增大,同时防止了梯度消失。这样激活函数就有一个不动点,网络深了以后每一层的输出都是均值为0方差为1。


MAXOUT

    https://blog.csdn.net/hjimce/article/details/50414467


激活函数一览

18.png

19.png



多层感知器实现图片分类

    基于tensorflow实现,使用fashion_mnist数据集。

from keras.datasets import fashion_mnist
import numpy as np
(x_train,y_train),(x_test,y_test)=fashion_mnist.load_data()
x_train=x_train.reshape(-1,784).astype('float32')/255.0
x_test=x_test.reshape(-1,784).astype('float32')/255.
y_train_onehot=np.zeros((y_train.shape[0],10))
y_test_onehot=np.zeros((y_test.shape[0],10))
for i,label in enumerate(y_train):
    y_train_onehot[i,label]=1
for i,label in enumerate(y_test):
    y_test_onehot[i,label]=1
print(x_train.shape)
print(x_test.shape)
print(y_train.shape)
print(y_test.shape)

    手动实现带感知器的多层(一个隐层)感知器。

import tensorflow as tf
num_inputs=784
num_hiddens=256
num_outputs=10
#初始化模型变量
w1 = tf.Variable(initial_value=tf.random_normal(shape=(num_inputs,num_hiddens),stddev=0.1,mean=0.))
b1 = tf.Variable(initial_value=tf.zeros(num_hiddens))
w2 = tf.Variable(initial_value=tf.random_normal(shape=(num_hiddens,num_outputs),stddev=0.1,mean=0.))
b2 = tf.Variable(initial_value=tf.zeros(num_outputs))
#定义模型
x=tf.placeholder(tf.float32,shape=(None,num_inputs))
y_=tf.placeholder(tf.float32,shape=(None,num_outputs))
net=tf.matmul(x,w1)+b1
net=tf.nn.relu(net)
net=tf.matmul(net,w2)+b2
#定义softmax
def softmax(o):
    #tf.nn.softmax()
    y_exp=tf.exp(o)
    exp_sum=tf.reduce_sum(y_exp,axis=1,keep_dims=True) #求和 保持维度不变
    y=tf.divide(y_exp,exp_sum)
    return y
y=softmax(net)
    
#定义正确率
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#定义交叉熵损失函数
loss=-tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
#定义优化器
sgd=tf.train.GradientDescentOptimizer(0.001).minimize(loss)

    训练网络。

%%time
BATCH_SIZE=64
w_history=[]
b_history=[]
EPOCHS=30
BATCH_SIZE=128
pred=None
#生成对话,训练网络
with tf.Session() as sess:
    init_op=tf.global_variables_initializer() #初始化所有的Variable
    sess.run(init_op)
    
    for i in range(EPOCHS):
        xlen=x_train.shape[0]
        permutation = np.random.permutation(xlen)
        x_data = x_train[permutation]
        y_data = y_train_onehot[permutation]
        
        for j in range(xlen//BATCH_SIZE-1):
            x_batch=x_data[j*BATCH_SIZE:(j+1)*BATCH_SIZE,:]
            y_batch=y_data[j*BATCH_SIZE:(j+1)*BATCH_SIZE,:]
            sess.run(sgd,feed_dict={x:x_batch,y_:y_batch})
            
        acc=sess.run(accuracy,feed_dict={x:x_data[:1000],y_:y_data[:1000]})
        print('%d train acc:%f'%(i,acc))
    
    acc=sess.run(accuracy,feed_dict={x:x_test,y_:y_test_onehot})
    
    pred=sess.run(y,feed_dict={x:x_test[:30],y_:y_test_onehot[:30]})
    
    print('test acc:',str(acc))

    训练精度超过70%。


参考文献

[1]Jerry_Jin.Difference between ReLU、LReLU、PReLU、CReLU、ELU、SELU.https://www.cnblogs.com/jins-note/p/9646602.html . 2018-09-14

下一篇: 没有了

首页 所有文章 机器人 计算机视觉 自然语言处理 机器学习 编程随笔 关于