tf学习笔记–BP算法(上)
BP算法又称“误差反向传播算法”,理解为:
监督学习,数据集分为数据(特征数据)与标签
1.建立一套正向计算模型,并给以相关参数初始化
2.将实际数据带入计算预测值,并与实际标签求差–损失值
3.优化器–如Adam优化器(梯度下降的一种)调整模型参数,使得损失值尽可能小。
4.损失值越小,则训练精度越高
内容:
1.梯度与梯度下降
2.一般激活函数
3.softmax算法
4.损失值函数
5.梯度下降–优化器
1.梯度与梯度下降
2.一般激活函数
常用的激活函数包括sigmoid函数,Tanh函数,ReLU函数以及Noise relus函数。其中Tanh用于特征相差明显的情况,细微分类则更多用softmax算法,ReLU–结果稀疏性更好。
3.softmax算法
用于多分类,且数据是互斥的,即一个数据有且仅有一个标签类别
softmax通过计算一个数据属于每个标签的概率,各个标签的概率和为1.
在此基础上,可以将概率最大的那个标签作为该数据的标签预测值用于计算。
函数表达式:
softmax(x) = (
e
x
1
∑
i
=
1
m
e
x
i
\frac{e^{x_1}}{\sum_{i=1}^{m} e^{x_i}}
∑i=1mexiex1,
e
x
2
∑
i
=
1
m
e
x
i
\frac{e^{x_2}}{\sum_{i=1}^{m} e^{x_i}}
∑i=1mexiex2, … ,
e
x
m
∑
i
=
1
m
e
x
i
\frac{e^{x_m}}{\sum_{i=1}^{m} e^{x_i}}
∑i=1mexiexm)
常用的tf代码:
tf.nn.softmax(logits, name=None) # 计算softmax
tf.nn.log_softmax(logits, name=None) # 对softmax结果取对数
4.损失值函数(将观察值–真实值,与预测值进行归一化处理效果更好)
即,预测值与实际值的差距,常用的为均值平方差(MSE)和交叉熵,两种损失值都是越小越则预测值越精确
均值平方差:
MSE =
∑
i
=
1
n
(
o
b
s
e
r
v
e
−
p
r
e
d
i
c
t
)
n
\frac{\sum_{i=1}^n(observe-predict)}{n}
n∑i=1n(observe−predict)
交叉熵:
c = -
1
n
∑
x
[
y
l
n
a
+
(
1
−
y
)
l
n
(
1
−
a
)
]
\frac{1}{n}\sum_x[ylna + (1-y)ln(1-a)]
n1∑x[ylna+(1−y)ln(1−a)]
其中y为真实值,a为预测值
个人认为不需要花太多时间研究损失值函数的各种不同程序实现方法,其本质就是求预测值与实际值的差距的一种方法,并在接下来的程序(反向传播)中以损失值的快速减小作为目标来调整正向模型当中的参数,使得最终的正向模型拥有较好的预测能力。
代码:
# -*- coding: utf-8 -*-
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
labels = [[0, 0, 1], [0, 1, 0]] # 真实标签,且进行过onehot编码
logits = [[2, 0.5, 6],
[0.1, 0, 3]] # 预测值,未分配标签
logits_scaled = tf.nn.softmax(logits)
logits_scaled2 = tf.nn.softmax(logits_scaled)
result1 = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits)
result2 = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits_scaled)
result3 = -tf.reduce_sum(labels * tf.log(logits_scaled), 1) # 针对第1维数据进行处理
with tf.Session() as sess:
print("scaled=", sess.run(logits_scaled))
print("scaled2=", sess.run(logits_scaled2)) # 经过第二次的softmax后,分布概率会有变化
print("rel1=", sess.run(result1), "\n") # 正确的方式
print("rel2=", sess.run(result2), "\n") # 如果将softmax变换完的值放进去会,就相当于算第二次softmax的loss,所以会出错
print("rel3=", sess.run(result3))
输出结果:
scaled= [[0.01791432 0.00399722 0.97808844]
[0.04980332 0.04506391 0.90513283]]
scaled2= [[0.21747023 0.21446465 0.56806517]
[0.2300214 0.22893383 0.5410447 ]]
rel1= [0.02215516 3.0996735 ]
rel2= [0.56551915 1.4743223 ]
rel3= [0.02215518 3.0996735 ]
对预测值进行一次softmax可以得到较为符合的结果,如scaled,各个值的分布情况接近[0,0,1],softmax得到的概率和为1
但是使用两次的话就会如scaled2一样出现不想要的结果
所以对于生成的预测结果,只能使用一次激活函数
对比rel1,rel2;因为函数
tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits)
本身带有softmax运算过程,所以rel2实际上是对预测结果进行了两次softmax处理,出现了类似scaled2一样不理想状态。
实际上函数
tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits)
的处理相当与对数据进行了一次softmax处理再加上一次rel1处理(对预测结果与实际结果的交叉熵–即:损失函数,取均值)
注意:在求交叉熵的时候最好对预测值与实际值进行归一化处理及onehot处理,这样得出的结果会更好一些
5.梯度下降–优化器
梯度下降的相关处理方式在第一点,这里只是强调,梯度下降就是对损失值函数求一阶导数,让损失函数沿着下降速率最快的方向减小。
常用的优化器有Adam优化器–在第1点有介绍。
tf.train.AdamOptimizer(learning_rate=0.001, beta1=0.9,beta2=0.999,epsilon=1e-08,use_locking=False,name=‘Adam’
其中learning_rate=0.001为学习率,可以使用固定值,但是也可以使用退化学习率:即在出席给以较大学习率加快模型训练速度,后期逐步降低学习率提高模型精度。
示例
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
global_step = tf.Variable(0, trainable=False)
initial_learning_rate = 0.1 #初始学习率
learning_rate = tf.train.exponential_decay(initial_learning_rate, global_step, decay_steps=10,decay_rate=0.9) # 退化学习率
opt = tf.train.GradientDescentOptimizer(learning_rate) # 优化器
add_global = global_step.assign_add(1) # global_step + 1
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(learning_rate))
for i in range(20):
g, rate = sess.run([add_global, learning_rate])
print(g,rate)
总结:BP算法:
1.建立正向模型
2.建立损失函数
3.优化器选择与设计
4.模型训练与评估