与 Eager 和 Graph 模式无关的 Tensorflow 训练

Posted

技术标签:

【中文标题】与 Eager 和 Graph 模式无关的 Tensorflow 训练【英文标题】:A Tensorflow training agnostic to Eager and Graph modes 【发布时间】:2018-07-30 03:12:07 【问题描述】:

我花了一些时间在 Tensorflow 中编写新颖的(我希望的)RNN 单元。 为了原型,我使用渴望模式(更容易调试)。 为了训练,我将代码迁移到图表(运行速度更快)。

我正在寻找一个包装器代码/示例,它可以以一种与我运行它的模式无关的方式运行前向传递和训练 - 尽可能多地渴望或图形。我想到了一组函数/类,可以在其中插入特定的神经网络/优化器/数据,并且这些函数/类集可以在两种模式下运行,而两者之间的变化最小。另外,能兼容多种类型的神经网络/优化器/数据实例当然是好事。

我很确定很多人都有这个想法。 考虑到 TF 中当前的 Eager/Graph 集成,我想知道这样的事情是否可行。

【问题讨论】:

【参考方案1】:

是的。我一直在想同样的事情。在Tensorflow documentation可以看到:

为 Eager Execution 编写的相同代码还将在图形执行期间构建图形。只需在未启用 Eager Execution 的新 Python 会话中运行相同的代码即可。

但这很难实现,主要是因为处理图形意味着处理占位符,而占位符不能在 Eager 模式下使用。我尝试使用面向对象的层和 Dataset API 摆脱占位符。这是我能得到的最接近完全兼容的代码:

m = 128  # num_examples
n = 5    # num features

epochs = 2
batch_size = 32
steps_per_epoch = m // 32

dataset = tf.data.Dataset.from_tensor_slices(
    (tf.random_uniform([m, n], dtype=tf.float32),
     tf.random_uniform([m, 1], dtype=tf.float32)))
dataset = dataset.repeat(epochs)
dataset = dataset.batch(batch_size)

model = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_dim=n),
    tf.keras.layers.Dense(32, activation='relu'),
    tf.keras.layers.Dense(1)
])

def train_eagerly(model, dataset):

    optimizer = tf.train.AdamOptimizer()
    iterator = dataset.make_one_shot_iterator()

    print('Training graph...')
    for epoch in range(epochs):
        print('Epoch', epoch)
        progbar = tf.keras.utils.Progbar(target=steps_per_epoch, stateful_metrics='loss')
        for step in range(steps_per_epoch):
            with tf.GradientTape() as tape:
                features, labels = iterator.get_next()
                predictions = model(features, training=True)
                loss_value = tf.losses.mean_squared_error(labels, predictions)
            grads = tape.gradient(loss_value, model.variables)
            optimizer.apply_gradients(zip(grads, model.variables))
            progbar.add(1, values=[('loss', loss_value.numpy())])

def train_graph(model, dataset):

    optimizer = tf.train.AdamOptimizer()
    iterator = dataset.make_initializable_iterator()

    print('Training graph...')
    with tf.Session() as sess:
        sess.run(iterator.initializer)
        sess.run(tf.global_variables_initializer())
        for epoch in range(epochs):
            print('Epoch', epoch)
            progbar = tf.keras.utils.Progbar(target=steps_per_epoch, stateful_metrics='loss')
            for step in range(steps_per_epoch):
                with tf.GradientTape() as tape:
                    features, labels = sess.run(iterator.get_next())
                    predictions = model(features, training=True)
                    loss_value = tf.losses.mean_squared_error(labels, predictions)
                grads = tape.gradient(loss_value, model.variables)
                optimizer.apply_gradients(zip(grads, model.variables))
                progbar.add(1, values=[('loss', loss_value.eval())])

如您所见,主要区别在于我在 Eager 训练期间使用 one_shot_iterator(当然,在图训练期间,我必须在会话中运行操作)。

我尝试使用 optimizer.minimize 来做同样的事情,而不是自己应用渐变,但我想不出一个既适用于 Eager 模式又适用于图形模式的代码。

此外,我敢肯定,对于不那么简单的模型(例如您正在使用的模型),这将变得更加困难。

【讨论】:

以上是关于与 Eager 和 Graph 模式无关的 Tensorflow 训练的主要内容,如果未能解决你的问题,请参考以下文章

tensorflow版本2.0和1.0兼容问题:The Session graph is empty. Add operations to the graph before calling run()

OneFlow v0.5.0 预览版发布

将 tf.Tensor 转换为 numpy 数组,然后将其保存为图像而不使用 eager_execution

对齐PyTorch,一文详解OneFlow的DataLoader实现

EAGER 和分页:Spring MVC + JPA Repository + Hibernate

Tensorflow Eager和Tensorboard图?