2017-08-08 31 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

相關問題