keras集成學習一
文檔完整位置:https://docs.nn.knowledge-precipitation.site/ji-chu-zhi-shi/guo-ni-he/jichengxuexi-ensemble
集成學習的概念
當數據集有問題,或者網絡學習能力不足,或準確度不夠時,我們可以採取集成學習的方法,來提升性能。說得通俗一些,就是發揮團隊的智慧,根據團隊中不同背景、不同能力的成員的獨立意見,通過某種決策方法來解決一個問題。所以集成學習也稱爲多分類器系統(multi-classifier system)、基於委員會的學習(committee-based learning)等。
下是一個簡單的集成學習的示意圖。
圖中有兩個組件:
Individual Learner 個體學習器
如果所有的個體學習器都是同一類型的學習器,即同質模式,比如都用神經網路,稱爲“基學習器”(base learner),相應的學習算法稱爲“基學習算法”(base learning algorithm)。
在傳統的機器學習中,個體學習器可以是不同的,比如用決策樹、支持向量機等,此時稱爲異質模式。
Aggregator 結合模塊
個體學習器的輸出,通過一定的結合策略,在結合模塊中有機結合在一起,可以形成一個能力較強的學習器,所以有時稱爲強學習器,而相應地稱個體學習器爲弱學習器。
個體學習器之間是否存在依賴關係呢?這取決於產生個體學習器的方法:
- Boosting系列算法,一系列的個體學習器需要一個個地串行生成,有前後依賴關係。
- Bagging算法和隨機森林算法(Random Forest),個體學習器可以獨立或並行生成,沒有依賴關係。
我們只討論使用神經網絡的同質個體學習方法,和Bagging集成算法。由於神經網絡的複雜性,即使使用相同的網絡參數,由於初始化的不同或者訓練數據的不同,也可以得到差別很大的模型。
Bagging法集成學習的基本流程
下是Bagging集成學習的示意圖。
- 首先是數據集的使用,採用自助採樣法(Bootstrap Sampling)。假設原始數據集Training Set中有1000個樣本,我們從中隨機取一個樣本的拷貝放到Training Set-1中,此樣本不會從原始數據集中被刪除,原始數據集中還有1000個樣本,而不是999個,這樣下次再隨機取樣本時,此樣本還有可能被再次選到。如此重複m次(此例m=1000),我們可以生成Training Set-1。一共重複N次(此例N=9),可以得到N個數據集。
- 然後搭建一個神經網絡模型,可以參數相同。在N個數據集上,訓練出N個模型來。
- 最後再進入Aggregator。N值不能太小,否則無法提供差異化的模型,也不能太大而帶來訓練模型的時間花銷,一般來說取5到10就能滿足要求。
生成數據集
def GenerateDataSet(count=9):
mdr = MnistImageDataReader(train_image_file, train_label_file, test_image_file, test_label_file, "vector")
mdr.ReadLessData(1000)
for i in range(count):
X = np.zeros_like(mdr.XTrainRaw)
Y = np.zeros_like(mdr.YTrainRaw)
list = np.random.choice(1000,1000)
k=0
for j in list:
X[k] = mdr.XTrainRaw[j]
Y[k] = mdr.YTrainRaw[j]
k = k+1
# end for
np.savez("level6_" + str(i)+".npz", data=X, label=Y)
# end for
在上面的代碼中,我們假設只有1000個手寫數據樣本,用np.random.choice(1000,1000)函數來可重複地選取1000個數字,分別取出對應的圖像數據X和標籤數據Y,命名爲level6_N.npz,N=[1,9],保存到9個npz文件中。
假設數據集中有m個樣本,這樣的採樣方法,某個樣本在第一次被選擇的概率是1/m,那麼不被選擇的概率就是1-1/m,則選擇m次後,不被採樣到的概率是,取極限值:
即,對於一個新生成的訓練數據集來說,原始數據集中的樣本沒有被使用的概率爲36.8%。
訓練個體學習器神經網絡
這一步很簡單,依然用我們在Level0中的過擬合網絡,來訓練9個神經網絡。爲了體現“弱學習器”的概念,我們可以在訓練每個神經網絡時,只迭代10個epoch。
nets = []
net_count = 9
for i in range(net_count):
dataReader = LoadData(i)
net = train(dataReader)
nets.append(net)
上述代碼在一個9次的循環中,依次加載我們在前面生成的9個數據集,把訓練好的9個net保存到一個列表中,後面測試時使用。
集成方法選擇
平均法
在迴歸任務中,輸出爲一個數值,可以使用平均法來處理多個神經網絡的輸出值。下面公式中的表示第i個神經網絡的輸出,表示集成後的輸出。
- 簡單平均法:所有值加起來除以N。
- 加權平均法:給每個輸出值一個人爲定義的權重。
權重值如何給出呢?假設第一個神經網絡的準確率爲80%,第二個爲85%,我們可以令:
這樣準確率高的網絡會得到較大的權重值。
投票法
對於分類任務,將會從類別標籤集合中預測出一個值,多個神經網絡可能會預測出不一樣的值,此時可以採樣投票法。
-
絕對多數投票法(majority voting)
當有半數以上的神經網路預測出同一個類別標籤時,我們可以認爲此預測有效。如果少於半數,則可以認爲預測無效。
比如9個神經網絡,5個預測圖片上的數字爲7,則最終結果就是7。如果有4個神經網絡預測爲7,3個預測爲4,2個預測爲1,則認爲預測失敗。
-
加權投票法(weighted voting)
與加權平均法類似。
-
相對多數投票法(plurality voting)
即得票最多的標籤獲勝。如果有多個標籤獲得相同的票數,隨機選一個。
我們在代碼中使用了相對多數投票法,具體過程如下。
假設9個神經網絡對於同一張圖片的預測結果爲表16-5所示。
表16-5 9個神經網絡對某張圖片的預測結果
神經網絡ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
預測輸出 | 7 | 4 | 7 | 4 | 7 | 7 | 9 | 7 | 7 |
可以看到,在9個結果中,有6個結果預測爲7,2個預測爲4,1個預測爲9,我們選擇多數投票法,最終的預測結果爲7。
爲了驗證真實的準確率,我們可以用MNIST的測試集中的10000個樣本,來測試這9個模型,得到10000行上面表格中的數據,最後再統計最終的準確率。
此處代碼比較複雜,最關鍵的一行語句是:
ra[i] = np.argmax(np.bincount(predict_array[:,i]))
先使用np.bincount得到9個神經網絡的預測結果中,每個結果出現的次數,得到:
其含義是:數字0出現了0次,數字1出現了1次,…數字4出現了2次,…,數字7出現了6次,等等。然後再用np.argmax([0,1,0,0,2,0,0,6,0,1])得到最大的數字6的下標,結果爲7。這樣就可以得到9個神經網絡的投票結果爲該圖片上的數字是7,因爲有6個神經網絡認爲是7,佔相對多數。
學習法
學習法,就是用另外一個神經網絡,通過訓練的方式,把9個神經網路的輸出結果作爲輸入,把圖片的真實數字作爲標籤,得到一個強學習器。
假設9個神經網絡的表現如表16-6所示。
表16-6 9個神經網絡對於原始數據集中的1000個樣本的預測結果
神經網絡ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 標籤值 |
---|---|---|---|---|---|---|---|---|---|---|
預測輸出1 | 7 | 4 | 7 | 4 | 7 | 7 | 9 | 7 | 7 | 7 |
預測輸出2 | 4 | 4 | 7 | 4 | 7 | 4 | 9 | 4 | 7 | 4 |
預測輸出N | 0 | 9 | 0 | 0 | 5 | 0 | 0 | 6 | 0 | 0 |
預測輸出1000 | 7 | 2 | 2 | 6 | 2 | 2 | 2 | 5 | 2 | 2 |
接下來我們可以建立一個兩層的神經網絡,輸入層爲9,用於接收9個神經網絡的預測輸出,隱層神經元數量不要大於16,輸出層爲10分類,標籤值爲上述表格中的最後一列。
scikit_learn中的ensemble
在keras中可以將模型轉換爲sklearn的迴歸或分類模型,傳入sklearn的函數中。
from keras.wrappers.scikit_learn import KerasRegressor, KerasClassifier
def build_model1():
model = Sequential()
model.add(Dense(128, activation='relu', input_shape=(13, )))
model.add(Dense(64, activation='relu'))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam',
loss='mean_squared_error')
return model
def build_model2():
model = Sequential()
model.add(Dense(64, activation='relu', input_shape=(784, )))
model.add(Dense(32, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
return model
model = KerasRegressor(build_fn=build_model1, epochs=100, batch_size=64)
model._estimator_type = "regressor"
model = KerasClassifier(build_fn=build_model2, epochs=2, batch_size=64)
model._estimator_type = "classifier"
運行結果
我們使用了相對多數投票法,其測試結果爲表16-7所示。
表16-7 9個神經網絡的預測準確率
神經網絡ID | 準確率 |
---|---|
1 | 0.8526 |
2 | 0.8482 |
3 | 0.8438 |
4 | 0.8327 |
5 | 0.8410 |
6 | 0.8452 |
7 | 0.8443 |
8 | 0.8397 |
9 | 0.8389 |
9個神經網絡的準確率如上表所示,最大的爲0.8526,最小的爲0.8327。用投票法得到的最後的準確率爲0.8751,得到了提升,達到了集成學習的目的。
從偏差-方差的角度看,Bagging主要起到降低方差的作用。在前面我們分析過,單個學習器的過擬合是高方差造成的,我們訓練多個這樣的學習器,隨機選擇的樣本數據如果分佈均勻的話,每個學習器在針對單個測試樣本時都會有高方差風險,從而產生泛化誤差。但是由於我們擁有9個神經網絡,採用集成法後,一定程度上緩解了高方差的現象。