【TensorFlow实战】6.损失函数(2)

TensorFlow不仅支持经典的损失函数,还可以任意的自定义损失函数。下面将介绍如何通过自定义损失函数的方法,使得神经网络优化的结果更接近实际问题的需求。在下面的介绍中将以预测商品销量问题为例。

在预测商品销量中,如果预测多了(预测值比实际销量大),商家损失的是生产商品的成本;而如果预测少了(预测值比真实小销量小),损失的是商品的利润。因为一般商品的成本和利润不会严格相等。例如一个商品的成本是1元,但是利润是10元,那么少预测一个就亏损10元;而多预测一个才亏损1元。如果神经网络模型最小化的是均方误差,那么很有可能此模型就无法最大化预期的利润。为了最大化预期利润,需要将损失函数和利润直接联系起来。注意损失函数定义的是损失,所以要将利润最大化,定义的损失函数应该刻画成本或代价。下面的公式给出了一个当预测多于真实值和预测小于真实值时有不同损失系数的损失函数:

和均方误差公式类似,yi为一个batch中第i个数据的正确答案,yi`为神经网络得到的预测值,a和b是常量。比如在上面介绍的销量预测问题中,a就是等于10(预测值小于真实值),而b等于1(预测值大于真实值)。通过对这个自定义损失函数的优化,模型提供的预测值更有可能最大化收益。在TensorFlow中,可以通过以下代码实现这个损失函数。

loss = tf.reduce_sum( tf.select(tf.greater(v1,v2), (v1-v2)*a, (v2-v)*b) )

上面的代码用到了tf.greater和tf.select来实现选择操作。tf.greater的输入是两个张量,次函数会比较这两个输入张量中每一个元素的大小,并返回结果。当tf.greater的输入张量维度不一样时,TensorFlow会进行类似NumPy广播操作(broadcasting)的处理。tf.select函数有三个参数。第一个为选择条件根据,当选择条件为True时,tf.select函数会选择第二个参数中的值,否则使用第三个参数中的值。注意tf.select函数判断和选择都是在元素级别进行,一下代码展示了tf.select函数和tf.greater函数的用法。

import tensorflow as tf
v1 = tf.constant([1.0, 2.0, 3.0, 4.0])
v2 = tf.constant([4.0, 3.0, 2.0, 1.0])

sess = tf.InteractiveSession()
print (tf.greater(v1, v2).eval())
#输出[False False True True]

print(tf.select(tf.greater(v1,v2), v1, v2).eval())
#输出[4. 3. 3. 4.]

sess.close()

在定义了损失函数之后,下面将通过一个简单的神经网络程序来讲解损失函数对模型训练结果的影响。在下面这个程序中,实现了一个拥有两个输入节点、一个输出节点,没有隐藏层的神经网络。程序中用到了上面定义的损失函数。

import tensorflow as tf
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.select(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)
#设置回归的正确值为两个输入的和加上一个随机量。之所以要加上一个随机量是为了加入不可预测的噪音,
#否则不同损失函数的意义就不大了,因为不同损失函数都会在能完全预测正确的时候最低。
#一般来说噪音为一个均值为0的最小量,所以这里的噪音设置为-0.05~0.05的随机数
Y = [[x1 + x2 + rdm.rand()/10.0 - 0.05] for (x1, x2) in X]

#训练网络
with tf.Session() as sess:
    init_op = tf.initialize_all_variables()
    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))

运行上面的代码会得到w1的值为[1.01934695, 1.04280889],也就是说得到的预测函数是1.02x1+1.04x2,这要比x1+x2大。因为在损失函数中指定预测少了的损失更大(loss_less>loss_more),所以模型倾向于多预测一些。如果将loss_less的值调整为1,loss_more的值调整为10,那么w1的值会是[0.95525805, 0.9813394]。也就是说,在这样的损失值下,模型更倾向于预测少一点。而如果使用均方误差作为损失函数,那么w1会是[0.9743756, 1.0243336]。使用这个损失函数会尽量让预测值离标准答案更近。通过这个样例可以感受到,对于相同的神经网络,不同的损失函数对训练的得到的模型产生重要影响。

猜你喜欢

转载自blog.csdn.net/poulang5786/article/details/81333378
今日推荐