Tensorflow实例:实现经典损失函数
Tensorflow实现经典损失函数
神经网络模型的效果以及优化的目标是通过损失函数(Loss function)来定义的。如何判断一个输出向量和期望的向量有多接近呢?
交叉熵(cross entropy)
交叉熵刻画了两个概率分布之间的距离,它是分类问题中使用比较广的一种损失函数。给定两个概率分布p和q,通过q来表示p的交叉熵为:
H(p,q)=−∑p(x)logq(x)
H
(
p
,
q
)
=
−
∑
p
(
x
)
log
q
(
x
)
如何将神经网络前向传播得到的结果也变成概率分布呢?Softmax回归就是一个非常常用的方法。
Softmax回归本身可以作为一个学习算法来优化分类结果,但在Tensorflow中,Softmax回归的参数被去掉了,它只是一层额外的处理层,将神经网络的输出变成一个概率分布。假设原始的神经网络的输出为
y1,y2,...,yn
y
1
,
y
2
,
.
.
.
,
y
n
,那么经过Softmax回归处理之后的输出为:
softmax(y)i=y′i=eyi∑nj=1eyj
s
o
f
t
m
a
x
(
y
)
i
=
y
i
′
=
e
y
i
∑
j
=
1
n
e
y
j
Tensorflow实现交叉熵
cross_entropy = -tf.reduce_mean(
y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
)
其中y_代表正确结果,y代表预测结果,tf.clip_by_value函数可以将一个张量中的数值限制在一个范围之内,tf.log完成对张量中所有元素依次求对数,* 实现两个矩阵元素之间直接相乘(矩阵乘法需要使用tf.matmul函数来完成)。
因为交叉熵一般会与Softmax回归一起使用,所以Tensorflow对这两个功能进行了统一封装,并提供了tf.nn.softmax_cross_entropy_with_logits函数。比如可以直接通过下面的代码来实现使用了softmax回归之后的交叉熵损失函数:
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y, y_)
均方误差(MSE)
对于回归问题,最常用的损失函数是均方误差(MSE):
MSE(y,y′)=∑ni=1(yi−y′i)2n
M
S
E
(
y
,
y
′
)
=
∑
i
=
1
n
(
y
i
−
y
i
′
)
2
n
其中
yi
y
i
为一个batch中第i个数据的正确答案,而
y′
y
′
为神经网络给出的预测值。一下代码展示了如何通过Tensorflow实现均方误差损失函数:
mse = tf.reduce_mean(tf.square(y_ - y))
自定义损失函数
通过自定义损失函数的方法,我们可以使得神经网络优化的结果更加接近实际问题的需求。例如我们在预测商品销售问题中使用的损失函数:
Loss(y,y′)=∑i=1nf(yi,y′i), f(x,y)={a(x−y)b(y−x)x>yx≤y
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
在Tensorflow中可以通过以下代码实现这个损失函数:
loss = tf.reduce_sum(tf.select(tf.greater(v1, v2),
(v1 - v2) * a, (v2-v1) * b))
tf.greater的输入是两个张量,此函数会比较这两个张量中每一个元素的大小,并返回比较结果。
tf.select函数有三个参数,第一个为选择条件,当选择条件为True时,tf.select函数会选择第二个参数中的值,否则使用第三个参数中的值。
在定义了损失函数之后,下面一个简单的神经网络程序来讲解如何利用自定义损失函数:
loss_less = 1
loss_more = 10
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)
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) % 128
end = (i*batch_size) % 128 + batch_size
sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
if i % 1000 == 0:
print("After %d training step(s), w1 is: " % (i))
print sess.run(w1), "\n"
print "Final w1 is: \n", sess.run(w1)