有没有办法使用Tensorflow自动化转移学习?

时间:2017-08-08 13:12:07

标签: machine-learning tensorflow

我正在使用Tensorflow来构建和训练几个神经网络。这些网络正在对相关任务进行监督学习(自然语言处理)。

我所有神经网络之间的共同点是它们共享一些早期层(有些共享另外2层)。

我希望能够从一个架构共享公共层的训练权重,以初始化另一个架构。

我现在正在做的事情是,每次我想传输权重时,我都在编写一个单独的(ad-hoc)代码。这使我的项目变得混乱并且非常耗时。

是否有人知道一种方法可以让我自动化重量转移过程。比如说,自动检测公共图层,然后初始化相应的权重。

2 个答案:

答案 0 :(得分:2)

您可以专门为感兴趣的变量集创建tf.Saver,只要它们具有相同的名称,您就可以恢复其他图形中的变量。您可以使用集合来存储这些变量,然后为集合创建保护程序:

TRANSFERABLE_VARIABLES = "transferable_variable"
# ...
my_var = tf.get_variable(...)
tf.add_to_collection(TRANSFERABLE_VARIABLES, my_var)
# ...
saver = tf.Saver(tf.get_collection(TRANSFERABLE_VARIABLES), ...)

这应该允许您在一个图表中调用save,在另一个图表中调用restore来传输权重。

如果你想避免在磁盘上写任何内容,那么我认为除了手动复制/粘贴值之外别无其他。但是,通过使用集合和完全相同的构造过程,这也可以在很大程度上实现自动化:

model1_graph = create_model1()
model2_graph = create_model2()

with model1_graph.as_default(), tf.Session() as sess:
    # Train...
    # Retrieve learned weights
    transferable_weights = sess.run(tf.get_collection(TRANSFERABLE_VARIABLES))

with model2_graph.as_default(), tf.Session() as sess:
    # Load weights from the other model
    for var, weight in zip(tf.get_collection(TRANSFERABLE_VARIABLES),
                           transferable_weights):
        var.load(weight, sess)
    # Continue training...

同样,这只有在公共图层的构造相同时才有效,因为两个图形中集合中变量的顺序应该相同。

<强>更新

如果您想确保恢复的变量不用于培训,您可能会有一些可能性,尽管它们可能都需要对您的代码进行更多更改。 trainable变量只是集合tf.GrapKeys.TRAINABLE_VARIABLES中包含的变量,因此您可以在第二个图表中创建转移变量时说trainable=False,并且恢复过程应该有效相同。如果您想要更加动态并自动执行它或多或少可能,但请记住:必须在创建优化器之前知道必须用于培训的变量列表,并且之后无法更改(无需创建新的优化器)。知道这一点,我认为没有任何解决方案不通过从第一个图中传递带有可转移变量名称的列表。 E.g:

with model1_graph.as_default():
    transferable_names = [v.name for v in tf.get_collection(TRANSFERABLE_VARIABLES)]

然后,在第二个图的构造过程中,在定义模型之后,在创建优化器之前,您可以执行以下操作:

train_vars = [v for v in tf.get_collection(tf.GrapKeys.TRAINABLE_VARIABLES)
              if v.name not in transferable_names]
# Assuming that `model2_graph` is the current default graph
tf.get_default_graph().clear_collection(tf.GrapKeys.TRAINABLE_VARIABLES)
for v in train_vars:
    tf.add_to_collection(tf.GrapKeys.TRAINABLE_VARIABLES, v)
# Create the optimizer...

另一个选择是不修改集合tf.GrapKeys.TRAINABLE_VARIABLES,而是将要优化的变量列表(示例中为train_vars)作为参数var_list传递给{{ 3}}优化器的方法。原则上我个人更喜欢这个,因为我认为集合的内容应该与它们的语义目的相匹配(毕竟,代码的其他部分可能会将相同的集合用于其他目的),但这取决于我猜的情况。 / p>

答案 1 :(得分:1)

如果我理解正确,您已经保存了一些权重,希望能够在不同的网络之间使用。

初始化特定网络时,您可以使用通过共享层构建计算图的共享函数,并在训练之前使用单独的函数来加载权重。

我经常有一个专门用于构建图形的模块,具有构建每个部分的不同功能,即

def build_graph():
    with tf.Graph().as_default() as graph:
        build_shared_layers()
        build_other_layers()
        build_training_ops()
        return graph

build_shared_layers()函数将设置在所有网络之间共享的变量和操作,但是使用trainable=False标志(我假设你已经为这些层保存了权重) 。您还可以提供变量的名称,以便稍后在加载函数中引用。

然后,在训练新网络之前,只需使用var_list加载权重。您可以使用图表集合:

tf.add_to_collection('var_list', some_var)
tf.add_to_collection('var_list', another_var)

然后只需抓住该集合并拥有一个类似这样的函数:

def load_existing_weights(sess, path, var_list):
    saver = tf.train.Saver(var_list=var_list)
    ckpt = tf.train.get_checkpoint_state(path)
    saver.restore(sess, ckpt.model_checkpoint_path)

...
...
with tf.Session(graph=graph) as sess:
    load_existing_weights(sess, FLAGS.save_path, var_list)
    # get on with the training below...

编辑:意识到我忘记添加文档链接...如另一个答案中所示,请查看tf.train.Saver,特别是var_list参数。