之前做圖像分類的項目的時候一直在尋找一個行之有效的遷移學習的實現方法,但是尋找了許久都沒有找到。經過我們團隊的努力實踐最近終於探索出一個有效的方法,這裏拿出來跟大家一起探討一下看看還有那些地方需要改進的。
一,背景
首先因爲遷移學習其實沒有理論性的一個定義,所以先解析一下我們所需要實現的遷移學習,我們的圖像分類是現實分類中的其中一類物體的垂直分類,細分到具體型號的。然後我們是基於DenseNet201創建訓練模型,一開始分類數從0到100,因爲imageNet的分類跟我們需要的分類不一樣所以即使是拿它訓練好的模型也是起不來多大的提升作用。項目一直在進行,分類數再從100提升到了500,這時候從0開始訓練也是可以接受,因爲跨度大之前訓練好的模型的分類數相對新增加的分類的分類數佔比低。再下去我們再從500增加到600,600增加到630,現在我們在想如果這樣子的增加幅度也是要從0開始的話,之前的訓練時間就相當於是浪費了,所以就想到了用遷移學習這樣的方法把之前訓練好的模型的權重集成過來,再在這個基礎上訓練新加的分類。雖然不知道這個是不是屬於真正的遷移學習的範疇,但是在實踐中的確比從0開始訓練要節省時間。
二,實現
就第一點我們遇到的問題從500增加到600,600增加到630的分類數怎麼樣有效的利用之前訓練好的模型主要有下面兩個問題
1. 如何繼承前一個模型的權重
2. 如何繼承前一個模型的權重之後加上新的分類數
下面先直接上一段代碼
#create a DenseNet201 and then load the weigth from existing model
densenet = DenseNet201(include_top=False, weights='imagenet',input_tensor=None, input_shape=(299, 299, 3), pooling='avg')
output = densenet.get_layer(index=-1).output
output = Dropout(0.3)(output)
output = Dense(500, activation='softmax', name='predictions')(output)
model = Model(outputs=output, inputs=densenet.input)
model.load_weights(best_model_file)
#get the old model`s last dense weight and then add new classies into the last dense layer
output = model.get_layer(index=-2).output
old_dense = model.get_layer(index=-1)
weight_list = old_dense.get_weights()
new_weight_0 = np.concatenate((weight_list[0], np.random.randn(old_dense.get_weights()[0].shape[0], 100)), axis=1)
new_weight_1 = np.concatenate((weight_list[1], np.random.randn(100)), axis=1)
old_dense.set_weight([new_weight_0,new_weight_1])
new_dense = old_dense.output
#output the new model to do the trainningmodel = Model(outputs=new_dense, inputs=densenet.input)
上面的僞代碼主要有三部分
第一步先用Keras的已擁有的model.load_weights(best_model_file)的方法把之前訓練好的500分類的模型的權重先加載進來,現在的模型是就的500分類的模型;
第二步是在最後一層的全連接層裏在原有的500分類的權重基礎上,再在張量矩陣裏面加上100新添加分類數的隨機數矩陣。這樣子就可以使用之前已經訓練好的500的分類的權重,又可以在新的訓練裏面添加上新的分類數。
第三步把新的全連接放到Model的outputs裏面創造一個全新的模型作爲訓練使用。
這樣子下來,得到的新的訓練模型體現在訓練時間上比從0開始訓效果要好,具體數據暫時沒有記錄下來以後有機會再補充。