2017-08-08 77 views
1

我正在使用Tensorflow来构建和培训几个神经网络。这些网络正在对相关任务(自然语言处理)进行监督学习。有没有一种使用Tensorflow自动进行转换学习的方法?

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

我希望能够从一个体系结构共享经过训练的通用层的权重,以初始化另一个体系结构。

我现在做事情的方式是每次我要传递权重时我正在编写一段单独的(特设)代码。这混乱了我的项目,并且很耗时。

是否有人知道一种方法,可以让我自动化权重转移的过程。举例来说,要自动检测常见图层,然后初始化相应的权重。

回答

1

您可以专门为感兴趣的一组变量创建一个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... 

再次,如果公共层的结构是相同的,这将仅工作,因为顺序两个图的集合中的变量应该是相同的。

更新:

如果你想确保恢复的变量没有被用于训练你有几个可能性,尽管他们可能都需要在你的代码更多的变化。 A trainable变量只是包含在集合tf.GrapKeys.TRAINABLE_VARIABLES中的一个变量,所以当您在第二个图中创建传输变量时,您可以仅说trainable=False,并且恢复过程应该工作相同。如果你想变得更具动态性并且自动执行,那么它或多或少是可能的,但请记住:必须知道必须用于训练的变量列表创建优化器之前,并且之后不能更改(而不创建新的优化器)。知道这一点,我不认为有任何解决方案不会通过从第一个图表中传递可传递变量名称的列表。例如。:

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,并将优化器的minimize方法作为参数var_list传递给想要优化的变量列表(示例中为train_vars)。原则上我个人更喜欢这个,因为我认为集合的内容应该符合他们的语义目的(毕竟,代码的其他部分可能会使用相同的集合用于其他目的),但这取决于我想的情况。

+0

这似乎是我正在寻找。我将专门为共享变量创建第二个保护程序实例。然后,恢复后,我将加载相应的权重。 – ryuzakinho

+0

我运用了你的方法。重新加载很好。我想知道是否有可能使恢复的变量动态地不可训练,即只有当我重新加载这些变量时。这样可以在恢复时不必更改我的代码。 – ryuzakinho

+0

@ryuzakinho我打算写回应,但它会太长或很难解释,所以我已经更新了答案。 – jdehesa

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()函数将设置其所有的网络之间共享的变量和OPS,但使用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参数。

+0

我不明白你的意思:“假设你有权为这些图层保存重量”。 – ryuzakinho

相关问题