使用tf.contrib.opt.ScipyOptimizerInterface和tf.keras.layers,丢失不变

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用tf.contrib.opt.ScipyOptimizerInterface和tf.keras.layers,丢失不变相关的知识,希望对你有一定的参考价值。

我想在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层中正常工作。

谢谢

答案

我认为问题在于线路

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")

希望这可以帮助。

另一答案

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

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

现在问题是用feed_dict来配置变量主要是偶然的。这是一个link,我在那里了解到这一点。换句话说,通过feed dict分配变量,这是ScipyOptimizerInterface所做的,是一种执行更新的hacky方式。

现在这个黑客大部分都有效,除非没有。 tf.keras.layers.Dense使用ResourceVariables来模拟模型的权重。这是简单变量的改进版本,具有更清晰的读/写语义。问题是在新语义下,在损失计算之后会发生Feed dict更新。上面的链接给出了一些解释。

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

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

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

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

以上是关于使用tf.contrib.opt.ScipyOptimizerInterface和tf.keras.layers,丢失不变的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)