TensorFlow: вызов графа внутри другого графа - PullRequest
1 голос
/ 07 апреля 2019

Мне нужно дать «логиты» одного графа (g1) как входные данные другого графа (g2). Затем мне нужно получить выходные данные слоя g2, когда вход «логит». После некоторых расчетов выходных данных слоя я должен вернуть пользовательское значение потерь 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, он не будет работать, поскольку он является тензором. Можно преобразовать его в массив с использованием сеанса, но как я могу использовать сеанс внутри графа? Я создаю сеанс после того, как создал график.

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

1 Ответ

1 голос
/ 07 апреля 2019

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

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 первого графа и затем передавая оцененное значение в качестве входных данных во второй граф.Я собираюсь использовать набор данных игрушечных блобов, чтобы проиллюстрировать:

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) уже является пустым массивом, поэтому вы можете использовать его какввод второго графика.То же самое, если вы хотите выполнить шаг поезда для второго графика:

# 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
...