我正在尝试定义一个损失函数,但遇到了困难。也许有人可以帮助我。
我有 x_i
和 y_i
的 N 个数据点,我想在以下条件下拟合一条直线(为简单起见):
即找到 h 的最小值,使得对于所有点 |y_i - f(x_i)| < h。此条件不涉及 tf.losses.mean_squared_error 或 LAD(最小绝对偏差),其中我们最小化绝对值的总和 .
tf_x = tf.placeholder(tf.float32, x.shape) # input x
tf_y = tf.placeholder(tf.float32, y.shape) # input y
l1 = tf.layers.dense(tf_x, 1) # assume linear activation
output = tf.layers.dense(l1, 1) # output layer
h = ???
loss = ???
optimizer = tf.train.train.AdamOptimizer(learning_rate=0.1)
train_op = optimizer.minimize(loss)
所以sess.run()
应该返回满足上述条件的预测线和h值。
谢谢!
答案 0 :(得分:1)
听起来您使用的是 Tensorflow 1.x API,因为您提到使用 tf.placeholder
和 sess.run
,所以我提供了使用 Tensorflow 2.x 中的 Tensorflow 1.x API 的解决方案。如果您想在 Tensorflow 1.x 中运行,只需删除 compat.v1
。
tf_x = tf.compat.v1.placeholder(tf.float32, [None, 1], name='x') # input x
tf_y = tf.compat.v1.placeholder(tf.float32, [None, 1], name='y') # input y
h = tf.Variable(0.0, name='h')
l1 = tf.compat.v1.layers.dense(tf_x, 1, name='layer_1') # assume linear activation
output = tf.compat.v1.layers.dense(l1, 1, name='output') # output layer
loss = tf.reduce_max(tf.abs(tf_y - output)) + tf.abs((h - tf.reduce_max(tf.abs(tf_y - output))))
optimizer = tf.compat.v1.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)
init = tf.compat.v1.global_variables_initializer()
variables = tf.compat.v1.trainable_variables()
x = np.expand_dims(np.array([5.0, 5.0], dtype=np.float32), axis=-1)
y = np.expand_dims(np.array([2.0, 3.0], dtype=np.float32), axis=-1)
with tf.compat.v1.Session() as sess:
sess.run(init)
for step in range(1000):
_, val = sess.run([optimizer, loss],
feed_dict={tf_x: x, tf_y: y})
prediction = sess.run(output, feed_dict={'x:0': x})
print(prediction)
if step % 5 == 0:
print("step: {}, loss: {}".format(step, val))
print([{variable.name: sess.run(variable)} for variable in variables])
我包含了一些打印语句来帮助观察训练过程。由于问题陈述,损失函数看起来有点奇怪 - 我们正在学习近似 f(x)
的函数 y
和残差 h
。我使用虚拟输入来验证模型的功能——通过提供两个 5 和 2 和 3 的输出,模型被迫妥协并围绕预测 2.5 收敛。从最后的步骤:
step: 990, loss: 0.6000000238418579
[{'h:0': 0.5}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.6000004]
[2.6000004]]
[{'h:0': 0.6}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.6000004], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.70000005}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.6}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.5}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.6000004]
[2.6000004]]
step: 995, loss: 0.6999993324279785
[{'h:0': 0.6}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.6000004], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.70000005}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.6}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.4000003]
[2.4000003]]
[{'h:0': 0.5}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.4000003], dtype=float32)}]
[[2.6000004]
[2.6000004]]
[{'h:0': 0.6}, {'layer_1/kernel:0': array([[0.04334712]], dtype=float32)}, {'layer_1/bias:0': array([-0.2167356], dtype=float32)}, {'output/kernel:0': array([[-1.0096708e-09]], dtype=float32)}, {'output/bias:0': array([2.6000004], dtype=float32)}]
请注意,模型对输入和 h
的预测为 2.4-2.6,估计值在 0.5-0.7 之间,接近实际残差 (0.4-0.6)。行为可能会随着真实数据而改变——具体来说,对于真实数据,可能不会有具有不同输出的重复输入,这对模型来说是令人困惑的。为了健全性检查,我们可以使用相同的输出再次运行,但将输入更改为 7:
step: 995, loss: 1.9000002145767212
[{'h:0': 1.8000002}, {'layer_1/kernel:0': array([[0.60248166]], dtype=float32)}, {'layer_1/bias:0': array([0.21199825], dtype=float32)}, {'output/kernel:0': array([[1.0599916]], dtype=float32)}, {'output/bias:0': array([0.2], dtype=float32)}]
[[-0.767429 ]
[-1.0744007]]
[{'h:0': 1.9000002}, {'layer_1/kernel:0': array([[-0.88150656]], dtype=float32)}, {'layer_1/bias:0': array([-6.8724134e-08], dtype=float32)}, {'output/kernel:0': array([[0.1741176]], dtype=float32)}, {'output/bias:0': array([0.], dtype=float32)}]
[[3.543093]
[4.895095]]
[{'h:0': 2.0000002}, {'layer_1/kernel:0': array([[-0.6377419]], dtype=float32)}, {'layer_1/bias:0': array([0.03482345], dtype=float32)}, {'output/kernel:0': array([[-1.0599916]], dtype=float32)}, {'output/bias:0': array([0.2], dtype=float32)}]
[[3.543093]
[4.895095]]
[{'h:0': 1.9000002}, {'layer_1/kernel:0': array([[-0.6377419]], dtype=float32)}, {'layer_1/bias:0': array([0.03482345], dtype=float32)}, {'output/kernel:0': array([[-1.0599916]], dtype=float32)}, {'output/bias:0': array([0.2], dtype=float32)}]
[[3.543093]
[4.895095]]
[{'h:0': 1.8000002}, {'layer_1/kernel:0': array([[-0.6377419]], dtype=float32)}, {'layer_1/bias:0': array([0.03482345], dtype=float32)}, {'output/kernel:0': array([[-1.0599916]], dtype=float32)}, {'output/bias:0': array([0.2], dtype=float32)}]
它相当准确,因为残差约为 2.1 (7 - 4.89),h
输出为 1.8。
值得注意的是,此损失函数可能需要一些额外的部分 - 例如,边界 output
,因为它是线性的并且可以达到无穷大(模型可能会这样做以最小化损失 - tf.reduce_max(tf.abs(tf_y - output))
意味着 output
为无穷大导致负无穷大损失) - 但这应该是一个起点。
答案 1 :(得分:0)
不确定这是否有帮助,但是有一个 scipy.optimize 包,它提供了几种常用的优化算法。这是文档的链接。
https://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html
我最近一直在使用这个,效果非常好!
答案 2 :(得分:0)
您正在寻找每个数据点 y_true 和 y_pred 之间的增量的 L-inf 范数。 L-inf 范数仅从最大发散数据点计算损失。如果您可以对此进行优化,您会找到最小的 h。
当然,L-inf 是不可微的,因为它只是一种表达“max”的数学方法。所以你可以用一个 Ln 范数来近似它,其中 n 很大。您可以网格搜索在数值上保持稳定的 n 并尝试其他技巧,例如梯度裁剪。
此外,我怀疑如果您使用损失计划近似 L-inf,首先是 L2,您可以逐渐将 n 增加到 L3、L4、L5 等,以帮助训练过程。