各位朋友,新年好! 隨着春節假期的結束,想必你們陸陸續續返回工做崗位,開始新的一年的拼搏。我也會繼續努力,爭取在深度學習方面更進一步,接下來,我將繼續聊一聊深度學習在計算機視覺中的應用。git
在前面的《站在巨人的肩膀上:遷移學習》和《再談遷移學習:微調網絡》兩篇文章中,咱們介紹了遷移學習的強大之處。然而,人們探索新知識老是永無止境,在提升深度學習模型準確率方面,仍在孜孜不倦的追求着。這篇文章將介紹一種提高模型準確率的方法:組合模型。github
從字面上理解,組合模型並不難解釋,簡單說,就是爲深度學習創建多個模型,而後用多個模型來預測,採起投票或平均法來決定最後的預測結果。稍微想想,彷佛比較好理解,俗話說,三個臭皮匠,頂個諸葛亮。多個模型投票的結果,應該好於單個模型的準確率。固然,機器學習看起來有些不靠譜(拿機率說事),但仍是創建在嚴密的理論基礎之上,組合模型提升準確率若是僅僅創建在一條諺語之上,不足以說服人,也沒辦法讓人接受。bash
事實上,組合模型是創建在一個稱爲琴生不等式(Jensen's inequality)之上,該公式以丹麥數學家約翰·琴生(Johan Jensen)命名,給出了積分的凸函數值和凸函數的積分值間的關係。有興趣的同窗能夠去Google一下,看看這個公式有何神奇之處,我也找了一些資料,然而...沒看懂,只瞭解其大意是說,可能某個的模型的偏差低於全部模型的平均值,但因爲咱們沒有能夠用來「選擇」此模型的標準,因此咱們能夠確信全部模型的平均值不會比隨機選擇一個模型差。是否是仍是有些暈乎?嗯,這個不重要,咱們用實踐來檢驗一下是否是有效吧。微信
接下來,咱們就要準備訓練多個機器學習模型。咱們也不用把問題複雜化,設計多種網絡結構的模型,最簡單的方法是,採用相同的網絡結構,甚至使用相同的超參數,但訓練出不一樣的參數。閒話少說,直接上代碼:網絡
((trainX, trainY), (testX, testY)) = cifar10.load_data()
trainX = trainX.astype("float") / 255.0
testX = testX.astype("float") / 255.0
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
labelNames = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "trunk"]
aug = ImageDataGenerator(rotation_range=10, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True,
fill_mode="nearest")
for i in np.arange(0, args["num"]):
print("[INFO] training model {}/{}".format(i + 1, args["num"]))
opt = SGD(lr=0.01, decay=0.01/40, momentum=0.9, nesterov=True)
model = MiniVGGNet.build(width=32, height=32, depth=3, classes=10)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=64), validation_data=(testX, testY), epochs=40,
steps_per_epoch=len(trainX)//64, verbose=1)
p = [args["models"], "model_{}.model".format(i)]
model.save(os.path.sep.join(p))
複製代碼
代碼比較容易理解,採用cifar10數據集訓練,10種類別標籤,對輸入數據進行了數據擴充(data augmentation),這個數據擴充是隨機實時進行,加上訓練數據集和驗證數據集也是隨機劃分,因此最後訓練出的網絡參數有所不一樣,訓練完成以後,將模型序列化到文件,供後面使用。循環num遍,就產生了num個模型。app
接下來就是依次加載個模型文件,每一個模型分別進行預測,而後取均值:機器學習
(testX, testY) = cifar10.load_data()[1]
testX = testX.astype("float") / 255.0
labelNames = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "trunk"]
lb = LabelBinarizer()
testY = lb.fit_transform(testY)
model_paths = os.path.join(args["models"], "*.model")
model_paths = list(glob.glob(model_paths))
models = []
for (i, model_path) in enumerate(model_paths):
print("[INFO] loading model {}/{}".format(i + 1, len(model_paths)))
models.append(load_model(model_path))
print("[INFO] evaluating ensemble ...")
predictions = []
for model in models:
predictions.append(model.predict(testX, batch_size=64))
predictions = np.average(predictions, axis=0)
print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1), target_names=labelNames))
複製代碼
上面的代碼,代碼量相對於單個模型而言,並無增長多少,只是多了一個循環,多了一個取平均值,但訓練過程卻多了num倍,我用電腦訓練5個模型,結果花了一夜尚未訓練完:(函數
最後測試的結果如何呢?經過組合多個網絡的輸出,成功將準確度從83%提升到84%,即便這些網絡使用徹底相同的超參數在同一數據集上進行訓練。有數據代表,採用組合模型,一般準確度有1-5%的提高。post
看到這兒,你可能會有些失望,費了這麼大的勁,好像也沒啥提高,可是別忘了,在醫療領域、自動駕駛領域,即便費上好大的力氣,準確率可以提高小數點後面幾位,都是值得的。就像每一年度的kaggle競賽,人們依然在孜孜不倦的追求着準確率的提高。學習
以上實例均有完整的代碼,點擊閱讀原文,跳轉到我在github上建的示例代碼。
另外,我在閱讀《Deep Learning for Computer Vision with Python》這本書,在微信公衆號後臺回覆「計算機視覺」關鍵字,能夠免費下載這本書的電子版。