Использование tf.contrib.opt.ScipyOptimizerInterface с tf.keras.layers, потери не меняются

Я хочу использовать интерфейс внешнего оптимизатора в программе tenorflow, чтобы использовать оптимизаторы Ньютона, поскольку в tf.train есть только оптимизаторы градиентного спуска первого порядка. В то же время я хочу построить свою сеть с использованием tf.keras.layers, поскольку это намного проще, чем использование tf.Variables при создании больших и сложных сетей. Я покажу свою проблему на следующем простом примере 1D линейной регрессии:

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.Variables вместо tf.keras.layers он отлично работает с tf.contrib.opt.ScipyOptimizerInterface. Почему это не работает с keras.layers, хотя??

Спасибо

0 ответов

После долгих раскопок я смог найти возможное объяснение.

ScipyOptimizerInterface использует feed_dicts для имитации обновлений ваших переменных в процессе оптимизации. Он выполняет операцию присваивания только в самом конце. Напротив, оптимизаторы tf.train всегда выполняют операции назначения. Код ScipyOptimizerInterface не так уж сложен, так что вы можете легко это проверить.

Теперь проблема в том, что присвоение переменных с feed_dict работает в основном случайно. Вот ссылка, где я узнал об этом. Другими словами, присвоение переменных с помощью feed dict, что и делает ScipyOptimizerInterface, является хакерским способом обновления.

Теперь этот хак в основном работает, кроме случаев, когда это не так. tf.keras.layers.Dense использует ResourceVariables для моделирования весов модели. Это улучшенная версия простых переменных, которая имеет более чистую семантику чтения / записи. Проблема заключается в том, что в соответствии с новой семантикой обновление рассылки происходит после расчета потерь. Ссылка выше дает некоторые пояснения.

Теперь tf.layers в настоящее время является тонкой оболочкой для tf.keras.layer, поэтому я не уверен, почему это сработает. Может быть, где-то в коде есть проверка совместимости.

Решения для решения этой проблемы несколько просты.

  • Либо избегайте использования компонентов, которые используют ResourceVariables. Это может быть довольно сложно.
  • Патч ScipyOptimizerInterface, чтобы всегда делать назначения для переменных. Это относительно просто, поскольку весь необходимый код находится в одном файле.

Были некоторые попытки заставить интерфейс работать с нетерпением (который по умолчанию использует ResourceVariables). Проверьте эту ссылку

Я думаю, что проблема с линией

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

Надеюсь это поможет.

Другие вопросы по тегам