本系列是实际深度学习框架的知识笔记。只是博主在看书的过程中认为比较重要的知识点。总结的比较简单,内容比较零散。请大家指出,共同进步。
2017-11-06
[第 4 章] 深度神经网络
1.深度学习和深度神经网络
维基百科对深度学习的准确定义是:通过多层非线性变换对高复杂度数据进行建模的算法集合。由于深度神经网络是实现“多层非线性变换”最常用的方法之一,因此深度学习具有两个非常重要的属性——多层和非线性。
只有通过线性变换,任何层的全连接神经网络和单层网络模型的表达能力没有区别,都是线性模型,然后线性模型能解决的问题是有限的。
如果每个神经元(即神经网络中的节点)的输出都经过一个非线性函数,那么整个神经网络的模型就不再是线性的了。这个非线性函数就是激活函数。
监督学习的两大类型是分类问题和回归问题。
通过神经网络解决多分类问题最常用的方法是设置n个输出节点,其中n是类别数。对于每个例子,神经网络可以得到一个n维数组作为输出结果,数组中的每一维(即每个输出节点)对应一个类别。理想情况下,如果一个样本属于第 k 类,则该类对应的输出节点的输出值应该为 1,其他节点的输出应该为 0。以标识号 1 为例,该类的输出越接近神经网络模型为[0,1,0,0,0,0,0,0,0,0],越好。那么如何判断一个输出向量与预期向量的接近程度呢?交叉熵(cross)是常用的评价方法之一。交叉熵描述了两个概率分布之间的距离,是分类问题中广泛使用的损失函数。注意:两个概率分布之间的距离用交叉熵来描述,但神经网络的输出不一定是概率分布。如何将神经网络前向传播得到的结果转化为概率分布?回归是一种非常常见的方法。回归本身可以作为一种学习算法来优化分类结果,但是在 中,回归的参数被去掉了,只是额外的一层处理,将神经网络的输出变成了概率分布。
从上式可以看出,以原神经网络的输出作为置信度来生成新的输出,新的输出满足概率分布的所有要求。这个新的输出可以理解为神经网络的推导,一个样本属于不同类别的概率是多少,这样神经网络的输出也变成了一个概率分布,这样就可以计算出预测的概率通过交叉熵分布与真实答案的概率分布之间的距离。
从交叉熵的公式可以看出,交叉熵函数是不对称的,它通过概率分布q来描述概率分布p的表达难度。因为正确答案是期望的结果,所以当使用交叉熵作为神经网络的损失函数时,p代表正确答案,q代表预测值。交叉熵描述了两个概率分布之间的距离。交叉熵值越小,两个概率分布越接近。
看过一句话,很生动。 (SVM只选择喜欢的男神,拉出所有备胎得分,最后归一化。)
因为交叉熵一般和回归一起使用,所以这两个函数统一封装和tf.nn。提供了功能。比如回归后的交叉熵损失函数可以直接通过如下代码实现:
= tf.nn.(y,y_)
其中y代表原始神经网络的值,输出结果,y_给出标准答案。这样,一个命令就可以得到使用回归后的交叉熵。在只有一个正确答案的分类问题中,tf.nn。提供函数以进一步加快计算过程。
与分类beni不同,回归问题解决的是具体数值的预测,比如房价预测、销售预测等都是回归问题。解决回归问题的神经网络一般只有一个输出节点,这个节点的输出值就是预测值。对于回归问题,最常用的损失函数是均方误差(MSE,mean error),代码如下:
mse = tf.(tf.(y-y_))
其中y代表神经网络的输出答案,y_代表标准答案。
自定义损失函数的优化,在中,这个损失函数可以通过以下代码实现:
loss = tf.(tf.(tf.(v1,v2),(v1-v2)*a,(v2-v1)*b))
上面的代码使用了 tf.和 tf。实施选择操作。 tf 的输入。是两个张量。该函数将比较两个输入张量中每个元素的大小并返回比较结果。当输入张量的维度为 tf.不同的是,类似numpy的广播会进行()运算处理。
3.神经网络优化算法
梯度下降算法主要用于优化单个参数的值,而反向传播算法给出了一种在所有参数上使用梯度下降算法的有效方式,使得神经网络模型的损失函数在训练数据尽可能小。
神经网络的优化过程可以分为两个阶段,第一个阶段,通过前向传播算法计算预测值,得到预测值与真实值的差值比较预测值。第二阶段,通过反向传播算法计算每个参数的损失函数的梯度,然后使用梯度下降算法根据梯度和学习率更新每个参数。需要注意的是,梯度下降算法并不保证优化后的函数达到全局最优解,参数的初始值会极大地影响最终结果。只有当损失函数为凸时,梯度下降算法才能保证达到全局最优解。
梯度下降算法除了不一定达到全局最优外,另一个问题是计算时间太长,因为要在所有训练数据上最小化损失,所有损失J(θ)都是损失之和在所有训练数据上。为了加快训练过程,可以使用随机梯度下降算法(SGD, ),该算法优化的不是所有训练数据上的损失函数,而是在每次迭代中,立即优化某一块训练数据上的损失函数。另外由于某条数据上的损失函数并不能代表所有数据,所以使用随机梯度下降优化的神经网络甚至可能达不到局部最优。
4.神经网络进一步优化
对于设置学习率的问题,提供了更灵活的方法。学习率设置方法—指数衰减法。 tf.train。函数实现指数衰减学习率。通过这个功能,可以使用较大的学习率快速得到更好的解,然后随着迭代不断地逐渐降低学习率,使模型在训练后期更加稳定。该函数以指数方式降低学习率,实现如下功能:
e = * ^ ( / )
其中e是每轮优化使用的学习率,是预先设定的初始学习率,是衰减系数,是衰减速度。 tf.train。函数可以通过设置参数选择不同的衰减方式。默认值为假。当设置为 True 时,/ 将被转换为整数。它通常表示一次完全使用训练数据所需的迭代次数,这个迭代次数是训练样本的总数除以每批训练样本的数量。下面用简单的代码表示:
= tf.(0)
= tf.train.(0.1,,100,0. 96,=True)
#使用指数衰减的学习率,传入函数会自动更新参数,这样学习率也会相应更新
= tf.train. izer().(…,=)
上面代码中,初始学习率设置为0.1,因为指定为True,所以每100轮训练后的学习率乘以0.96。
为了避免过拟合的问题,一个很常用的方法是正则化()。正则化的思想是在损失函数中加入表征模型复杂度的一个指标。假设用来描述模型在训练数据上性能的损失函数是J(θ),那么不直接优化J(θ),而是优化J(θ)+λR(w)。其中,R(w)描述了模型的复杂度,λ表示模型复杂度损失在总损失中的比例。有两个常用的函数 R(w) 来描述模型的复杂性。一种是L1正则化,计算公式为:
另一个是L2正则化,计算公式为:
,无论使用哪种正则化方法,其基本思想都是限制权重的大小,使模型不能任意拟合训练数据中的随机噪声。但是这两种正则化方法也有很大的不同。首先,L1 正则化会使参数变得更加稀疏,而 L2 正则化不会。所谓参数变稀疏,是指更多的参数会变成0,可以实现类似的特征提取功能。在实践中,L1正则化和L2正则化也可以同时使用:
下面的代码展示了使用set()计算L2正则化的5层神经网络损失函数的计算方法:
#获取一层神经网络边缘的权重,并将该权重的L2正则化损失加入名为”的集合中
定义(形状,):
#生成一个变量
var = tf.(tf.(shape),dtype=tf.)
#函数正则化这个新生成的变量的L2 将损失项添加到集合中
#这个函数的第一个参数”是集合的名称,第二个参数是添加这个集合的内容
tf.(”,tf…()(var))
变量
使用这种方法计算损失函数会大大增强代码的可读性。
还可以在 tf.tra in.rage 中实现移动平均模型。初始化rage时,需要提供一个衰减率,用来控制模型更新的速度,rage会为每个变量维护一个变量( ),这个变量的初始值就是对应的初始值变量,并且每次运行变量更新时,影子变量的值都会更新如下:
= 衰减 * + (1 – 衰减) *
这里是变量,也就是要更新的变量,decay是衰减率。从公式可以看出,衰减决定了模型更新的速度。衰减越大,模型越稳定。在实际应用中,decay一般设置为非常接近1的数字(如0.999),以使模型在训练初期更新更快。
以下是解释愤怒如何使用的代码。
作为 tf
#定义一个变量用于计算滑动平均,这个变量的初始值为0,注意这里手动指定了变量的类型为tf.float32
# 因为所有需要计算滑动平均的变量必须时实数型
v1 = tf.Variable(0,dtype=tf.float32)
#这里step变量模拟神经网络中迭代的轮数,用于动态控制衰减率
step = tf.Variable(0,trainable=False)
#定义一个滑动平均的类(class).初始化给定了衰减率(0.99)和控制衰减率的变量step
ema = tf.train.ExponentialMovingAverage(0.99,step)
#定义一个更新变量滑动平均的操作,这里需要给定一个列表,每次执行这个操作时这个列表中的变量都会更新
maintain_average_op = ema.apply([v1])
with tf.Session() as sess:
#初始化所有变量
init_op = tf.global_variables_initializer()
sess.run(init_op)
#通过ema.average(v1)获取滑动平均之后变量的取值。在初始化之后变量v1的值和v1的滑动平均都为0
print(sess.run([v1,ema.average(v1)])) #输出[0.0,0.0]
#更新变量v1的值到5
sess.run(tf.assign(v1,5))
#更新v1的滑动平均值,衰减率为min{0.99,(1+step)/(10+step)=0.1}=0.1
#所以v1的滑动平均会被更新为0.1*0+0.9×5=4.5
sess.run(maintain_average_op)
print(sess.run([v1,ema.average(v1)])) #输出[5.0,4.5]
#更新step的值为10000
sess.run(tf.assign(step,10000))
#更新v1的值为10
sess.run(tf.assign(v1,10))
#更新v1的滑动平均值,衰减率为min{0.99,(1+step)/(10+step)=0.999}=0.99
#所以v1的滑动平均会被更新为0.99*4.5+0.01*10=4.555
sess.run(maintain_average_op)
print(sess.run([v1,ema.average(v1)])) #输出[10.0,4.555]
#再次更新滑动平均值,得到的新滑动平均值为0.99*4.555+0.01*10=4.609
sess.run(maintain_average_op)
print(sess.run([v1,ema.average(v1)])) #输出[10.0,4.609]
暂无评论内容