TensorFlow: вызов графика внутри другого графика

#tensorflow #neural-network #tensor

#tensorflow #нейронная сеть #тензор

Вопрос:

Мне нужно предоставить «логиты» одного графика (g1) в качестве входных данных другого графика (g2). Затем мне нужно получить выходные данные уровня g2, когда входные данные являются «logits». После некоторых вычислений на выходных данных слоя я должен вернуть пользовательское значение потерь в g1.

Вот первый график:

 g1 = tf.Graph() 
with g.as_default():
    X = tf.placeholder(dtype=tf.float32, shape=[...])
    Y = tf.placeholder(dtype=tf.float32, shape=[...])
    ...
    logits = tf.matmul(flatten, W2)   b2

    def custom_loss(logits):
        # get layer output values of g2 on the input "logits" 
        # some calculations on layer outputs
       return loss

    mse = tf.reduce_mean(tf.squared_difference(logits, Y))

    loss = mse   custom_loss(logits)

    step = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(loss)

sess1 = tf.InteractiveSession(graph=g1)
tf.global_variables_initializer().run()
  

Вот второй график:

 g2 = tf.Graph()
with g2.as_default():
    X = tf.placeholder(dtype=tf.float32, shape=[...])
    Y = tf.placeholder(dtype=tf.float32, shape=[...])
    ...
    loss = ...
    step = ...

sess2 = tf.InteractiveSession(graph=g2)
tf.global_variables_initializer().run()
  

Я не уверен, что это возможно сделать. Первая проблема в том, что сеансы работы с этими графами разные. Следовательно, я не мог ввести «логиты» в качестве входных данных g2 на графике g1.

Вторая проблема в том, что g2 принимает массив элементов («X»), но когда я передаю «logits» в g2, это не сработает, поскольку это тензор. Можно преобразовать его в массив numpy, используя сеанс, но как я могу использовать сеанс внутри графика? Я создаю сеанс после того, как я создал график.

Мне нужны ваши предложения для решения этих проблем. Заранее спасибо.

Ответ №1:

Рассмотрим следующий пример. У вас есть первый график следующим образом:

 import tensorflow as tf

graph1 = tf.Graph()
with graph1.as_default():
    x1 = tf.placeholder(tf.float32, shape=[None, 2])
    y1 = tf.placeholder(tf.int32, shape=[None])

    with tf.name_scope('network'):
        logits1 = tf.layers.dense(x1, units=2)

    train_vars1 = tf.trainable_variables()
  

И второй график:

 graph2 = tf.Graph()
with graph2.as_default():
    x2 = tf.placeholder(tf.float32, shape=[None, 2])
    y2 = tf.placeholder(tf.int32, shape=[None])

    with tf.name_scope('network'):
        logits2 = tf.layers.dense(x2, units=2)

    with tf.name_scope('loss'):
        xentropy2 = tf.nn.sparse_softmax_cross_entropy_with_logits(
            labels=y2, logits=logits2)
        loss_fn2 = tf.reduce_mean(xentropy2)

    with tf.name_scope('optimizer'):
        optimizer2 = tf.train.GradientDescentOptimizer(0.01)
        train_op2 = optimizer2.minimize(loss_fn2)
    train_vars2 = tf.trainable_variables()
  

Теперь вы хотите передать выходные данные уровня logits первого графика в качестве входных данных во второй график. Мы делаем это, создавая два сеанса, инициализируя переменные, оценивая уровень logits первого графика, а затем отправляя вычисленное значение в качестве входных данных во второй график. Я собираюсь использовать набор данных toy blobs для иллюстрации:

 from sklearn.datasets import make_blobs

x_train, y_train = make_blobs(n_samples=4,
                              n_features=2,
                              centers=[[1, 1], [-1, -1]],
                              cluster_std=0.5)
sess1 = tf.Session(graph=graph1)
sess2 = tf.Session(graph=graph2)

_ = sess1.run([v.initializer for v in train_vars1])
_ = sess2.run([v.initializer for v in train_vars2])

# feed the logits layer of graph1 as input to graph2
logits1_val = sess1.run(logits1, feed_dict={x1:x_train})
logits2_val = sess2.run(logits2, feed_dict={x2:logits1_val})
print(logits2_val)
# [[ 1.3904244   2.811252  ]
#  [-0.39521402 -1.6812694 ]
#  [-1.7728546  -4.522432  ]
#  [ 0.6836863   3.2234416 ]]
  

Обратите внимание, что вычисленное значение логитов первого графика ( logits1_val ) уже является массивом numpy, поэтому вы можете использовать его как есть в качестве входных данных второго графика. То же самое, когда вы хотите выполнить шаг поезда для второго графика:

 # train step for the second graph
logits1_val = sess1.run(logits1, feed_dict={x1:x_train})
loss_val2, _ = sess2.run([loss_fn2, train_op2], feed_dict={x2:logits1_val, y2:y_train})
print(loss_val2) # 0.8134985
  

ОБНОВИТЬ, если мы определим обе сети в одном графике:

 import tensorflow as tf
from sklearn.datasets import make_blobs

x_train, y_train = make_blobs(n_samples=4,
                              n_features=2,
                              centers=[[1, 1], [-1, -1]],
                              cluster_std=0.5)

with tf.variable_scope('network_1'):
    x = tf.placeholder(tf.float32, shape=[None, 2])
    y = tf.placeholder(tf.int32, shape=[None])

    with tf.name_scope('network'):
        logits1 = tf.layers.dense(x, units=2)

with tf.variable_scope('network_2'):
    with tf.name_scope('network'):
        logits2 = tf.layers.dense(logits1, units=2) # <-- output of `network_1` is input to `network_2`

    with tf.name_scope('custom_loss'):
        # Define your custom loss here. I use cross-entropy
        # for illustration
        xentropy2 = tf.nn.sparse_softmax_cross_entropy_with_logits(
            labels=y, logits=logits2)
        custom_loss2 = tf.reduce_mean(xentropy2)

    with tf.name_scope('optimizer'):
        optimizer2 = tf.train.GradientDescentOptimizer(0.01)
        var_list = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                     scope='network_2')
        train_op2 = optimizer2.minimize(custom_loss2, var_list=var_list)

with tf.variable_scope('network_1'):
    # Take the `custom_loss2` from `network_2` and create a new custom loss
    # for `network_1`
    xentropy1 = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=y, logits=logits1)
    custom_loss1 = tf.reduce_mean(xentropy1)   custom_loss2 # <-- loss from `network_2`
    optimizer1 = tf.train.AdamOptimizer(0.01)
    var_list = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                 scope='network_1')
    train_op1 = optimizer1.minimize(custom_loss1, var_list=var_list)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    # grad update step   loss computation for first network
    loss1, _ = sess.run([custom_loss1, train_op1], feed_dict={x:x_train, y:y_train})
    print(loss1) # 0.44655064
    # grad update step   loss computation for second network
    loss2, _ = sess.run([custom_loss2, train_op2], feed_dict={x:x_train, y:y_train})
    print(loss2) # 0.3163877
  

Комментарии:

1. Спасибо за быстрый ответ @Vlad! Я понял, как передавать логиты graph1 в качестве входных данных graph2, например. Но мне нужно сделать это внутри графика, поскольку я добавлю возвращаемое значение к функции потерь. Например; logits1_val = sess1.run(logits1, feed_dict={X1:logits2, Y1:np.zeros((1,10))}) . Это должно быть внутри графа2. Здесь проблема в том, что «feed_dict» не принимает «logits2» для «X1», потому что это не массив numpy. Я не могу оценить его как «sess2.run(logits2)», чтобы получить его значение массива внутри графика , поскольку sess2 еще не создан для graph2. Надеюсь, это поясняющее.

2. Хорошо, я думаю, что знаю, как это написать. Я пропустил ту часть, которая вам нужна для возврата потерь со второго графика. Это слишком сложно сделать с двумя отдельными графиками, потому что будет сложно вычислить градиенты потерь по отношению к весам из обоих графиков (для этого потребуется вычисление градиента вручную). Это должны быть две отдельные сети на одном графике. Здесь немного поздно, поэтому я сформулирую свой ответ завтра.

3. Спасибо за ваш ответ @Vlad. Это действительно то, чего я хочу.