如果手上的訓練資料太少,但是測試資料一大堆,該怎麼辦?如果可以把測試資料當成訓練資料來用,不知道該有多好,可是測試資料沒有標籤呀!
今天讓我們來談談,遇到訓練資料遠比測試資料少的時候,我們如何善用測試資料,來增加模型的效能。
一、虛擬資料集產生器
我們先定義一個可以產生虛擬資料集的function,function的輸入是資料集的大小N,輸出是具有8個特徵的資料N筆、以及對應的N個標籤。
def func_create_data(N):
e = np.random.normal(loc = 0.0, scale = 0.1, size = (N, 8))
x = np.random.normal(loc = 0.0, scale = 1.0, size = (N, 8))
y = np.zeros(N) for index in range(len(x)):
if((x[index][0] > 1)or(x[index][1] < -1)):
y[index] = 1 return x + e, y
二、建立虛擬資料集
我們定義訓練資料100筆,測試資料10000筆。TH的功用之後會提到,在這邊讀者可以先略過。
import numpy as np
from sklearn.metrics import f1_score
from sklearn.ensemble import RandomForestClassifierTH = 0.95
N_TRAIN = 100
N_TEST = 100 * N_TRAINnp.random.seed(1)x_train, y_train = func_create_data(N_TRAIN)
x_test, y_test = func_create_data(N_TEST)
三、建立模型並做出預測
在這裡我們使用隨機森林分類器做為範例,評價指標為F1-Score。訓練好模型之後直接對測試資料做出預測。不了解隨機森林或F1-Score的讀者,可以參考旗標出版的「Kaggle競賽攻頂秘笈 - 揭開Grandmaster的特徵工程心法,掌握制勝的關鍵技術」第二章的內容。
model = RandomForestClassifier(random_state=0).fit(x_train, y_train)y_pred = model.predict(x_test)print(“Before Pseudo Labeling F1-Score:”, f1_score(y_test, y_pred))
印出來的結果:
Before Pseudo Labeling F1-Score: 0.9088445906715695
四、使用Pseudo Labeling增加模型效能
我們現在的困難是「訓練資料不夠多」,我們現在希望做的事情是「善用測試資料來訓練模型」,但我們的問題是「測試資料沒有標籤」。
讀者現在仔細想想:使用訓練好的模型,對測試資料做出預測後,測試資料就有標籤了呀!我們稱這些標籤為Pseudo Label。接下來我們其實可以把具有標籤的測試資料,跟訓練資料合併起來再訓練模型一次,並重新對測試資料做出預測。
聰明的讀者可能已經想到一個問題:如果測試資料的標籤預測錯了,卻還用這些錯誤的資訊來訓練模型,不是會讓模型更糟。沒錯!這時候剛剛略過的TH就派上用場啦:我們就只選那些非常有把握的預測結果(比如模型認為某一筆測試資料屬於標籤0的機率大於TH),加入到訓練資料:
x_pseudo = [x_test[index] for index in range(len(x_test)) if (y_prob[index][0] >= TH or y_prob[index][1] >= TH)]y_pseudo = [y_pred[index] for index in range(len(x_test)) if (y_prob[index][0] >= TH or y_prob[index][1] >= TH)]y_right0 = [y_pred[index] for index in range(len(x_test)) if (y_prob[index][0] >= TH and y_test[index] == 0)]y_right1 = [y_pred[index] for index in range(len(x_test)) if (y_prob[index][1] >= TH and y_test[index] == 1)]x_train = np.concatenate((x_train, x_pseudo), axis = 0)y_train = np.concatenate((y_train, y_pseudo), axis = 0)
重新訓練模型,並再對測試資料集做出預測:
model = RandomForestClassifier(random_state=0).fit(x_train, y_train)y_pred = model.predict(x_test)print(“After Pseudo Labeling F1-Score:”, f1_score(y_test, y_pred))
得到的分數如下:
After Pseudo Labeling F1-Score: 0.9215238095238095
增加2%,看起來不多,但現實上取得更多有標籤的資料並不一定這麼容易。而Pseudo Labeling的技術,讓我們可以不用獲得更多資料,即提升模型效能!
五、比較兩個模型的訓練資料差異
我們來看看有多少資料是來自Pseudo Labeling:
print(“Training Data Count:”, N_TRAIN)
print(“Pseudo Labeling Count:”, len(y_train) — N_TRAIN)
print(“Training Data + Pseudo Labeling Count:”, len(y_train))
print(“Correct Pseudo Labeling Count”, len(y_right0) + len(y_right1))
印出來的結果:
Training Data Count: 100
Pseudo Labeling Count: 1642
Training Data + Pseudo Labeling Count: 1742
Correct Pseudo Labeling Count 1624
第一次訓練模型的時候只有100筆資料,第二次加上Pseudo Labeling之後,我們使用了1742筆資料訓練模型。由於這些資料是我們自己創建的,所以我們可以進一步知道這些額外多出來的1642筆資料裡,有1624筆資料其實是正確的預測結果。如果讀者希望模型可以用更多正確的測試資料,可以嘗試把TH調高一點喔!
重點整理
1、如果訓練資料稀少,測試資料卻很多,可以考慮使用Pseudo Labeling來增加模型的效能
2、可以透過預測機率的分析,來篩選品質比較好的測試資料,加入原始的訓練資料集,並重新訓練模型
關於作者
Chia-Hao Li received the M.S. degree in computer science from Durham University, United Kingdom. He engages in computer algorithm, machine learning, and hardware/software codesign. He was former senior engineer in Mediatek, Taiwan. His currently research topic is the application of machine learning techniques for fault detection in the high-performance computing systems.