入门
1.TensorFlow入门
1.1 计算模型——计算图
计算图:每一个计算为计算图的一个节点,边描述计算之间的依赖关系
TensorFlow程序可以分为两个阶段。在第一阶段需要定义图中所有的计算,第二阶段为执行计算。
tensorFlow自动将定义的计算转化为计算图上的节点,系统会维护一个默认的计算图。
不同计算图上的张量和运算都不会共享。
1.2 数据模型——张量
Tensor:张量。在tensorFlow程序中,所有数据都通过张量的形式来表示。
从功能角度,张量可以被简单理解为多维数组。
TensorFlow中的张量没有保存数字,保存的是如何得到这些数字的计算过程。
# 张量主要保存了三个属性,name,shape,type
# add:0 表示计算节点“add”输出的第一个结果,shape=(2,)表面张量为一个一维数组,数组长度为2,type表示数组类型
'''
输出
Tensor("add:0",shape=(2,),dtype=float32)
'''
1.3 运行模型——会话
使用会话session执行定义好的运算。会话拥有并管理tensorFlow运行时的所有资源,计算完成之后需要关闭会话来帮助系统回收资源,否则可能会出现资源泄露的问题。
1.3.1 会话模式1
# 创建会话
sess = tf.Session()
# 使用创建的会话得到运算结果
sess.run(result)
#关闭会话。释放资源;当程序因为异常退出是,关闭会话的函数可能就不会被执行而导致资源泄露
sess.close()
1.3.2 会话模式2
# 通过python上下文管理器管理会话
with tf.Session() as sess:
sess.run(result)
# 不需要在调用Session.close关闭会话,上下文退出是会话关闭和资源释放自动完成
1.3.3 默认会话
sess = tf.Session()
with sess.as_default():
print(result.eval())
1.4 tensorflow实现神经网络
#
"""
Created on Tue Oct 30 09:12:10 2018
@author: cc
"""
import tensorflow as tf
from numpy.random import RandomState
# 定义训练数据的batch
batch_size =8
# 定义神经网络的参数,方差为1的随机数矩阵,随机种子为1
w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))
x=tf.placeholder(tf.float32,shape=(None,2),name="x-inpt")
y_=tf.placeholder(tf.float32,shape=(None,1),name="Y-inpt")
# 定义神经网络前向传播的过程,a为隐藏层计算所得
a =tf.matmul(x,w1)
y =tf.matmul(a,w2)
# 定义损失函数
cross_entropy = -tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
train_step =tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
# 通过随机数生成一个模拟数据集
rdm =RandomState(1)
dataset_size =1024
X = rdm.rand(dataset_size,2)
# 定义规则给出样本的标签,用0表示负样本(x1+x2>1),用1表示正样本(x1+x2<1)
Y =[[int(x1+x2<1)] for (x1,x2) in X]
# 创建一个会话运行Tensorflow程序
with tf.Session() as sess:
# 初始化所有的参数
init_op = tf.initialize_all_variables()
sess.run(init_op)
print(sess.run(w1))
print(sess.run(w2))
# 定义训练的轮数
STEPS = 8000
for i in range(STEPS):
# 每次选择batch_size个样本进行训练
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]})
if i%1000 ==0:
# 计算所有数据的交叉熵并输出
total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y})
print("After %d traning steps,cross entropy on all data is %g" %(i,total_cross_entropy))
# 训练好的参数
print(sess.run(w1))
print(sess.run(w2))
2.神经网络
2.1 激活函数
2.2 损失函数loss function
用于判断输出向量和期望的向量的接近程度
2.2.1 分类问题
交叉熵:用来评估分类效果的意义,刻画的两个概率分布之间的聚类
H
(
p
,
q
)
=
−
∑
p
(
x
)
log
q
(
x
)
H(p,q)=-\sum p(x)\log q(x)
H(p,q)=−∑p(x)logq(x)
Softmax回归,将神经网络前向传播得到的结果也变成概率分布
假设原始神经网络输出为 y1,y2,……,yn ,经过Softmax回归处理之后的输出为:
s
o
f
t
m
a
x
(
y
)
i
=
y
i
′
=
e
i
y
∑
j
=
1
n
e
y
j
softmax(y)_i =y_i' =\frac {e^y_i}{\sum_{j=1}^{n}e^{y_j}}
softmax(y)i=yi′=∑j=1neyjeiy
在1.1.4的例子中已经通过tensorflow实现交叉熵:
# 其中y——表示正确结果,y表示预测结果
cross_entropy = tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,10)))
- tf.clip_by_value函数可以将张量中的数值控制在一个范围内,避免一些运算错误
- tf.log用于对张量中的所有元素依次进行对数运算
- * 表示矩阵中的元素直接相乘,矩阵乘法用tf.matmul
- 计算结果为n*m二维矩阵,n为一轮中样例数量,m为分类的类别数量。根据交叉熵的公式,应该将每行的m个结果相加,得到所有样例的交叉熵,然后对n行取平均得到一个batch的平均交叉熵。 tf.reduce_mean 就是这个作用,相当于 ∑ i = 1 n n \frac{\sum_{i=1}^{n}}{n} n∑i=1n 运算
- tf.nn.softmax_cross_entropy_with_logits(y,y_)可以计算softmax回归之后的交叉熵
2.2.2 回归问题
回归问题是解决对具体数值的预测。常用的损失函数式均方误差MSE
M
S
E
(
y
,
y
′
)
=
∑
i
=
1
n
(
y
i
−
y
i
′
)
2
n
MSE(y,y')=\frac{\sum_{i=1}^{n}(y_i-y_i')^2}{n}
MSE(y,y′)=n∑i=1n(yi−yi′)2
其中y_i表示一个batch中第i个数据的正确答案,
y
i
′
y_i'
yi′为神经网络的预测值
# tensorflow实现均方误差损失函数
mse = tf.reduce_mean(tf.square(y_-y))
除了上面的两种常见的还可以自定义损失函数
2.3 神经网络优化算法
梯度下降算法
用θ表示深度学习中的参数,J(θ)表示损失函数的取值,其梯度为
α
α
θ
J
(
θ
)
\frac{\alpha}{\alpha \theta}J(\theta)
αθαJ(θ)
学习率η:定义每次参数更新的幅度
θ
n
+
1
=
θ
n
−
θ
α
α
θ
n
J
(
θ
n
)
\theta_{n+1} =\theta_n - \theta \frac {\alpha}{\alpha\theta_n}J(\theta_n)
θn+1=θn−θαθnαJ(θn)
梯度下降算法通过梯度和学习率更新参数x的取值,使用梯度下降算法对参数的更新公示为
X
n
+
1
=
X
n
−
η
Δ
n
X_{n+1}=X_n - \eta\Delta n
Xn+1=Xn−ηΔn
缺点:
1.不能保证达到全局最优解
2.计算时间太长。因为J(θ)是在所有训练数据上的损失和。
为了加速训练过程,可以采用 随机梯度下降的算法。每一次训练的过程中,随机优化某一天训练数据上的损失函数。但是这样得到的神经网络甚至无法达到局部最优。实际中一般采用这两个算法的折中——每次计算一小部分训练数据的损失函数。这部分数据被称为一个batch,通过矩阵运算。每次在batch上优化神经网络的参数并不会比单个数据慢太多。另一方面可以大大减小收敛所需的迭代次数。
反向传播算法back pagation
学习率设置
设置学习率
η
\eta
η 控制参数更新的速度。学习率过大,可能导致参数在极优值两侧来回移动;学习率过小,会降低优化速度,需要迭代更多轮才能达到理想的优化效果。
tensorFlow提供一种灵活的学习率设置方法——指数衰减法tf.train.exponential_decay函数实现指数衰减学习率。
global_step = tf.Variable(0)
# exponential_decay函数的作用:decay_learning_rate = learing_rate*decay_raye^(global_step/decay_steps)
# learing_rate:初始学习率,decay_rate:衰减系数,decay_steps:衰减速度
learning_rate=tf.train.exponential_decay(0.1,global_step,100,0.96,staircase=True)
# 更新学习率
learning_step = tf,train.GradientDescentOptimize(learning_rate).minimize(...my loss...,global_step = global_step)
过拟合问题
过度拟合了训练数据中的噪声而忽视了问题的整体规律。
为了避免过拟合问题,常用的方法是正则化。正则化的思想是在损失函数中加入刻画模型复杂程序的指标。
优化时不直接优化
J
(
θ
)
J(\theta)
J(θ),而是优化
J
(
θ
)
+
λ
R
(
ω
)
J(\theta)+\lambda R(\omega)
J(θ)+λR(ω),其中
R
(
ω
)
R(\omega)
R(ω)刻画的是模型的复杂程度,而
λ
\lambda
λ表示的模型复杂损失在总损失中的比例。一般来说模型的复杂度只由权重
ω
\omega
ω决定
常见的刻画模型复杂度的函数
R
(
ω
)
R(\omega)
R(ω)有两种,一种是L1正则化,一种是L2正则化。
L
1
正
则
化
:
R
(
ω
)
=
∥
ω
∥
1
=
∑
i
∣
ω
i
∣
L1正则化:R(\omega)=\parallel\omega\parallel_1=\sum_i|\omega_i|
L1正则化:R(ω)=∥ω∥1=i∑∣ωi∣
L
2
正
则
化
:
R
(
ω
)
=
∥
ω
∥
2
2
=
∑
i
∣
ω
i
2
∣
L2正则化:R(\omega)=\parallel\omega\parallel_2^2=\sum_i|\omega_i^2|
L2正则化:R(ω)=∥ω∥22=i∑∣ωi2∣
正则化的思想是希望通过限制权重的大小,使模型不能任意拟合训练数据的随机噪声。L1正则化会让参数变得更稀疏;L1正则化不可导,L2正则化可导。在实践中,可以将L1正则化和L2正则化同时使用:
R
(
ω
)
=
α
∥
ω
∥
1
+
(
1
−
α
)
∥
ω
∥
2
2
=
∑
i
α
∣
ω
i
∣
+
i
(
1
−
α
)
∣
ω
i
2
∣
R(\omega)=\alpha\|\omega\|_1+(1-\alpha)\parallel\omega\parallel_2^2=\sum_i{\alpha|\omega_i|+_i(1-\alpha)|\omega_i^2|}
R(ω)=α∥ω∥1+(1−α)∥ω∥22=i∑α∣ωi∣+i(1−α)∣ωi2∣
w=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
y=tf.matmual(x,w)
loss=tf.reduce_mean(tf.square(y_-y))+tf.contrib.layers.l2.regularize(lambda)(w)
滑动平均模型
每个变量维护一个影子变量shadow_variable,每次运行变量更新时,影子变量的值会更新,公式如下,其中decay为衰减率,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*shadow\_variable+(1-decay)*variable
shadow_variable=decay∗shadow_variable+(1−decay)∗variable
"""
Created on Wed Oct 31 11:00:25 2018
@author: cc
"""
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_averages_op = ema.apply([v1])
with tf.Session() as sess:
# 初始化所有变量
init_op = tf.initialize_all_variables()
sess.run(init_op)
print(sess.run([v1,ema.average(v1)]))
# 更新v1到5
sess.run(tf.assign(v1,5))
# 更新v1的滑动平均值
sess.run(maintain_averages_op)
print(sess.run([v1,ema.average(v1)]))