如果不知道导数并且需要一批输出来计算成本,如何训练模型?

时间:2018-04-17 23:28:18

标签: python tensorflow

如果无法在每次输入中评估成本,我想知道如何在tensorflow中训练模型。例如。如果我的目标函数测试某个条件是否满足 half 的时间(任何与此相关的偏差都会受到惩罚)。

以前我会编写类似下面的代码来定义我的成本函数和反向传播学习器:

# Backward propagation
loss = tensorflow.losses.mean_squared_error(labels=y, predictions=yhat)
cost = tensorflow.reduce_mean(loss, name='cost')
updates = tensorflow.train.GradientDescentOptimizer(0.01).minimize(cost)

yhat是一个张量,产生一些估计输出y,而cost只是 true 预测值。

但是,如果我的目标函数只能在所有输入(或某些数据)之后才能计算出来,并且导数未知?

这方面的一个例子可能是训练神经网络在50%的时间内在一些其他函数内部(例如,在x^2 + y^2 = r^2的圆圈内r)找到一组笛卡尔坐标。正确和错误答案的空间不是有限的,虽然无法计算成本相对于输出的导数(使反向传播不可能),但损失函数本身的计算相对简单。

def loss(yhat_all, inputs):
  for prediction, input in zip(yhat_all, inputs):
    correct += is_inside(prediction, input)

  return -abs(correct / len(inputs) - 0.5)

显然loss在这种情况下不是一个有效的张量,我只是用原生的python代码写出来来说明问题。鉴于上面的例子,在这种情况下如何定义updates张量?显然我不能使用梯度下降,所以我需要使用不同的优化器,但我也不知道如何计算损失,因为我不能再使用正常的losses张量孤立地运行每个单独的输出。

1 个答案:

答案 0 :(得分:2)

首先,您可以做的是通过整批而不是单个输入定义自己的成本函数。坚持使用您的圈子示例,您可以:

inside_bool = ( tf.square( X_pred ) + tf.square( Y_pred ) ) < tf.square( r )
inside_float = tf.cast( inside_bool, tf.float32 )
proportion_inside = tf.reduce_mean( inside_float )
loss = -tf.abs( proportion_inside - 0.5 )

另一个问题是这种网络的输入是什么。我建议你从一个随机张量开始。 (基本上,建立一个生成网络。)

如果您的损失函数不可导出,则很难训练。所以我建议用可导出的近似值替换不可导出的部分。最重要的是,内外布尔可以是距离周边的距离的大根(保持符号)。采用大根将其接近一。 (提升到0将是基本上的符号。)您还可以添加一个喜欢一个值和一个值的正则化器。 (这会破坏坐标的分布,但是,如果这是一个因素。)

tf.abs()不是一个大问题,基本上是L1正规化。 所有这些,一个想法可能是(未经测试的代码):

dist_from_perimeter = ( tf.square( X_pred ) + tf.square( Y_pred ) ) - tf.square( r )
dist_loss = tf.sign( dist_from_perimeter ) * tf.pow( tf.abs( dist_from_perimeter ), 0.2 ) # 0.2 for 5th root
inside = tf.reduce_mean( dist_loss ) # 0-based now!
loss = -tf.abs( inside )

这会强制周边的所有点,但是渐变在周长周围会变得非常大,所以它不太可能留在那里。它们将在内外振荡,但一旦比例稳定下来,它们就不会移动太多。 (或者我认为...... :))

如果你有一个圆形以外的东西,那么你必须提出一个相当容易计算的距离度量,它会在X和Y坐标上产生接近相等的压力。

希望这一切都有所帮助!

为此编写了工作代码,尽管没有调查生成结果的内部结构:

import tensorflow as tf

r = 1.0

rnd = tf.random_uniform( shape = ( 100, 50 ), dtype = tf.float32, minval = 0.0, maxval = 1.0 )

l1 = tf.layers.dense( rnd, 50, activation = tf.nn.relu, kernel_regularizer = tf.nn.l2_loss )
l2 = tf.layers.dense( l1, 50, activation = tf.nn.relu, kernel_regularizer = tf.nn.l2_loss )
l3 = tf.layers.dense( l2, 50, activation = None, kernel_regularizer = tf.nn.l2_loss )
X_pred = tf.layers.dense( l3, 1, activation = None, kernel_regularizer = tf.nn.l2_loss )
Y_pred = tf.layers.dense( l3, 1, activation = None, kernel_regularizer = tf.nn.l2_loss )

dist_from_perimeter = ( tf.square( X_pred ) + tf.square( Y_pred ) ) - tf.square( r )
dist_loss = tf.sign( dist_from_perimeter ) * tf.pow( tf.abs( dist_from_perimeter ), 0.5 ) # 0.5 for square root
inside = tf.reduce_mean( dist_loss ) # 0-based now!
loss = tf.abs( inside )

inside_binary = tf.sign(tf.sign( dist_from_perimeter ) + 1 )
prop = tf.reduce_mean( inside_binary )

global_step = tf.Variable(0, name='global_step', trainable=False)
updates = tf.train.GradientDescentOptimizer( 0.0001 ).minimize( loss )

with tf.Session() as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    for step in xrange( 100000 ):
        _, loss_value, prop_val = sess.run( [ updates, loss, prop ] )
        if 0 == step % 2000:
            print( "Step {}, loss {:.6f}, proportion inside: {:.4f}". format( step, loss_value, prop_val ) )

输出:

  

步骤0,损失0.963431,内部比例:0.0000
  步骤2000,损失0.012302,内部比例:0.4900
  步骤4000,损失0.044224,内部比例:0.5300
  步骤6000,损失0.055603,内部比例:0.5400
  步骤8000,损失0.001739,内部比例:0.4100
  步骤10000,损失0.136604,比例内:0.5900
  步骤12000,损失0.028738,内部比例:0.4600
  步骤14000,损失0.089664,内部比例:0.4100
  步骤16000,损失0.035139,内部比例:0.4900
  步骤18000,损失0.021432,内部比例:0.5100
  步骤20000,损失0.008821,内部比例:0.4600
  步骤22000,损失0.079573,内部比例:0.5500
  步骤24000,损失0.145942,内部比例:0.3700
  步骤26000,损失0.009984,内部比例:0.4700
  步骤28000,损失0.010401,内部比例:0.4700
  步骤30000,损失0.077145,内部比例:0.4000
  步骤32000,损失0.029588,内部比例:0.5300
  步骤34000,损失0.032815,内部比例:0.5100
  步骤36000,损失0.081417,内部比例:0.4000
  步骤38000,损失0.079384,内部比例:0.3900
  步骤40000,损失0.040977,内部比例:0.5500
  步骤42000,损失0.095768,内部比例:0.5900
  步骤44000,损失0.012109,内部比例:0.5300
  步骤46000,损失0.064089,内部比例:0.4200
  步骤48000,损失0.001401,内部比例:0.4700
  步骤50000,损失0.024378,内部比例:0.5400
  步骤52000,损失0.037057,内部比例:0.4900
  步骤54000,损失0.004553,内部比例:0.4800
  步骤56000,损失0.097677,内部比例:0.4000
  步骤58000,损失0.060175,内部比例:0.5300
  步骤60000,损失0.008686,内部比例:0.4800
  步骤62000,损失0.077828,内部比例:0.3600
  步骤64000,损失0.000750,内部比例:0.4600
  步骤66000,损失0.071392,内部比例:0.5700
  步骤68000,损失0.066447,内部比例:0.5600
  步骤70000,损失0.057511,内部比例:0.5600
  步骤72000,损失0.008800,内部比例:0.5400
  步骤74000,损失0.000322,内部比例:0.5200
  步骤76000,损失0.002286,内部比例:0.4700
  步骤78000,损失0.008778,内部比例:0.4900
  步骤80000,损失0.044092,内部比例:0.4500
  步骤82000,损失0.018876,内部比例:0.4600
  步骤84000,损失0.108120,内部比例:0.3500
  步骤86000,损失0.054647,内部比例:0.5600
  步骤88000,损失0.024990,内部比例:0.4600
  步骤90000,损失0.030924,内部比例:0.4700
  步骤92000,损失0.021789,内部比例:0.5100
  步骤94000,损失0.066370,内部比例:0.5600
  步骤96000,损失0.057060,内部比例:0.4100
  步骤98000,损失0.030641,内部比例:0.5200