深度学习——神经网络

一:神经网络介绍

 传统神经网络结构比较简单,训练时随机初始化输入参数,并开启循环计算输出结果,与实际结果进行比较从而得到损失函数,并更新变量使损失函数结果值极小,当达到误差阈值时即可停止循环。

神经网络的训练目的是希望能够学习到一个模型,实现输出一个期望的目标值。学习的方式是在外界输入样本的刺激下不断改变网络的连接权值。传统神经网络主要分为以下几类:前馈神经网络反馈型神经网络和自组织神经网络。这几类网络具有不同的学习训练算法,可以归结为监督学习算法和非监督学习算法。

  • 前馈神经网络

前馈神经网络是一种单向多层的网络结构,即信息是从输入层开始,逐层向一个方向传递,一直到输出层结束。所谓的”前馈“是指输入信号的传播方向为前向,在此过程中并不调整各层的权值参数,而反传播时是将误差逐层向后传递,从而实现使用权值参数对特征的记忆,即通过反向传播(BP)算法来计算各层网络中神经元之间边的权重。BP算法具有非线性映射能力,理论上可逼近任意连续函数,从而实现对模型的学习

  1. 感知器

感知器是一种结构最简单的前馈神经网络,也称为感知机,它主要用于求解分类问题。感知器是单层感知器的简称,除此之外还有多层感知器,即由多层神经元构成前馈神经网络。如下图所示:

                                                                                    单层感知器结构

一个感知器可以接收n个输入x=(x1,x2,...,xn),对应几个权值w=(w1,w2,...,wn),此外还要一个偏置项阈值,就是图中的b,神经元将所有输入参数对应权值进行加权求和,得到的结果经过激活函数变换后输出,计算公式如下:

                                                                  y=f(x*w+b)

感知器的激活函数有很多种,比如Sigmoid函数、双曲正切函数(tanh)、ReLU函数等,主要作用是非线性映射,从而对现实环境中非线性数据建模。除此之外还有线性函数、斜坡函数、阶跃函数等,在激活函数选择时,一般选择光滑、连续和可导的函数,将结果转换成固定的输出范围,例如[0,1],这样,在分类时通过判断y值来判定样本类别。

神经元的作用可以理解为对输入空间进行直线划分,单层感知器无法解决最简单的非线性可分问题——异或问题,如下图,感知器可以顺利求解与(AND)和或(OR)问题,但是对应异或(XOR)问题,单层感知器无法通过一条线进行分割。

2.BP神经网络

BP神经网络也称为前馈神经网络,只是它的参数权重值是由反向传播学习算法进行调整的。BP神经网络模型拓扑结构包括输入层(input)、隐藏层(hide layer)和输出层(output layer),如下图所示,利用激活函数实现从输入到输出的任意非线性映射,从而模拟更曾神经元之间的交互。激活函数需满足处处可导的条件。例如,Sigmoid函数连续可微,求导合适,单调递减,输出值是0~1的连续量,这些特点使其适合作为神经网络的激活函数。

BP神经网络训练过程的基本步骤可以归纳如下:

  • 初始化网络权值和神经元的阈值,一般通过随机的方式进行初始化。
  • 前向传播:计算隐层神经元和输出层神经元的输出。
  • 反向传播:根据目标函数公式修正权值wij. 

BP神经网络的核心思想是由后层误差推导前层误差,用输出层的误差来估计隐层的误差,再用这个误差估计输入层的误差,如此一层一层地反传,最终获得各层的误差估计,从而得到参数的权重值。由于权值参数的运算量过大,一般采用梯度下降法来实现,所谓梯度下降就是让参数向着梯度的反方向前进一段距离,不断重复,直到梯度接近零时停止。此时,所有的参数恰好达到使成本函数取得最低值的状态,为了避免局部最优,可以采用随机化梯度下降。 

  • 神经网络的相关概念

学习神经网络相关概念有助于理解深度学习中网络设计原理,可在模型训练过程中收放自如的调整参数,并且这些神经网络相关概念是深度学习的基础,随着深度学习的不断演化,深入理解这些常识性理论有助于快速理解层出不穷的深度学习网络模型。

  1. 激活函数

使用非线性激活函数的原因是线性模型的表达能力不够,通过对输出结果应用激活函数而引入非线性变换。如果不用激活函数,每一层输出都是上层输入的线性函数,那么每一次的输出都是输入的线性组合,与只有一个隐藏层效果是一样的。引入非线性函数作为激活函数之后,深层神经网络才有意义,可以逼近任意函数。激活函数经常使用Sigmoid函数,其输出有界。此外,常见的激活函数还有ReLU函数。激活函数通常有以下性质。

  • 非线性

神经网络中神经元完成线性变换后,叠加一个非线性激活函数,转换输出为非线性函数结果,神经网络就有可能学习导平滑的曲线来分割平面,而不是通过复杂的线性组合逼近平滑曲线来实现。当激活函数是非线性的时候,一个两层的神经网络理论上可以逼近所有的函数。

  • 可微性

当基于梯度的优化方法时,激活函数需要满足可微性,因为在反向传播更新梯度时,需要计算损失函数对权重的偏导数。传统的激活函数sigmoid满足处处可微的特性,而ReLU函数仅在有限个点处不可微。对于随机梯度下降算法,几乎不可能收敛到梯度接近零的位置,所以有限的不可微点对于优化结果影响不大。

1.Sigmoid函数

sigmoid函数的优点在于输出范围有限,数据在传递的过程中不容易发散,并且其输出范围为(0,1),可以在输出层表示概率值,如下图所示。Sigmoid函数的导数是非0的,很容易计算。

Sigmoid函数的主要缺点是梯度下降非常明显,且两头过于平坦,容易出现梯度消失的情况,输出的值域不对称。

2.ReLU函数

ReLU函数是目前神经网络中常用的激活函数,这是因为ReLU函数的线性特点使其收敛速度比Sigmoid要快,而且没有梯度饱和的情况出现。计算更加高效,相比于Sigmoid函数,只需一个阈值就可以得到激活值,不需要对输入归一化来防止达到饱和,如下图所示

Sigmoid是饱和非线性函数,结果达到一定范围后不再变换,而ReLU是非饱和非线性函数,输出值范围是无限的,梯度下降速度更快,训练的时间更短。

Sigmoid函数能对细微的特征进行区分,所以适用于特征差别较小的情形,对于这种函数,为了避免激活函数进入饱和区,使隐层的输出结果趋同,要对输入值归一化处理。

ReLU函数的缺点是所有负值均被截断为结果0,从而导致特征丢失。ReLU要求学习率不能太高,如果学习率很大,会使网络中很多神经元都失效,即很多神经元的激活函数结果值为0.所有一般设置一个较小的学习率,如0.005.

2.损失函数

损失函数评价模型对样本拟合度,预测结果与实际值越接近,说明模型的拟合能力越强,对应损失函数的结果就越小;反之,损失函数的结果越大。损失函数比较大时,对应的梯度下降比较快。为了计算方便,可以采用欧式距离作损失度量标准,通过最小化实际值与估计值之间的均方误差作为损失函数,即最小平方误差准则

min C [Y,G(X)]=||G(X)-Y||^{2}=\sum [G(Xi)-y^{i}]^{2}

其中G(X)是模型根据输入矩阵X输出一个预测向量,预测值G(X)和真值Y的欧式距离越大,损失就越大,反之就越小。

  • Softmax

使用Softmax函数的好处是可以使分类问题的预测结果更加明显,不同类别之间的差距更大。在实际应用中,特别是在Tensorflow中推荐采用交叉熵与Softmax结合作为损失函数,可以避免数值不稳定的情况。

  • 交叉熵

目标为二分类问题,分类误差越小,则损失越小,对正负分类计算各自的损失。但是会产生梯度爆炸问题,例如,如果实际结果yn=1,但是预测结果yn接近于0,则logyn便趋向于负无穷,最终的损失趋向于无穷大,产生梯度爆炸问题。

下面是用Tensorflow实现简单的神经网络代码:

import numpy as np
import  tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets("MNIST_data",one_hot=True)
n_hidden_1=256  #第一层神经元
n_hidden_2=128  #第二层神经元
n_input=784     #输入像素点个数
n_classes=10 #最终得出分类的类别 10分类
#参数初始化
x=tf.placeholder("float",[None,n_input])
y=tf.placeholder("float",[None,n_classes])

stddev=0.1
weights={#初始化w1 w2 out 使用高斯初始化
    'w1':tf.Variable(tf.random_normal([n_input,n_hidden_1],stddev=stddev)),#w1=784*256
    'w2':tf.Variable(tf.random_normal([n_hidden_1,n_hidden_2],stddev=stddev)),#w2=256*128
    'out':tf.Variable(tf.random_normal([n_hidden_2,n_classes],stddev=stddev)) #out=128*10
}
biases={
    'b1':tf.Variable(tf.random_normal([n_hidden_1])),
    'b2':tf.Variable(tf.random_normal([n_hidden_2])),
    'out':tf.Variable(tf.random_normal([n_classes]))
}
print("NETWORK READY")
#前向传播
def multilayer_perceptron(_X,_weights,_biases): # _X表示data weights表示所有的w biases表示所有的b
    layer_1=tf.nn.sigmoid(tf.add(tf.matmul(_X,_weights['w1']),_biases['b1']))#计算layer1这层的输出值,每层后面都要加sigmoid激活函数
    layer_2=tf.nn.sigmoid(tf.add(tf.matmul(layer_1,_weights['w2']),_biases['b2'])) #计算layer2这层的输出值
    return  (tf.matmul(layer_2,_weights['out'])+_biases['out'])#输出层不需要sigmoid函数激活
#prediction
pred=multilayer_perceptron(x,weights,biases)
#定义损失函数
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred,labels=y))#交叉熵函数第一个参数是网络的预测值,第二个参数是实际的label值
optm=tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(cost)#运用梯度下降的优化器求解cost
corr=tf.equal(tf.argmax(pred,1),tf.argmax(y,1)) #模型的准确率
accr=tf.reduce_mean(tf.cast(corr,"float")) #转化成float类型计算精度
init=tf.global_variables_initializer()#全局变量初始化
print("FUNCTIONS READY")
training_epochs=20
batch_size=100
display_step=4

sess=tf.Session()#定义计算图的区域
sess.run(init)
for epoch in range(training_epochs):
    avg_cost=0
    total_batch=int(mnist.train.num_examples/batch_size)
    for i in range(total_batch):
        batch_xs,batch_ys=mnist.train.next_batch(batch_size)
        feeds={x:batch_xs,y:batch_ys}
        sess.run(optm,feed_dict=feeds)
        avg_cost+=sess.run(cost,feed_dict=feeds)
    avg_cost=avg_cost/total_batch
    if(epoch+1) % display_step ==0:
        print("Epoch:%03d/%03d costL%.9f" % (epoch,training_epochs,avg_cost))
        feeds={x:batch_xs,y:batch_ys}
        train_acc=sess.run(accr,feed_dict=feeds)
        print("TRAIN ACCURACY: %.3f" %(train_acc))
        feeds={x:mnist.test.images,y:mnist.test.labels}
        test_accc=sess.run(accr,feed_dict=feeds)
        print("TEST ACCURACY:%.3f" %(test_accc))
print("OPTIMIZATTION FINISHED")

 

猜你喜欢

转载自blog.csdn.net/qq_41338249/article/details/84555419