Как сделать обратный переход через модель, которая предсказывает веса для другого в Tensorflow
В настоящее время я пытаюсь обучить модель (гиперсеть), которая может предсказать весовые коэффициенты для другой модели (основной сети) так, чтобы потеря кросс-энтропии основной сети уменьшалась. Однако когда я использую tf.assign для назначения новых весов сети, это не позволяет обратное распространение в гиперсети, что делает систему недифференцируемой. Я проверил, правильно ли обновляются мои веса, и, похоже, они таковы, поскольку вычитание начальных весов из обновленных является ненулевой суммой.
Это минимальный образец того, чего я пытаюсь достичь.
import numpy as np
import tensorflow as tf
from tensorflow.contrib.layers import softmax
def random_addition(variables):
addition_update_ops = []
for variable in variables:
update = tf.assign(variable, variable+tf.random_normal(shape=variable.get_shape()))
addition_update_ops.append(update)
return addition_update_ops
def network_predicted_addition(variables, network_preds):
addition_update_ops = []
for idx, variable in enumerate(variables):
if idx == 0:
print(variable)
update = tf.assign(variable, variable + network_preds[idx])
addition_update_ops.append(update)
return addition_update_ops
def dense_weight_update_net(inputs, reuse):
with tf.variable_scope("weight_net", reuse=reuse):
output = tf.layers.conv2d(inputs=inputs, kernel_size=(3, 3), filters=16, strides=(1, 1),
activation=tf.nn.leaky_relu, name="conv_layer_0", padding="SAME")
output = tf.reduce_mean(output, axis=[0, 1, 2])
output = tf.reshape(output, shape=(1, output.get_shape()[0]))
output = tf.layers.dense(output, units=(16*3*3*3))
output = tf.reshape(output, shape=(3, 3, 3, 16))
return output
def conv_net(inputs, reuse):
with tf.variable_scope("conv_net", reuse=reuse):
output = tf.layers.conv2d(inputs=inputs, kernel_size=(3, 3), filters=16, strides=(1, 1),
activation=tf.nn.leaky_relu, name="conv_layer_0", padding="SAME")
output = tf.reduce_mean(output, axis=[1, 2])
output = tf.layers.dense(output, units=2)
output = softmax(output)
return output
input_x_0 = tf.zeros(shape=(32, 32, 32, 3))
target_y_0 = tf.zeros(shape=(32), dtype=tf.int32)
input_x_1 = tf.ones(shape=(32, 32, 32, 3))
target_y_1 = tf.ones(shape=(32), dtype=tf.int32)
input_x = tf.concat([input_x_0, input_x_1], axis=0)
target_y = tf.concat([target_y_0, target_y_1], axis=0)
output_0 = conv_net(inputs=input_x, reuse=False)
target_y = tf.one_hot(target_y, 2)
crossentropy_loss_0 = tf.losses.softmax_cross_entropy(onehot_labels=target_y, logits=output_0)
conv_net_parameters = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="conv_net")
weight_net_parameters = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="weight_net")
print(conv_net_parameters)
weight_updates = dense_weight_update_net(inputs=input_x, reuse=False)
#updates_0 = random_addition(conv_net_parameters)
updates_1 = network_predicted_addition(conv_net_parameters, network_preds=[weight_updates])
with tf.control_dependencies(updates_1):
output_1 = conv_net(inputs=input_x, reuse=True)
crossentropy_loss_1 = tf.losses.softmax_cross_entropy(onehot_labels=target_y, logits=output_1)
check_sum = tf.reduce_sum(tf.abs(output_0 - output_1))
c_opt = tf.train.AdamOptimizer(beta1=0.9, learning_rate=0.001)
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) # Needed for correct batch norm usage
with tf.control_dependencies(update_ops): # Needed for correct batch norm usage
train_variables = weight_net_parameters #+ conv_net_parameters
c_error_opt_op = c_opt.minimize(crossentropy_loss_1,
var_list=train_variables,
colocate_gradients_with_ops=True)
init=tf.global_variables_initializer()
with tf.Session() as sess:
init = sess.run(init)
loss_list_0 = []
loss_list_1 = []
for i in range(1000):
_, checksum, crossentropy_0, crossentropy_1 = sess.run([c_error_opt_op, check_sum, crossentropy_loss_0,
crossentropy_loss_1])
loss_list_0.append(crossentropy_0)
loss_list_1.append(crossentropy_1)
print(checksum, np.mean(loss_list_0), np.mean(loss_list_1))
Кто-нибудь знает, как я могу получить тензор потока для вычисления градиентов для этого? Спасибо.
1 ответ
В этом случае ваши веса не являются переменными, они вычисляются тензорами на основе гиперсети. Все, что у вас есть, это одна сеть во время тренировок. Если я вас правильно понимаю, вы предлагаете отказаться от гиперсети и иметь возможность использовать только основную сеть для выполнения прогнозов.
Если это так, то вы можете либо сохранить значения веса вручную и перезагрузить их как константы, либо использовать tf.cond
а также tf.assign
назначать их, как вы делаете во время тренировки, но используйте tf.cond
выбрать использование переменной или вычисленного тензора в зависимости от того, проводите ли вы обучение или умозаключение.
Во время обучения вам нужно будет использовать вычисленный тензор из гиперсети, чтобы включить backprop.
Пример из комментариев, w
вес, который вы будете использовать, вы можете назначить переменную во время тренировки, чтобы отслеживать ее, но затем использовать tf.cond
либо использовать переменную (во время вывода), либо вычисленное значение из гиперсети (во время обучения). В этом примере вам нужно передать логический заполнитель is_training_placeholder
чтобы указать, проводите ли вы тренировку вывода.
tf.assign(w_variable, w_from_hypernetwork)
w = tf.cond(is_training_placeholder, true_fn=lambda: w_from_hypernetwork, false_fn=lambda: w_variable)