多层神经网络

背景

上一章通过实验验证了单层神经网络的拟合功能。但是在实际环境中,发现这种拟合的效果极其有限。对于某些样本,即便是Maxout也无法解决问题。追究根本,源于样本本身的特性,即单层神经网络只能结果对线性可分的问题。

线性可分与线性不可分

可以用直线(或平面)分割的方式解决问题,则可以说这个问题是线性可分的。同理,类似这样的数据集就可以被称为线性可分数据集合。
在这里插入图片描述
在这里插入图片描述
非线性问题,就是用直线(或平面)分不开的问题。虽然可以通过数学公式进行变化,但有时候数据维度太大,根本无法可视化,这就需要使用多层神经网络来解决问题了。
在这里插入图片描述

使用隐藏层解决非线性问题
实例:使用带隐藏层的神经网络拟合异或操作

1.数据集介绍
所谓“异或数据”就是来源于异或操作,两个数相同时,输出为0,不相同时输出为1,这就是异或的规则。表示为两类数据就是(0,0)和(1,1)为一类,(0,1)和(1,0)为一类。
在这里插入图片描述
2.网络模型介绍
本例中使用了一个隐藏层来解决这个问题,当然隐藏层的神经元个数没有图中这么多。
在这里插入图片描述
3.定义变量
第一步定义变量,在网络参数的定义中,输入是“2”代表两个数(可以理解为两个特征),输出是“1”代表最终结果,在放一个隐藏层,该层里有两个节点。输入占位符为x,输出为y,学习率为0.0001。

import tensorflow as tf
import numpy as np

learning_rate = 1e-4
n_input = 2
n_label = 1
n_hidden = 2

x = tf.placeholder(tf.float32,[None,n_input])
y = tf.placeholder(tf.float32,[None,n_label])

4.定义学习参数
这里以字典的方式定义权重w和b,里面的h1代表隐藏层,h2代表最终的输出层。

weights = {
    'h1':tf.Variable(tf.truncated_normal([n_input.n_hidden],stddev=1.0)),
    'h2':tf.Variable(tf.truncated_normal([n_hidden,n_label],stddev=1.0))
}
biases = {
    'b1':tf.Variable(tf.zeros([n_hidden])),
    'b2':tf.Variable(tf.zeros([n_label]))
}

5.定义网络模型
该例中模型的正向结构入口为x,经过与第一层的w相乘再加上b,通过Relu函数进行激活转化,最终生成layer_1,再将layer_1代入第二层,使用Tanh激活函数生成最终的输出y_pred。

layer_1 = tf.nn.relu(tf.add(tf.matmul(x,weights['h1']),biases['b1']))
y_pred = tf.nn.tanh(tf.add(tf.matmul(layer_1,weights['h2']),biases['b2']))

loss = tf.reduce_mean(tf.pow(y_pred-y,2))
train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)

模型的反向使用均值平方差(即对预测值与真实值的差取平均值)计算loss,最终使用AdamOptimizer进行优化。
6.构建模拟数据

#生成数据
X = [[0,0],[0,1],[1,0],[1,1]]
Y = [[0],[1],[1],[0]]
X = np.array(X).astype('float32')
Y = np.array(Y).astype('int16')

手动建立X和y数据集,形成对应的异或关系
7.运行session,生成结果

#加载session
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

#训练
for i in range(100000):
    sess.run(train_step,feed_dict={x:X,y:Y})

#计算预测值
print(sess.run(y_pred,feed_dict={x:X}))

#查看隐藏层的输出
print(sess.run(layer_1,feed_dict={x:X}))

结果:
[[5.7726265e-07]
[9.9998635e-01]
[9.9998671e-01]
[5.7726265e-07]]
[[0. 0. ]
[1.6117644 0. ]
[0. 1.4968766]
[0. 0. ]]
分析:结果为四舍五入后为 0 1 1 0和我们标签值一致。

过拟合与欠拟合

欠拟合可以理解为一个学渣,上课下课不学习,对课本知识很模糊,所以期末考试分数很低。
过拟合可以理解为一个书呆子,虽然把课本知识完完全全掌握了,但是期末考试却不会变通,分数也不高。
事实上,我们的训练数据集的数据不可能会完全没有一点问题,总是会存在一些少数的错误数据,而过拟合会把这些数据一起学会,这是我们不希望看到的。为此,我们有以下方式进行解决:
·early stopping:顾名思义,也就是在发生过拟合之前停止训练。
·增大数据集:通过增大数据集,让模型更加见多识广,然而这种方法效果不好。
·正则化:通过引入范数,增强模型的泛化能力。
·dropout:通过每次训练时舍去一些节点来增强泛化能力。
下面,我们具体介绍一些后两种。

正则化

所谓正则化,其实就是在神经网络计算损失值的过程中,在损失后面再加一项。这样损失值所代表的输出值与标准结果间的误差就会受到干扰,导致学习参数w和b无法按照目标方向来调整,实现模型无法与样本完全拟合的结果,从而到达防止过拟合的效果。
理解原理之后,现在就来介绍如何添加这个干扰项。干扰项一定要有这样的特性:
当欠拟合时,希望它对模型误差的影响越小越好,以便让模型快速拟合实际。
如果是过拟合时,希望它对模型误差的影响越大越好,以便让模型不要产生过拟合的情况。
由此引入了两个范式L1和L2:
L1:所有学习参数w的绝对值的和,乘以λ/n。
L2:所有学习参数w的平方,除以训练集的样本大小n。
如果放到损失函数公式里,会将其变形一下:
L1:
l e s s = l e s s ( 0 ) + λ ∑ W n ∣ W ∣ less = less(0)+\lambda \sum_{W}^{n}\left | W \right | less=less(0)+λWnW
L2:
l e s s = l e s s ( 0 ) + λ 2 ∑ W n W 2 less = less(0)+\frac{\lambda }{2}\sum_{W}^{n}W^{2} less=less(0)+2λWnW2
解释:
最终的loss为等式左边的结果,less(0)代表真实的loss值,less(0)后面的那一项就代表正则化了,λ为一个可以调节的参数,用来控制正则化对loss的影响。

TensorFlow中的正则化

L1的正则化函数(自行封装):
tf.reduce_sum(tf.abs(w))
L2的正则化函数:
tf.nn.l2_loss(t,name=None)

Dropout
dropout原理

有一种常用的过拟合的方法叫dropout。dropout的意思是,在训练过程中,每次随机选择一部分节点不要去“学习”。
这样做得原理是什么?
因为从数据的分析来看,数据本身是不可能很纯净的,即任何一个模型不能100%把数据完全分开,在某一类中一定会有一些异常数据,过拟合的问题恰恰把这些异常数据当成规律来学习。对于模型来说,我们希望它能够有一定的“智商”,把异常的数据过滤掉,只关心有用的规律数据。
异常数据的特点是,它与主流样本中的规律都不同,但是量非常少,相当于在一个样本中出现的概率比主流数据出现的概率低很多。我们就是利用这个特性,通过在每次模型中忽略一些节点的数据学习,将小概率的异常数据获得学习的机会降低,这样这些异常数据对模型的影响就会更小了。
注意:由于dropout让一部分节点不去“学习”,所以在增加模型的泛化能力的同时,会使学习速度降低,是模型不太容易“学成”,所以在使用的过程中需要合理地调节到底丢弃多少节点,并不是丢弃的节点越多越好。

TensorFlow中的dropout

在TensorFlow中dropout的函数原型如下:
def dropout(x,keep_prob,noise_shape=None,seed=None,name=None)
其中参数的含义如下:
x:输入的模型节点
keep_prob:保持率。如果为1,则代表全部进行学习;如果为0.8,则代表丢弃20%的节点,只让80%的节点去学习。
noise_shape:代表指定的x中,哪些维度可以使用dropout技术。为None时,表示所有维度都使用dropout技术,也可以将某个维度标志位1,来代表该维度使用dropout技术。例如:x的形状为[n,len,w,ch],使用nose_shape未[n,1,1,ch],这表明会对x中的第二维度len和第三维度进行drop。
seed:随机选取节点的过程中随机数种子值。
注意:drop改变了神经网络的结构,它仅仅是属于训练时的方法,所以一般在进行测试时,要将dropout的keep_prob变为1,代表不需要进行丢弃,否则会影响模型的正常输出。

基于退化学习率dropout技术

有些时候,我们会看到损失值会发生抖动现象,即一时减少,一时增加,这表明后期的学习率有点大了。使用退化学习率,让开始的学习率很大,后面逐渐变小。

loss = blablabla.......
learning_rate = 0.1
global_step = tf.Variable(0,trainable=False)
#设置每1000,学习率衰减0.9
decaylearning_rate = tf.train.exponential_decay(learning_rate,global_step,1000,0.9)
optimizer = tf.train.AdamOptimizer(dacaylearning_rate).minimize(lost,global_step=global_step)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值