1

我想在 tensorflow 中使用外部优化器接口来使用牛顿优化器,因为 tf.train 只有一阶梯度下降优化器。同时,我想使用 tf.keras.layers 构建我的网络,因为在构建大型复杂网络时,它比使用 tf.Variables 更容易。我将通过以下简单的一维线性回归示例展示我的问题:

import tensorflow as tf
from tensorflow.keras import backend as K
import numpy as np

#generate data
no = 100
data_x = np.linspace(0,1,no)
data_y = 2 * data_x + 2 + np.random.uniform(-0.5,0.5,no)
data_y = data_y.reshape(no,1)
data_x = data_x.reshape(no,1)

# Make model using keras layers and train
x = tf.placeholder(dtype=tf.float32, shape=[None,1])
y = tf.placeholder(dtype=tf.float32, shape=[None,1])

output = tf.keras.layers.Dense(1, activation=None)(x)

loss = tf.losses.mean_squared_error(data_y, output)
optimizer = tf.contrib.opt.ScipyOptimizerInterface(loss, method="L-BFGS-B")

sess = K.get_session()
sess.run(tf.global_variables_initializer())

tf_dict = {x : data_x, y : data_y}
optimizer.minimize(sess, feed_dict = tf_dict, fetches=[loss], loss_callback=lambda x: print("Loss:", x))

运行它时,损失根本没有改变。当使用 tf.train 中的任何其他优化器时,它工作正常。此外,当使用 tf.layers.Dense() 而不是 tf.keras.layers.Dense() 时,它确实可以使用 ScipyOptimizerInterface。所以真正的问题是 tf.keras.layers.Dense() 和 tf.layers.Dense() 之间有什么区别。我看到 tf.layers.Dense() 创建的变量是 tf.float32_ref 类型,而 tf.keras.layers.Dense() 创建的变量是 tf.float32 类型。就我现在而言,_ref 表明这个张量是可变的。所以也许这就是问题所在?但是话又说回来,来自 tf.train 的任何其他优化器都可以与 keras 层一起正常工作。

谢谢

4

2 回答 2

1

经过大量挖掘,我找到了可能的解释。

ScipyOptimizerInterface 使用 feed_dicts 在优化过程中模拟变量的更新。它仅在最后执行分配操作。相反, tf.train 优化器总是做分配操作。ScipyOptimizerInterface 的代码并不复杂,因此您可以轻松验证这一点。

现在的问题是使用 feed_dict 分配变量主要是偶然的。这是我了解这一点的链接。换句话说,通过 feed dict 分配变量,这是 ScipyOptimizerInterface 所做的,是一种进行更新的 hacky 方式。

现在这个 hack 主要是有效的,除非它没有。tf.keras.layers.Dense 使用 ResourceVariables 对模型的权重进行建模。这是简单变量的改进版本,具有更清晰的读/写语义。问题是在新语义下,feed dict 更新发生在损失计算之后。上面的链接给出了一些解释。

现在 tf.layers 目前是 tf.keras.layer 的薄包装,所以我不确定它为什么会起作用。也许代码中的某处有一些兼容性检查。

解决这个问题的解决方案有些简单。

  • 要么避免使用使用 ResourceVariables 的组件。这可能有点困难。
  • 修补 ScipyOptimizerInterface 以始终对变量进行赋值。这相对容易,因为所有必需的代码都在一个文件中。

有一些努力使界面与 Eager 一起工作(默认情况下使用 ResourceVariables)。看看这个链接

于 2019-06-06T01:13:00.970 回答
0

我认为问题出在线路上

output = tf.keras.layers.Dense(1, activation=None)(x)

在这种格式中,输出不是层而是层的输出,这可能会阻止包装器收集层的权重和偏差并将它们提供给优化器。尝试将其写成两行,例如

output = tf.keras.layers.Dense(1, activation=None)
res = output(x)

如果要保留原始格式,则可能必须手动收集所有可训练数据并通过 var_list 选项将它们提供给优化器

optimizer = tf.contrib.opt.ScipyOptimizerInterface(loss, var_list = [Trainables], method="L-BFGS-B")

希望这可以帮助。

于 2019-04-22T06:20:00.793 回答