提升模型準確率:組合模型

各位朋友,新年好! 隨着春節假期的結束,想必你們陸陸續續返回工做崗位,開始新的一年的拼搏。我也會繼續努力,爭取在深度學習方面更進一步,接下來,我將繼續聊一聊深度學習在計算機視覺中的應用。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》這本書,在微信公衆號後臺回覆「計算機視覺」關鍵字,能夠免費下載這本書的電子版。

往期回顧

  1. 再談遷移學習:微調網絡
  2. 站在巨人的肩膀上:遷移學習
  3. 聊一聊rank-1和rank-5準確度
  4. 使用數據加強技術提高模型泛化能力

image
相關文章
相關標籤/搜索