TensorFlow学习(三)——神经网络进阶DNN
一、神经网络的进阶概念
激活函数
在线性模型中,模型的输出是输入的加权和,例如通过下面这个公式计算的模型
该公式称为线性变换,该模型称为线性模型。只通过线性变换,任意层的全连接神经网络与单层神经网络的表达能力没有太大区别。而深度学习主要是强调非线性。比如碰到如下问题,线性变换模型不能很好拟合。
当引入激活函数后,这个问题就能被很好解决,因为激活函数是非线性的。
常用的激活函数有relu、sigmod、tanh,它们在TensorFlow中分别为tf.nn.relu、tf.sigmoid、tf.tanh。
激活函数的具体介绍可以看这篇博客
https://blog.csdn.net/kangyi411/article/details/78969642
偏置项
在神经网络中,偏置项一般置为1,是一个常量。偏置项具体介绍可以参考这篇博客
https://blog.csdn.net/Uwr44UOuQcNsUQb60zk2/article/details/81074408
损失函数
损失函数简单讲就是神经网络中优化算法的优化目标,通过最小化损失函数,然后神经网络能够学习到权重,从而实现我们所见的预测、分类等功能。
经典损失函数
交叉熵(cross entropy)损失函数——分类问题
x表示所属类别
给定两个概率分布p和q,通过q定义p的交叉熵:H(p, q) = –
∑
x
p
(
x
)
l
o
g
q
(
x
)
\sum_{x}p(x)log\ q(x)
∑xp(x)log q(x)
交叉熵刻画了两个概率分布之间的距离,概率分布刻画了不同事件发生的概率
当事件总数有限时,概率分布函数p(X=x)满足
∀
x
,
p
(
X
=
x
)
∈
[
0
,
1
]
且
∑
x
p
(
X
=
x
)
=
1
\forall x, \quad p(X=x) \in [0, 1]且\sum_{x}p(X=x) = 1
∀x,p(X=x)∈[0,1]且∑xp(X=x)=1
将前向传播的结果变为概率分布可以适用softmax回归,在TensorFlow中,softmax回归只是额外的一层处理层,加入了softmax层的神经网络如图。一般要预测多少类,softmax就输出多少个。
若神经网络输出为y1,y2,…,yn,则经过softmax回归处理后的输出为:
s
o
f
t
m
a
x
(
y
i
)
=
y
i
′
=
e
y
i
(
∑
j
=
1
n
e
y
i
)
softmax(y_i) = y'_i = \frac{e^{y_i}} {(\sum_{j=1}^{n}\ e^{y_i})}
softmax(yi)=yi′=(∑j=1n eyi)eyi
这样的话就可以将结果转换为一个概率分布,从而使用交叉熵损失函数计算预测的概率分布和真实概率分布之间的距离。
当使用交叉熵作为神经网络的损失函数时,p代表正确答案,q代表预测值
示例展示
假设一个三分类问题,某个样例的正确答案是(1,0,0)。某模型经过Softmax回归之后的预测答案是(0.5,0.4,0.1), 那么这个预测和正确答案之间的交叉熵为:
H((1, 0, 0), (0.5, 0.4, 0.1))= -(1 x log0.5+ 0 x log0.4+ 0 x log0.1) ≈ 0.3
如果另外一个模型的预测是(0.8,0.1,0.1),那么这个预测值和真实值之间的交叉熵是:
H((1, 0, 0), (0.8, 0.1, 0.1))= -(1 x log0.8 + 0 x log0.1 + 0 x log0.1) ≈ 0.1
代码表示
corss_entropy = -tf.reduce_mean(y_real * tf.log(tf.clip_by_value(y_pred, 1e-10, 1.0))
代码说明
其中y_real代表实际值,也就是上面示例中的(1, 0, 0)
y_pred表示预测值,也就是上面示例中的(0.5, 0.4, 0.1)和(0.8, 0.1, 0.1)
tf.clip_by_value函数可以将张量限制在一定范围内,从而避免运算错误
例如
v = tf.constant([1., 2., 3.], [4., 5., 6.]])
print(tf.clip_by_value(v, 2.0, 5.0).eval())
输出如下
将所有小于2.0的替换为2.0,将所有大于5的替换为5
*表示矩阵点乘,tf.matmul表示矩阵乘法
在TensorFlow中可以直接使用softmax回归后的交叉熵损失函数
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y_pred, y_real)
均方误差——回归问题(数值预测等)
M
S
E
(
m
e
a
n
s
q
u
a
r
e
d
e
r
r
o
r
)
=
∑
i
=
1
n
(
y
i
−
y
i
′
)
2
n
MSE(mean squared error) = \frac{\sum_{i=1}^{n}\ (y_i - y'_i)^2} n
MSE(meansquarederror)=n∑i=1n (yi−yi′)2
其中yi表示batch中第i个数据的正确答案,y’i为神经网络给出的预测值。
代码展示
tf.reduce_mean(tf.square(y_real - y_pred))
代码说明
y_real表示实际值
y_pred表示输出值
"-"表示对于的元素相减,类似于点乘
自定义损失函数
示例展示
例如损失函数如下:
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_{i=1}^n\ f(y_i, y'_i),f(x, y)=\begin{cases} a(x - y) & x > y \\ b(y - x) & x≤ y \end{cases}
Loss(y,y′)=i=1∑n f(yi,yi′),f(x,y)={a(x−y)b(y−x)x>yx≤y
其中yi为第i个数据的正确答案,y’i为神经网络得到的预测值,a和b是常量
代码展示
# windows下tf没有select函数,使用where函数代替
# method "select" don't exist in windows, you can replace it with "where()"
loss = tf.reduce_sum(tf.select(tf.greater(x, y), (x - y) * a, (y - x) * b))
代码说明
上述代码通过tf.select和tf.greater实现选择操作
tf.greater(judgement, operation1, operation2)比较两个元素大小,当judgement是True时,执行operation1,当judgement是False时,执行operation2
学习率设置
指数衰减法
该方法在TensorFlow中可以通过调用tf.train.exponential_decay实现,大概过程如下
d
e
c
a
y
e
d
_
l
e
a
r
n
i
n
g
_
r
a
t
e
=
l
e
a
r
n
i
n
g
_
r
a
t
e
∗
d
e
c
a
y
_
r
a
t
e
g
l
o
b
a
l
_
s
t
e
p
/
d
e
c
a
y
_
s
t
e
p
decayed\_learning\_rate = learning\_rate * decay\_rate^{global\_step / decay\_step}
decayed_learning_rate=learning_rate∗decay_rateglobal_step/decay_step
其中decaed_learining_rate是每轮优化时使用的学习率,learning_rate为初始学习率,decay_rate为衰减系数,decay_steps为衰减速度。
在TensorFlow中可以通过设置参数staircase来选择不同衰减方式。当staircase为True时,是阶梯函数,如下图黑色阶梯函数;当staircase为False时,是连续函数,如下图灰色连续曲线
staircase默认为False
代码展示
global_step = tf.Variable(0)
# 通过exponential_decay函数生成学习率
learning_rate = tf.train.exponential_decay(0.1, global_step, 100, 0.96, staircase=True)
# 使用指数衰减更新学习率。在minimize中传入global_step传入参数将自动更新
learning_step = tf.train.GradientDescentOptimizer(learning_reate).minimize(cost_function, global_step=global_step)
代码说明
上述代码中设定初始学习率为0.1, 指定staircase为True,每训练100轮后,学习率乘以0.96。
二、使用自定义损失函数实现的神经网络
import tensorflow as tf
from numpy.random import RandomState
# load dataset
batch_size = 8
dataset_size = 128
rnd = RandomState(1)
X = rnd.rand(dataset_size, 2)
Y = [[x1 + x2 + rnd.rand() / 10.0 - 0.05] for (x1, x2) in X]
x = tf.placeholder(tf.float32, shape=(None, 2), name="x_input")
y_real = tf.placeholder(tf.float32, shape=(None, 1), name="y_input")
# initialize weights
w1 = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1, name="weight1"))
# forward propagation algorithm
y_pred = tf.matmul(x, w1)
# cost function
a = 10
b = 1
cost_function = tf.reduce_sum(tf.where(tf.greater(y_real, y_pred), (y_real - y_pred) * a, (y_pred - y_real) * b))
training_step = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost_function)
with tf.Session() as sess:
tf.global_variables_initializer().run()
print("before training, w1:\n{}".format(w1.eval()))
steps = 5000
for i in range(steps):
start = (i * batch_size) % dataset_size
end = min(start + batch_size, dataset_size)
sess.run(training_step, feed_dict={x: X[start: end], y_real: Y[start: end]})
if i % 1000 == 0:
total_loss = sess.run(cost_function, feed_dict={x: X, y_real: Y})
print("after %d steps, total loss is %f" % (i, total_loss))
print("after training, w1:\n{}".format(w1.eval()))