【Tensorflow专题-03】深层神经网络

时间:2022-12-14 17:11:47
  • 基本定义:一类通过多层非线性变换对高复杂度性数据建模算法的合集。

  • 激活函数实现去线性化

    在前面所提到的示例中,输入输出与权值有关系: y=xW ,换句话说,对于任何输入输出,都可以通过与权值进行加权求得,但这样的结果,实践证明无法解决高于一维的数据分类问题,由此提出去线性化 的概念,也即激活函数 。以下给出加入了激活函数和偏置项后的神经元结构

    【Tensorflow专题-03】深层神经网络

    上面的结构使用函数表达为:

    A=f(xW+b)

    对比之前的激活函数,其实就是在其基础上进行了一次函数运算。以下给出了几种常用的非线性函数的激活函数图像

    【Tensorflow专题-03】深层神经网络

    tensorflow一共提供了7种不同的激活函数,当然,tensorflow也支持自己定义激活函数。

  • 损失函数

    • 损失函数刻画了神经网络的输出结果与目标之间的差距

    • 经典损失函数

    • 对于分类问题,一般会按照分类的数目来确定输出数目,通常n分类问题会有n个输出,比如,对于一个数字识别问题,其实就是10分类问题,这样的输出可以刻画为 [0,0,0,1,0,0,0,0,0,0] ,1代表输出的结果为真,反之为假,那么前面的例子标识的就是结果为:3。当然,为了更准确的用数学语言描述,我们需要把输出转换为概率语言表达,通过交叉熵(cross entropy) 来刻画输出向量与期望向量之间的近似程度,对于概率分布 p,q ,他们的交叉熵定义为:H(p,q)=-\sum_\limits xp(x)log(q(x)) 。有的时候,神经网络输出的结果并不一定是概率分布,这时就需要把其转换为概率分布,通过Softmax回归实现这个目标,如下示意:

      【Tensorflow专题-03】深层神经网络

      Softmax的函数表达式定义为:

      softmax(y)i=yi=eyjnj=ieyj

    • 对于回归问题,输出节点一般仅有一个,对于这种类别,常用的损失函数为均方误差(MSE mean squared error) ,其定义如下:

      MSE(y,y)=ni=1(yiyi)2n

    • 自定义损失函数:损失函数的定义有时需要结合实际问题进行设定,以下给出一个使用自定义损失函数和使用MSE的例子,这里求解的问题为:

    【Tensorflow专题-03】深层神经网络

    代码如下:

    
    # TensorFlow 在模拟训练集上展示完整的训练过程
    
    
    # author = yooongchun
    
    
    # time = 20180107
    
    
    # 解决商品销量预测问题,同时引入损失函数概念,说明考察的指标不同,则定义的损失函数也应该有异
    
    import tensorflow as tf
    from numpy.random import RandomState
    
    
    # 定义训练集大小
    
    batch_size=8
    
    
    # 输入的placeholder
    
    
    # None参数表示训练集数据放到了一个batch中
    
    
    # 输入2个节点
    
    x=tf.placeholder(tf.float32,shape=(None,2),name='x-input')
    
    # 输出节点,对于回归问题,一般仅有一个输出节点
    
    y_=tf.placeholder(tf.float32,shape=(None,1),name='y-input')
    
    
    # 定义神经网络参数
    
    w1=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
    
    
    # 定义神经网络前向传播过程
    
    
    # 仅通过线性加权获得
    
    y=tf.matmul(x,w1)
    
    
    # 定义损失函数
    
    
    # 损失函数参数,分别为多预测和少预测对应的损失
    
    loss_less=1
    loss_more=10
    
    # 使用自定义损失函数
    
    loss=tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*loss_more,(y_-y)*loss_less))
    
    # 使用MSE均方值定义损失函数
    
    loss_mse=tf.reduce_mean(tf.square(y-y_))
    train_step=tf.train.AdamOptimizer(0.001).minimize(loss_mse)
    
    
    # 生成随机数模拟数据集
    
    rdm=RandomState(1)
    dataset_size=128
    X=rdm.rand(dataset_size,2)
    
    
    # 定义标签,并加入噪音(为了区别不同损失函数之间的差别)
    
    Y=[[x1+x2+rdm.rand()/10.0-0.05] for (x1,x2) in X]
    
    
    # 创建会话进行训练
    
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
    
        # 设定训练轮数
        STEPS=5000
        for i in range(STEPS):
            start=(i*batch_size)%dataset_size
            end=min(start+batch_size,dataset_size)
            # 选择样本训练
            sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
        print(sess.run(w1))
  • 神经网络优化算法

    • 反向传播(backpropagation)算法和梯度下降(gradient decent)算法是用来调整神经网络参数的主要算法

    • 梯度下降算法更新参数 θ 的公式为: θn+1=θnηθnJ(θn) ,式中, η 代表学习率(learning rate)

    • 梯度下降算法理论上只能达到局部最优,如下示意:

    【Tensorflow专题-03】深层神经网络

    另外,梯度下降算法对于大量数据收敛很慢,这时提出一种改进算法:随机梯度下降(stochastic gradient descent)算法,即对于每一次参数更新,只选择一部分(batch)数据进行更新,这样能兼顾正确性和收敛速度。

    • 指数衰减学习率

    过大的学习率可能会导致模型参数振荡,而太小的学习率会导致收敛太慢,鉴于此,设置一种先大后小的指数型衰减学习率,以保证模型既能较快收敛又不至于振荡。

    【Tensorflow专题-03】深层神经网络

    • 过拟合问题

    当模型的参数多到能够完全区分每个变量,这时数据的噪声已经被模型所包含,这样的模型失去了“预测”的功能,称之为:过拟合。如下图示:

    【Tensorflow专题-03】深层神经网络

    避免过拟合的一个常用方法称之为:正则化(regularization)。正则化的思想是在损失函数中加入刻画模型复杂度的指标。当损失函数为 J(θ) 时,加入正则化后优化的目标即成为 J(θ)+λR(w) ,其中, R(w) 刻画的就是模型的复杂度,而 λ 代表模型复杂度在总损失中占有的比例。常用的 R(w) 有两种,其一为 L1 正则化,数学描述为:

    R(w)=||w||1=i|wi|

    其二为 L2 正则化,数学描述为:

    R(w)=||w||22=i|w2i|

    正则化的目的在于限制权重的大小,使得模型不能任意拟合训练数据中的随机噪声。这两种正则化各有特点,其中,L1正则化会使得模型参数变稀疏(更多参数变为0),而L2则不会;另外,L2正则化公式可导,而L1不可。有时,会把两种正则化方法一起使用,如: R(w)=iα|wi|+(1α)w2i

    • 滑动平均模型:滑动平均模型能保证模型在测试数据集上更健壮。

    Tensorflow提供了tf.train.ExponentialMovingAverage来实现滑动平均模型。初始化时该函数使用一个衰减率(decay)来控制模型更新的速度。该函数对每一个变量维护一个影子变量(shadow variable),其更新规则为:

    shadow_variable=decayshadow_variable+(1decay)variable

    易看出,越大的衰减率,模型更新速度越慢,Tensorflow提供了动态更新decay的机制,当提供一个 num_updates 参数时,衰减率更新公式为:

    decay=min{decay,1+num_updates10+num_updates}

    num_updates=10 时,decay取值如下:

    【Tensorflow专题-03】深层神经网络

    一个使用滑动平均模型的例子

    
    # TensorFlow 滑动平均模型
    
    
    # author = yooongchun
    
    
    # time = 20180113
    
    
    import tensorflow as tf
    
    
    # 定义变量
    
    v1 = tf.Variable(0, dtype=tf.float32)
    
    # step 模拟训练轮数
    
    step = tf.Variable(0, trainable=False)
    
    
    # 定义一个滑动平均类,初始衰减率给定0.99,控制衰减率变量为step
    
    ema = tf.train.ExponentialMovingAverage(0.99, step)
    
    # 定义一个更新变量滑动平均的操作
    
    maintain_average_op = ema.apply([v1])
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        # 获取参数的滑动平均
        sess.run(maintain_average_op)
        print(sess.run([v1, ema.average(v1)]))
        # 更新变量值
        sess.run(tf.assign(v1, 5))
        sess.run(maintain_average_op)
        print(sess.run([v1, ema.average(v1)]))
        # 更新step
        sess.run(tf.assign(step, 10000))
        sess.run(tf.assign(v1, 10))
        sess.run(maintain_average_op)
        print(sess.run([v1, ema.average(v1)]))
    
        sess.run(maintain_average_op)
        print(sess.run([v1, ema.average(v1)]))