深层神经网络

TensorFlow实战Google深度学习框架学习笔记

1.通过激活函数实现去线性化

对于线性不可分的数据集,可以通过激活函数对神经网络模型去线性化。
常见的激活函数有:

  • ReLU函数:f(x) = max(x,0)
  • sigmoid函数: f ( x ) = 1 1 + e − x f(x) = \frac{1}{1+e^{-x}} f(x)=1+ex1
  • tanh函数: f ( x ) = 1 − e − 2 x 1 + e 2 x f(x) = \frac {1-e^{-2x}}{1+e^{2x}} f(x)=1+e2x1e2x

Tensorflow提供了七种不同的非线性激活函数。常见的有:tf.nn.relu;tf.nn.sigmoid;tf.tanh

#这是使用了ReLU激活函数和偏置项的神经网络前向传播算法。
# a  = tf.nn.relu(tf.matmul(x, w1) + biases1)
# y = tf.nn.relu(tf.matmul(a,w2) + biases2)

2.经典损失函数

分类问题的损失函数

1.首先介绍交叉熵的概念。

给定两个概率分布p和q,通过q来表示交叉熵的概念。
H ( p , q ) = − ∑ x p ( x ) l o g q ( x ) H(p,q) = - \sum_{x}p(x)logq(x) H(p,q)=xp(x)logq(x)

交叉熵刻画的是两个概率分布的距离 。预测结果与实际值相似度越高。交叉熵越小。

通过举例来说明信息熵的作用。假设有一个三分类问题,某个样例的正确答案是(1,0,0).某个模型进过预测之后的预测答案是(0.5,0.4,0.1),那么这个预测答案与正确答案的交叉熵为:
H ( ( 1 , 0 , 0 ) , ( 0.5 , 0.4 , 0.1 ) ) = − ( 1 × l o g 0.5 + 0 × l o g 0.4 + 0 × l o g 0.1 ) ≈ 0.3 H((1,0,0),(0.5,0.4,0.1)) = - (1\times log0.5 + 0 \times log0.4 + 0\times log0.1) \approx 0.3 H((1,0,0),(0.5,0.4,0.1))=(1×log0.5+0×log0.4+0×log0.1)0.3

如果另一个模型预测的结果是(0.8,0.1,0.1),那么预测值与真实的交叉熵为:
H ( ( 1 , 0 , 0 ) , ( 0.8 , 0.1 , 0.1 ) ) = − ( 1 × l o g 0.5 + 0 × l o g 0.4 + 0 × l o g 0.1 ) ≈ 0.3 H((1,0,0),(0.8,0.1,0.1)) = - (1\times log0.5 + 0 \times log0.4 + 0\times log0.1) \approx 0.3 H((1,0,0),(0.8,0.1,0.1))=(1×log0.5+0×log0.4+0×log0.1)0.3
可以发现很明显第一个预测值与实际值相似度更高,而他们的交叉熵也越小。

#在TensorFlow实现交叉熵的代码如下
#cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
#y_代表正确结果,y代表预测结果。
#tf.clip_by_value函数可以把一个张量的数值控制在一个范围内。可以避免一些不必要的数学计算错误。
#1.下面是使用tf.clip_by_value的简单样例。
import tensorflow as tf
sess  =tf.InteractiveSession()
v = tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
print(tf.clip_by_value(v,2.5,4.5).eval())
'''
输出
[[ 2.5  2.5  3. ]
 [ 4.   4.5  4.5]]
 '''
#2.对于tf.log函数,对张量中的所有元素依次求对数的功能。
v = tf.constant([1.0,2.0,3.0])
print(tf.log(v).eval())
#输出 [ 0.          0.69314718  1.09861231]

#3.矩阵乘法运算。
v1 = tf.constant([[1.0,2.0],[3.0,4.0]])
v2 = tf.constant([[5.0,6.0],[7.0,8.0]])
#元素依次相乘
print((v1*v2).eval())

#矩阵乘法
print(tf.matmul(v1,v2).eval())

#tf.reduce_mean 对整个矩阵取平均
v = tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
print(tf.reduce_mean(v).eval())
[[ 2.5  2.5  3. ]
 [ 4.   4.5  4.5]]
[ 0.          0.69314718  1.09861231]
[[  5.  12.]
 [ 21.  32.]]
[[ 19.  22.]
 [ 43.  50.]]
3.5

tf.nn.softmax_cross_entropy_with_logits函数可以计算softmax回归之后的交叉熵的损失函数。

#cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y)
#y代表原始神经网络的输出结果。y_给出了标准答案。

回归问题

回归问题的损失函数通常为均方误差函数。

M S E ( y , y ′ ) = ∑ i = 1 n ( y i − y i ′ ) ( 2 ) n MSE(y,y') = \frac{\sum^{n}_{i=1}(y_{i} - y'_{i})^(2)}{n} MSE(y,y)=ni=1n(yiyi)(2)


#mse = tf.reduce_mean(tf.square(y_ - y))

3.自定义损失函数

L o s s ( y , y ′ ) = ∑ i = 1 n f ( y i , y i ′ ) , f ( x , y ) = { a ( x − y ) x > y b ( y − x ) x ≤ y Loss(y,y') = \sum^{n}_{i=1}f(y_{i},y'_{i}), f(x,y) = \left\{\begin{matrix} a(x - y) & x>y \\ b(y - x) & x\leq y \end{matrix}\right. Loss(y,y)=i=1nf(yi,yi),f(x,y)={a(xy)b(yx)x>yxy

#用TensorFlow表示上边的损失函数。
#loss = tf.reduce_sum(tf.where(tf.greater(v1,v2), (v1 - v2) *  a, (v2 - v1) * b ))
#其中tf.greater函数接受两个变量,v1,v2。如果和 v1>v2 同义。
#tf.where.接受三个参数。第一个参数是boolean型选择条件。如果选择条件为True,就输出第二个参数。否则就输出第三个参数。
#下面展示了tf.where函数和tf.greater函数的用法。
v1 = tf.constant([1.0,2.0,3.0,4.0])
v2 = tf.constant([4.0,3.0,2.0,1.0])

print(tf.greater(v1,v2).eval())
print(tf.where(tf.greater(v1,v2),v1,v2).eval())
sess.close()
[False False  True  True]
[ 4.  3.  3.  4.]
'''
下面是将自定义的损失函数加入神经网络中。神经网络有俩个输入节点,一个输出节点。没有隐藏层。
'''
from numpy.random import RandomState
batch_size = 8
#两个输入节点。
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 = 10
loss_more = 1
loss = tf.reduce_sum(tf.where(tf.greater(y,y_),(y - y_) * loss_more, (y_ - y) * loss_less))
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
#通过随机数生成一个模拟数据集
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:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    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))
[[ 1.01934695]
 [ 1.04280889]]

4.神经网络优化算法

  • 梯度下降算法:
    梯度下降的公式为:
    θ n + 1 = θ n − η ∂ ∂ θ n J ( θ n ) \theta_{n+1} = \theta_{n} - \eta \frac{\partial }{\partial \theta_{n}} J(\theta_{n}) θn+1=θnηθnJ(θn)
    其中 η \eta η代表学习率。
    对于非凸函数,梯度下降有可能会达到局部最优。
  • 随机梯度下降算法:
    这个算法优化不是在全部数据上进行参数更新,而是在每一次迭代中,随机优化某一条训练数据的损失函数。
    缺点:在某一条数据上的损失函数最小并不能代表在全局数据上的损失函数最小。因此随机梯度下降甚至可能无法达到局部最优。
  • Tensorflow中的训练算法。
    每次计算只计算一小部分训练数据的损失函数。这一部分数据称为一个Batch.
'''
batch_size = n
# 每次只读取一小部分数据作为当前的训练数据来执行反向传播算法
x = tf.placeholder(tf.float32, shape = (batch_size, 2), name = 'x-input')
y_ = tf.placeholder(tf.float32, shape = (batch_size, 1), name = 'y-input')

#定义神经网络结构和算法

loss = ...
train_step = tf.train.AdamOptimizer(0.001).minimize(loss)

#训练神经网络
with tf.Session() as sess:
    #参数初始化。
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    STEPS =5000
    #准备batch_size个训练数据。一般将所有的训练数据随机打乱后再选取可以的到更好的优化效果。
    current_X, current_Y = ...
    sess.run(train_step, feed_dict = {x: current_X, y_: current_Y})
'''
"\nbatch_size = n\n# 每次只读取一小部分数据作为当前的训练数据来执行反向传播算法\nx = tf.placeholder(tf.float32, shape = (batch_size, 2), name = 'x-input')\ny_ = tf.placeholder(tf.float32, shape = (batch_size, 1), name = 'y-input')\n\n#定义神经网络结构和算法\n\nloss = ...\ntrain_step = tf.train.AdamOptimizer(0.001).minimize(loss)\n\n#训练神经网络\nwith tf.Session() as sess:\n    #参数初始化。\n    init_op = tf.global_variables_initializer()\n    sess.run(init_op)\n    STEPS =5000\n    #准备batch_size个训练数据。一般将所有的训练数据随机打乱后再选取可以的到更好的优化效果。\n    current_X, current_Y = ...\n    sess.run(train_step, feed_dict = {x: current_X, y_: current_Y})\n"

5.神经网络进一步优化

- 学习率设置

- 过拟合的解决

- 滑动平均模型

1. 学习率的设置

TensorFlow提供了一种更加灵活的学习率设置方法–指数衰减法。
tf.train.exponential_decay函数实现了指数衰减算法。一开始设置一个较大的学习率,随着迭代的继续进行学习率会逐步下降。
代码的功能如下所示:

decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)
其中dacayed_learing_rate表示:每一轮时使用的学习率
learning_rate:为初始学习率
decay_rate:为衰减系数
decay_steps:为衰减速度
staircase:默认参数设置为True.学习率的下降是曲线型的。如果参数为False.global_step / decay_steps转换为整数。学习率的下降是阶梯型的

'''
#在TensorFlow中使用tf.train.exponential_decay函数
global_step = tf.Variable(0)

#通过exponential_decay函数生成学习率

learing_rate = tf.train.exponential_decay(0.1,global_step,100,0.96, staircasr = True)

#使用指数衰减的学习率。在minimize函数传入global_step 将自动更新global_step参数。从而使得学习率也得到相应的更新。
learning_step = tf.train.GradientDescentOptimizer(learing_rate)\
.minimize(...my loss ..., global_step = global_step = global_step)
'''
'\n#在TensorFlow中使用tf.train.exponential_decay函数\nglobal_step = tf.Variable(0)\n\n#通过exponential_decay函数生成学习率\n\nlearing_rate = tf.train.exponential_decay(0.1,global_step,100,0.96, staircasr = True)\n\n#使用指数衰减的学习率。在minimize函数传入global_step 将自动更新global_step参数。从而使得学习率也得到相应的更新。\nlearning_step = tf.train.GradientDescentOptimizer(learing_rate).minimize(...my loss ..., global_step = global_step = global_step)\n'

2.过拟合的解决 - 正则化

正则化的思想就是在损失函数加入惩罚项,惩罚项就是刻画模型复杂度的指标。优化模型为:
J ( θ ) + λ R ( w ) J(\theta) + \lambda R(w) J(θ)+λR(w)
其中R(w)刻画的是模型的复杂度。常见的模型复杂度的函数有两种:

  • L1正则化: R ( w ) = ∣ ∣ w ∣ ∣ 1 = ∑ i ∣ w i ∣ R(w) = ||w||_{1} = \sum_{i}|w_{i}| R(w)=w1=iwi
  • L2正则化: R ( w ) = ∣ ∣ w ∣ ∣ 2 2 = ∑ i ∣ w i 2 ∣ R(w) = ||w||_{2}^{2} = \sum_{i}|w_{i}^{2}| R(w)=w22=iwi2

在实践中,L1正则化和L2正则化可以同时使用。
R ( w ) = ∑ i α ∣ w i ∣ + ( 1 − α ) w i 2 R(w) = \sum_{i}\alpha |w_{i}| + (1-\alpha)w_{i}^{2} R(w)=iαwi+(1α)wi2

'''
#TensorFlow给出一个简单的带L2正则化的损失函数定义:
w = tf.Variable(tf.random_normal([2,1], stddev = 1, seed = 1))
y = tf.matmul(x,w)

loss = tf.reduce_mean(tf.sqaure(y_ - y) + tf.contrib.layers.12_regularizer(lambdai)(w))

'''
'\n#TensorFlow给出一个简单的带L2正则化的损失函数定义:\nw = tf.Variable(tf.random_normal([2,1], stddev = 1, seed = 1))\ny = tf.matmul(x,w)\n\nloss = tf.reduce_mean(tf.sqaure(y_ - y) + tf.contrib.layers.12_regularizer(lambdai)(w))\n\n'
#tf.contrib.layers.l1_regularizer可以计算L1正则项的值。
weights = tf.constant([[1.0,2.0],[-3.0,4.0]])
with tf.Session() as sess:
    print(sess.run(tf.contrib.layers.l1_regularizer(.5)(weights)))
    print(sess.run(tf.contrib.layers.l2_regularizer(.5)(weights)))
5.0
7.5
#给出一个计算5层神经网络带L2正则化的损失函数的计算方法

#获取一层神经网络边上的权重,并将这个权重的L2正则化损失加入到名称为‘losses’的集合
def get_weight(shape, lambdai):
    #生成一个变量
    var = tf.Variable(tf.random_normal(shape), dtype = tf.float32)
    # add_to_collection 函数将这个新生成的变量的L2正则化损失项加入集合。
    # 这个函数的第一个参数‘losses’是集合的名称,第二个参数是要加入这个集合的内容。
    tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambdai)(var))
    return var

x = tf.placeholder(tf.float32, shape = (None,2))
y_ = tf.placeholder(tf.float32, shape = (None, 1))

#定义了每一层神经网络的个数
layer_dimension = [2,10,10,10,1]

#定义神经网络的层数
n_layers = len(layer_dimension)

# 这个变量维护前向传播时的最深层的节点,开始的时候是输入层
cur_layer = x
#当前层的节点个数
in_dimension = layer_dimension[0]

#通过一个循环,生成5层全连接的神经网络结构
for i in range(1, n_layers):
    # layer_dimension[i]为下一层的节点个数
    out_dimension = layer_dimension[i]
    
    # 生成层中权重的变量,并将这个变量的L2正则化损失加入到计算图的上的集合。
    weight = get_weight([in_dimension, out_dimension], 0.001)
    bias = tf.Variable(tf.constant(0.1, shape= [out_dimension]))
    #使用ReLU激活函数
    cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
    # 进入下一层之前将下一层的节点个数更新为当前层节点的个数
    in_dimension = layer_dimension[i]
    
# 在定义神经网络前向传播的同时已经将所有的L2正则化加入了图上的集合
# 这里只需要计算刻画模型在训练数据上表现的损失函数
mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer))

#将均方误差损失函数加入到损失集合中
tf.add_to_collection('losses', mse_loss)

#get_collection返回一个列表,这个列表就是集合中的所有元素。
#在这个样例中,这些元素来自损失函数的不同部分。将他们加起来就是最终的损失函数

loss = tf.add_n(tf.get_collection('losses'))

train_step = tf.train.AdamOptimizer(0.001).minimize(loss)
#通过随机数生成一个模拟数据集
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:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    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))
[[-0.81131822]
 [ 1.48459876]]

3.滑动平均模型

在TensorFlow中提供了tf.train.ExponentialMovingAverage来实现滑动平均模型。
ExponentialMovingAverage会对每一个变量维护一个影子变量 shadow_variable.
s h a d o w _ v a r i a b l e = d e c a y × s h a d o w _ v a r i a b l e + ( 1 − d e c a y ) × v a r i a b l e shadow\_variable = decay \times shadow\_variable + (1 - decay) \times variable shadow_variable=decay×shadow_variable+(1decay)×variable
shadow_variable 是影子变量;variable 是待更新的变量;decay 是衰减率.
ExponentialMovingAverage提供了num_updates参数来动态设置decay的大小。
d e c a y = m i n { d e c a y , 1 + n u m u p d a t e s 10 + n u m u p d a t e s } decay = min\{decay, \frac{1 + num_updates}{10 + num_updates}\} decay=min{decay,10+numupdates1+numupdates}

# 通过以下代码解释ExponentialMovingAverage是如何被使用的
# 定义一个变量来计算滑动平均,这个变量的初始值为0.
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_averages_op = ema.apply([v1])

with tf.Session() as sess:
    #初始化变量
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    
    #通过ema.average(v1)获取滑动平均之后的变量的取值。在初始化后变量v的值和滑动平均都为0.
    print(sess.run([v1, ema.average(v1)]))
    
    #更新变量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_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    #更新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.9999} = 0.99
    #v1的滑动平均会被更新为:0.99 * 0.45 + 0.01 * 10 = 4.555
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    
    #再次更新滑动平均,得到的新滑动平均为: 0.99 * 4.555 + 0.01 * 10 = 4.60945
    sess.run(maintain_averages_op)
    print(sess.run([v1, ema.average(v1)]))
    

[0.0, 0.0]
[5.0, 4.5]
[10.0, 4.5549998]
[10.0, 4.6094499]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值