多任務學習方法

  最近一直在做多任務,但是效果好象沒什麼提升,因爲都是憑自己的想法和感覺在做。於是上網查找了一些這方面的資料,尋求一些理論上的支撐和前人經驗上的幫助。

多任務學習:

  故名思意,就是多個任務一起學習。爲什麼要進行多任務學習呢?因爲現實中樣本採樣的成本較高,而訓練樣本不足常常會出現過擬合的現象,而將多個相關任務同時學習,通過共享某個共同的知識可以提高各任務的泛化效果

分類:

在這裏插入圖片描述
  基於軟共享的深度多任務學習在這裏插入圖片描述
  基於硬共享的深度多任務學習
在這裏插入圖片描述

一些問題:

1、損失的整合

  爲多個任務定義一個損失函數,若將每個任務的損失進行簡單相加,由於不同任務的收斂速度不同,可能某一任務的收斂得到不錯的效果,而其他任務表現卻很差。
  簡單的解決辦法是將簡單相加變爲加權相加,但這樣會不時進行調參。
  論文《Multi-Task Learning Using Uncertainty to Weigh Losses for Scene Geometry and Semantics》,提出引入不確定性來確定損失的權重:在每個任務的損失函數中學習另一個噪聲參數(noise parameter)。此方法可以接受多任務(可以是迴歸和分類),並統一所有損失的尺度。這樣就能像一開始那樣,直接相加得到總損失了。該方法不僅可以得到很好的結果而且不需要考慮額外的權重超參數。

2、調節學習速率
  學習速率是最重要的超參數之一。我們發現,任務 A 和任務 B 各自合適的速率可能是不同的。這時,我們可以在各個任務的子網絡(基於硬共享的深度多任務學習)分別調節各自的學習速率,而在共享網絡部分,使用另一個學習速率。
  雖然聽上去很複雜,但其實非常簡單。通常,在利用 TensorFlow 訓練神經網絡時,使用的是:

optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)

  AdamOptimizer 定義如何應用梯度,而 minimize 則完成具體的計算和應用。我們可以將 minimize 替換爲我們自己的實現方案,在應用梯度時,爲計算圖中的各變量使用各自適合的學習速率。

all_variables = shared_vars + a_vars + b_vars
all_gradients = tf.gradients(loss, all_variables)

shared_subnet_gradients = all_gradients[:len(shared_vars)]
a_gradients = all_gradients[len(shared_vars):len(shared_vars + a_vars)]
b_gradients = all_gradients[len(shared_vars + a_vars):]

shared_subnet_optimizer = tf.train.AdamOptimizer(shared_learning_rate)
a_optimizer = tf.train.AdamOptimizer(a_learning_rate)
b_optimizer = tf.train.AdamOptimizer(b_learning_rate)

train_shared_op = shared_subnet_optimizer.apply_gradients(zip(shared_subnet_gradients, shared_vars))
train_a_op = a_optimizer.apply_gradients(zip(a_gradients, a_vars))
train_b_op = b_optimizer.apply_gradients(zip(b_gradients, b_vars))

train_op = tf.group(train_shared_op, train_a_op, train_b_op)  

注:這個技巧其實在單任務網絡中也很實用

3、將估計作爲特徵
  當完成第一階段的工作,爲預測多任務創建好神經網絡後,我們可能希望將某一個任務得到的估計(estimate)作爲另一個任務的特徵。在前向傳遞(forward-pass)中,這非常簡單。但在反向傳播中呢?
  假設將任務 A 的估計作爲特徵輸入給 B,我們可能並不希望將梯度從任務 B 傳回任務 A,因爲我們已經有了任務 A 的標籤。對此,TensorFlow 的 API 所提供的 tf.stop_gradient 會有所幫助。在計算梯度時,它允許你傳入一個希望作爲常數的張量列表,這正是我們所需要的。

all_gradients = tf.gradients(loss, all_variables, stop_gradients=stop_tensors)    

不止如此,該技術可用在任何你希望利用 TensorFlow 計算某個值並將其作爲常數的場景。

我的一些想法:

關於多個任務的訓練,應該也可以不統一成一個損失函數,各個任務擁有自己的損失函數即可。
這樣可以分別找到適合各個任務的學習速率,和迭代次數,然後進行次數不同迭代即可。
比如:
任務A需要迭代100次才收斂:optimizer1 = tf.train.AdamOptimizer(learning_rate1).minimize(loss1)
任務B需要迭代10次收斂:optimizer2 = tf.train.AdamOptimizer(learning_rate2).minimize(loss2)

# 訓練:
for epoch in range(100):
    # Task A
    sess.run([optimizer1], feed_dict1)
    # Task B
    if epoch % 10 == 0:
        sess.run([optimizer2], feed_dict2)

【當然這部分只是我的想法啦!沒什麼科學依據】

參考資料:

什麼是多任務學習
深度神經網絡中的多任務學習彙總
關於深度多任務學習的 3 點經驗

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章