參考:遷移學習——Fine-tunepython
1、遷移學習git
就是把已訓練好的模型參數遷移到新的模型來幫助新模型訓練。網絡
模型的訓練與預測:
深度學習的模型能夠劃分爲 訓練 和 預測 兩個階段。
訓練 分爲兩種策略:一種是白手起家從頭搭建模型進行訓練,一種是經過預訓練模型進行訓練。
預測 相對簡單,直接用已經訓練好的模型對數據集進行預測便可。app
優勢:性能
1)站在巨人的肩膀上:前人花很大精力訓練出來的模型在大機率上會比你本身從零開始搭的模型要強悍,沒有必要重複造輪子。
2)訓練成本能夠很低:若是採用導出特徵向量的方法進行遷移學習,後期的訓練成本很是低,用CPU都徹底無壓力,沒有深度學習機器也能夠作。
3)適用於小數據集:對於數據集自己很小(幾千張圖片)的狀況,從頭開始訓練具備幾千萬參數的大型神經網絡是不現實的,由於越大的模型對數據量的要求越大,過擬合沒法避免。這時候若是還想用上大型神經網絡的超強特徵提取能力,只能靠遷移學習。學習
遷移學習的幾種方式:測試
一、Transfer Learning:凍結預訓練模型的所有卷積層,只訓練本身定製的全鏈接層。spa
二、Extract Feature Vector:先計算出預訓練模型的卷積層對全部訓練和測試數據的特徵向量,而後拋開預訓練模型,只訓練本身定製的簡配版全鏈接網絡。
三、Fine-tune:凍結預訓練模型的部分卷積層(一般是靠近輸入的多數卷積層),訓練剩下的卷積層(一般是靠近輸出的部分卷積層)和全鏈接層。
* 注:Transfer Learning關心的問題是:什麼是「知識」以及如何更好地運用以前獲得的「知識」,這能夠有不少方法和手段,eg:SVM,貝葉斯,CNN等。.net
而fine-tune只是其中的一種手段,更經常使用於形容遷移學習的後期微調中。rest
三種遷移學習方式對比
一、第一種和第二種訓練獲得的模型本質上並無什麼區別,可是第二種的計算複雜度要遠遠優於第一種。
二、第三種是對前兩種方法的補充,以進一步提高模型性能。要注意的是,這種方法並不必定能真的對模型有所提高。
本質上來說:這三種遷移學習的方式都是爲了讓預訓練模型可以勝任新數據集的識別工做,可以讓預訓練模型本來的特徵提取能力獲得充分的釋放和利用。可是,在此基礎上若是想讓模型可以達到更低的Loss,那麼光靠遷移學習是不夠的,靠的更多的仍是模型的結構以及新數據集的豐富程度。
2、實驗:嘗試對模型進行微調,以進一步提高模型性能
一、fine-tune的做用:
拿到新數據集,先用預訓練模型處理,一般用上面的方法一或方法二測試預訓練模型在新數據上的表現,若是表現不錯,能夠嘗試fine-tune,進一步解鎖卷積層以繼續訓練。
可是不要期待質的飛躍,另外,若是因爲新數據集與原數據集差異太大致使表現不好,一方面能夠考慮從頭訓練,另外一方面也能夠考慮解鎖比較多層的訓練。
二、不一樣數據集下使用微調
數據集1:數據量少,但數據類似度很是高
在這種狀況下,咱們所作的只是修改最後幾層或最終的softmax圖層的輸出類別,方法一
數據集2:數據量少,數據類似度低
在這種狀況下,咱們能夠凍結預訓練模型的初始層(好比k層),並再次訓練剩餘的(n-k)層。因爲新數據集的類似度較低,所以根據新數據集對較高層進行從新訓練具備重要意義。方法三
數據集3:數據量大,數據類似度低
在這種狀況下,因爲咱們有一個大的數據集,咱們的神經網絡訓練將會頗有效。可是,因爲咱們的數據與用於訓練咱們的預訓練模型的數據相比有很大不一樣。使用預訓練模型進行的預測不會有效。所以,最好根據你的數據從頭開始訓練神經網絡(Training from scatch)。
數據集4:數據量大,類似度高
這是理想狀況。在這種狀況下,預訓練模型應該是最有效的。使用模型的最好方法是保留模型的體系結構和模型的初始權重。而後,咱們可使用在預先訓練的模型中的權重來從新訓練該模型。
3.微調的注意事項
1)一般的作法是截斷預先訓練好的網絡的最後一層(softmax層),並用與咱們本身的問題相關的新的softmax層替換它。
2)使用較小的學習率來訓練網絡。
3)若是數據集數量過少,咱們進來只訓練最後一層,若是數據集數量中等,凍結預訓練網絡的前幾層的權重也是一種常見作法。
注:卷積神經網絡的核心是:
(1)淺層卷積層提取基礎特徵,好比邊緣,輪廓等基礎特徵。
(2)深層卷積層提取抽象特徵,好比整個臉型。
(3)全鏈接層根據特徵組合進行評分分類。
四、實驗操做具體步驟
一、下載預訓練模型
二、預處理:按照預訓練模型本來的預處理方式對數據進行預處理,使用預訓練模型必定要確保讓待訓練的數據儘量向原數據集靠攏,這樣才能最大程度發揮模型的識圖本領。
三、基模型和定製模型:構建和預訓練裏面徹底相同的模型。
四、查看固定和恢復節點名
五、訓練過程設置恢復,固定張量的列表
3、代碼詳情
基模型和定製模型
import slim.nets.resnet_v1 as resnet_v1 # 定義模型,由於給出的只有參數,並無模型,這裏須要指定模型的具體結構 with slim.arg_scope(resnet_v1.resnet_arg_scope()): # logits就是最後預測值,images就是輸入數據,指定num_classes=None是爲了使resnet模型最後的輸出層禁用 logits, end_points = resnet_v1.resnet_v1_50(inputs=input_images, num_classes=None) # 自定義的輸出層 with tf.variable_scope("Logits"): # 將原始模型的輸出數據去掉維度爲2和3的維度,最後只剩維度1的batch數和維度4的300*300*3 # 也就是將原來的二三四維度所有壓縮到第四維度 net = tf.squeeze(logits, axis=[1, 2]) # 加入一層dropout層 net = slim.dropout(net, keep_prob=0.5, scope='dropout_scope') # 加入一層全鏈接層,指定最後輸出大小 logits = slim.fully_connected(net, num_outputs=labels_nums, scope='fc')
查看固定和恢復節點名
look_checkpoint.py
import os from tensorflow.python import pywrap_tensorflow model_dir = os.getcwd() # 獲取當前文件工做路徑 print(model_dir)#輸出當前工做路徑 checkpoint_path = r'G:\1-modelused\Siamese_Densenet_Single_Net\output\640model\model3/model_epoch_20.ckpt'#model_dir + "\\ckpt_dir\\model-ckpt-100" print(checkpoint_path)#輸出讀取的文件路徑 # 從checkpoint文件中讀取參數 reader = pywrap_tensorflow.NewCheckpointReader(checkpoint_path) var_to_shape_map = reader.get_variable_to_shape_map() # 輸出變量名稱及變量值 for key in var_to_shape_map: # if key.startswith('DenseNet_121/AuxLogits'): # print(1) # print(key) print("tensor_name: ", key)
訓練過程設置恢復,固定張量的列表
CKPT_FILE = r'.\pretrain\resnet_v1_50.ckpt' #不須要從谷歌訓練好的模型中加載的參數。這裏就是最後的全鏈接層,由於在新的問題中要從新訓練這一層中的參數。 #這裏給出的是參數的前綴 CHECKPOINT_EXCLUDE_SCOPES = 'Logits' ## 指定最後的全鏈接層爲可訓練的參數,須要訓練的網絡層參數名稱,在fine-tuning的過程當中就是最後的全鏈接層 TRAINABLE_SCOPES = 'Logits' #獲取全部須要從谷歌訓練好的模型中加載的參數 def get_tuned_variables(): exclusions = [scope.strip() for scope in CHECKPOINT_EXCLUDE_SCOPES.split(',')] variables_to_restore = [] #枚舉inception-v3模型中全部的參數,而後判斷是否須要從加載列表中移除 for var in slim.get_model_variables(): excluded = False for exclusion in exclusions: if var.op.name.startswith(exclusion): excluded = True break if not excluded: variables_to_restore.append(var) return variables_to_restore #獲取全部須要訓練的變量列表。 def get_trainable_variables(): scopes = [scope.strip() for scope in TRAINABLE_SCOPES.split(',')] variables_to_train = [] #枚舉全部須要訓練的參數前綴,並經過這些前綴找到全部的參數。 for scope in scopes: variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,scope) variables_to_train.extend(variables) return variables_to_train #定義加載Google訓練好的Inception-v3模型的Saver load_fn = slim.assign_from_checkpoint_fn( CKPT_FILE, get_tuned_variables(), ignore_missing_vars=True ) saver = tf.train.Saver(max_to_keep=100) max_acc = 0.0 with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state('models/resnet_v1/') if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path): saver.restore(sess, ckpt.model_checkpoint_path) else: sess.run(tf.global_variables_initializer()) sess.run(tf.local_variables_initializer()) # 加載谷歌已經訓練好的模型 print('Loading tuned variables from %s' % CKPT_FILE) load_fn(sess)