什么是半監(jiān)督學(xué)習(xí)?
在機(jī)器學(xué)習(xí)的世界里,有一種學(xué)習(xí)方法介于“全力以赴”的監(jiān)督學(xué)習(xí)和“放飛自我”的無監(jiān)督學(xué)習(xí)之間,這就是我們今天的主角——半監(jiān)督學(xué)習(xí)(Semi-Supervised Learning)。如果把監(jiān)督學(xué)習(xí)比作一個學(xué)生考試時完全靠自己背的書,而無監(jiān)督學(xué)習(xí)就像是瞎蒙,半監(jiān)督學(xué)習(xí)則是個取巧的小聰明學(xué)生。他手里有一些答案(標(biāo)簽數(shù)據(jù)),也有一部分沒見過的題目(無標(biāo)簽數(shù)據(jù)),于是他聰明地利用已知的知識去推測未知的答案。
半監(jiān)督學(xué)習(xí)與監(jiān)督學(xué)習(xí)的比較
為了更好地理解半監(jiān)督學(xué)習(xí),我們不妨先回顧一下監(jiān)督學(xué)習(xí)。在監(jiān)督學(xué)習(xí)中,每一個樣本都配有一個明確的標(biāo)簽,算法就像個“好學(xué)生”,通過學(xué)習(xí)這些樣本來預(yù)測新樣本的標(biāo)簽。然而,在現(xiàn)實(shí)世界中,標(biāo)注數(shù)據(jù)往往非常昂貴。想想看,如果要給成千上萬的圖片打標(biāo)簽,得有多少個小手酸痛的標(biāo)注員??!而且,很多時候我們手頭只有少量標(biāo)注數(shù)據(jù),但卻有大量的無標(biāo)簽數(shù)據(jù),這種情況就是半監(jiān)督學(xué)習(xí)的舞臺。
在這種情況下,半監(jiān)督學(xué)習(xí)通過結(jié)合少量的標(biāo)注數(shù)據(jù)和大量的無標(biāo)簽數(shù)據(jù)來訓(xùn)練模型。與監(jiān)督學(xué)習(xí)相比,半監(jiān)督學(xué)習(xí)既節(jié)省了標(biāo)注成本,又能有效提高模型的泛化能力。就像在考試中,半監(jiān)督學(xué)習(xí)的學(xué)生不僅僅依靠老師給出的復(fù)習(xí)資料(有標(biāo)簽的數(shù)據(jù)),還會從其他未標(biāo)注的資料中尋找模式、推測答案,最終在考試中取得好成績。
常用的半監(jiān)督學(xué)習(xí)算法
半監(jiān)督學(xué)習(xí)的方法很多,我們來聊聊幾種常見的算法:
自訓(xùn)練(Self-training)
這可以說是最經(jīng)典的半監(jiān)督學(xué)習(xí)方法之一。想象一下,你在做作業(yè)時對某些題目不是特別確定,但又不想放棄,于是你先寫下一個自己認(rèn)為最有可能的答案。之后,假設(shè)自己寫對了,并繼續(xù)用這個“答案”來解答后續(xù)的問題。這就是自訓(xùn)練的基本思路:模型用少量的標(biāo)注數(shù)據(jù)進(jìn)行訓(xùn)練,然后用自己預(yù)測的結(jié)果來為無標(biāo)簽的數(shù)據(jù)打標(biāo)簽,再用這些新“打上標(biāo)簽”的數(shù)據(jù)來進(jìn)一步訓(xùn)練模型。雖然聽起來有點(diǎn)像“自我欺騙”,但在某些情況下,它能有效提高模型的性能。
共訓(xùn)練(Co-training)
共訓(xùn)練的思路比自訓(xùn)練稍微復(fù)雜一點(diǎn)點(diǎn),但原理卻很巧妙。它假設(shè)你手里有兩套不同的學(xué)習(xí)資料(特征),比如一份是講解概念的,另一份是練習(xí)題。你可以用其中一份資料學(xué)習(xí)并預(yù)測另一份資料上的內(nèi)容,反之亦然。這兩個模型就像兩位小伙伴,互相幫助對方提升學(xué)習(xí)效果。具體來說,兩個模型會在不同的特征子集上獨(dú)立進(jìn)行訓(xùn)練,然后用彼此預(yù)測的結(jié)果來為新的無標(biāo)簽數(shù)據(jù)打上標(biāo)簽。最后,這些新的標(biāo)簽會被用來更新兩個模型,提升它們的整體性能。
生成式模型(Generative Models)
生成式模型試圖去了解數(shù)據(jù)的內(nèi)在結(jié)構(gòu),并通過這種理解來生成數(shù)據(jù)。比如,混合高斯模型(Gaussian Mixture Model, GMM)就是一種常用的生成式模型。它假設(shè)數(shù)據(jù)是由多個高斯分布生成的,然后嘗試找到這些分布的參數(shù)。標(biāo)注數(shù)據(jù)幫助模型找到每個分布對應(yīng)的類別,而無標(biāo)簽數(shù)據(jù)則進(jìn)一步幫助確定這些分布的具體形狀和位置。
圖形方法(Graph-based Methods)
圖形方法把數(shù)據(jù)看作圖上的節(jié)點(diǎn),節(jié)點(diǎn)之間的邊代表它們的相似度。一個關(guān)鍵的假設(shè)是:相似的節(jié)點(diǎn)應(yīng)該有相似的標(biāo)簽。通過傳播標(biāo)注數(shù)據(jù)的標(biāo)簽到相似的無標(biāo)簽數(shù)據(jù)上,這些方法可以高效地擴(kuò)展標(biāo)注數(shù)據(jù)。一個典型的例子是拉普拉斯正則化(Laplacian Regularization),它通過最小化圖上相鄰節(jié)點(diǎn)標(biāo)簽差異的平方和,來確保相似的數(shù)據(jù)被分配到同一類。
半監(jiān)督學(xué)習(xí)的應(yīng)用領(lǐng)域
說了這么多,你可能會問:“半監(jiān)督學(xué)習(xí)究竟能派上什么用場呢?” 實(shí)際上,半監(jiān)督學(xué)習(xí)在多個領(lǐng)域有著廣泛的應(yīng)用:
自然語言處理(NLP)
在NLP任務(wù)中,比如文本分類、情感分析、機(jī)器翻譯等,往往存在大量未標(biāo)注的文本數(shù)據(jù)。通過半監(jiān)督學(xué)習(xí),可以充分利用這些未標(biāo)注的數(shù)據(jù)來提升模型的性能。比如,在情感分析中,你可能只有少量標(biāo)注為“積極”或“消極”的評論,但有大量未標(biāo)注的評論。半監(jiān)督學(xué)習(xí)可以幫助你從這些無標(biāo)簽數(shù)據(jù)中挖掘出更多的情感信息。
計算機(jī)視覺
在圖像分類、物體檢測、圖像分割等任務(wù)中,標(biāo)注數(shù)據(jù)的獲取成本非常高昂。半監(jiān)督學(xué)習(xí)可以在只有少量標(biāo)注圖像的情況下,通過利用大量未標(biāo)注的圖像數(shù)據(jù)來提高模型的表現(xiàn)。例如,在自動駕駛中,標(biāo)注每一幀圖像中的行人、車輛等對象需要大量的人工成本,而半監(jiān)督學(xué)習(xí)可以在一定程度上減少這種依賴。
生物信息學(xué)
在基因表達(dá)數(shù)據(jù)分析、蛋白質(zhì)結(jié)構(gòu)預(yù)測等生物信息學(xué)領(lǐng)域,標(biāo)注數(shù)據(jù)通常很稀缺。半監(jiān)督學(xué)習(xí)可以幫助研究人員利用大量的無標(biāo)簽數(shù)據(jù)來預(yù)測基因的功能或疾病的相關(guān)性,從而推動生物醫(yī)學(xué)研究的發(fā)展。
推薦系統(tǒng)
推薦系統(tǒng)中,用戶對商品的評價(比如打分)通常是稀疏的,但你可能有大量的用戶行為數(shù)據(jù)(如瀏覽、點(diǎn)擊)。半監(jiān)督學(xué)習(xí)可以通過這些無標(biāo)簽的行為數(shù)據(jù)來改進(jìn)推薦算法,提供更精準(zhǔn)的個性化推薦。
在醫(yī)療領(lǐng)域,標(biāo)注的數(shù)據(jù)通常是專家給出的診斷結(jié)果,而這些數(shù)據(jù)的獲得往往非常昂貴且時間緊迫。然而,醫(yī)療機(jī)構(gòu)通常擁有大量的未標(biāo)注的病人記錄。通過半監(jiān)督學(xué)習(xí),模型可以更好地從這些未標(biāo)注的數(shù)據(jù)中學(xué)習(xí),輔助醫(yī)生進(jìn)行更準(zhǔn)確的診斷。
半監(jiān)督學(xué)習(xí)在機(jī)器學(xué)習(xí)中是一個強(qiáng)大的工具,特別是在標(biāo)注數(shù)據(jù)稀缺但無標(biāo)簽數(shù)據(jù)豐富的情況下,它能幫助我們以較低的成本獲得更好的模型效果。通過結(jié)合監(jiān)督學(xué)習(xí)的準(zhǔn)確性和無監(jiān)督學(xué)習(xí)的靈活性,半監(jiān)督學(xué)習(xí)在多個應(yīng)用領(lǐng)域中展現(xiàn)了其獨(dú)特的價值。盡管目前半監(jiān)督學(xué)習(xí)仍然面臨著一些挑戰(zhàn),如:如何有效地利用無標(biāo)簽數(shù)據(jù)以及如何防止模型被錯誤標(biāo)簽誤導(dǎo),但它無疑是機(jī)器學(xué)習(xí)領(lǐng)域中一顆璀璨的明珠。
半監(jiān)督學(xué)習(xí)一些算法示例:
自訓(xùn)練(Self-training)示例:
用已標(biāo)注的數(shù)據(jù)訓(xùn)練一個初始模型。這是因?yàn)槲覀兪诸^只有少量的標(biāo)注數(shù)據(jù),所以一開始的模型可能不是很強(qiáng)大。使用這個初始模型對未標(biāo)注的數(shù)據(jù)進(jìn)行預(yù)測。模型會為每個未標(biāo)注的樣本生成一個預(yù)測標(biāo)簽。選擇那些模型預(yù)測結(jié)果置信度較高的未標(biāo)注樣本。這些樣本的預(yù)測結(jié)果很可能是正確的,所以我們可以假設(shè)它們的標(biāo)簽是準(zhǔn)確的。將這些高置信度的樣本及其預(yù)測標(biāo)簽加入到標(biāo)注數(shù)據(jù)集中,重新訓(xùn)練模型。這樣,模型的訓(xùn)練數(shù)據(jù)增多,性能也會提高。不斷重復(fù)步驟2-4,直到模型的性能達(dá)到滿意的水平,或者沒有更多高置信度的未標(biāo)注數(shù)據(jù)可供使用為止。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 生成一個二分類問題的數(shù)據(jù)集
X, y = make_classification(n_samples=300, n_features=2, n_informative=2, n_redundant=0, n_clusters_per_class=1,
random_state=42)
X_labeled, X_unlabeled, y_labeled, _ = train_test_split(X, y, test_size=0.95, random_state=42)
# 可視化函數(shù)
def plot_decision_boundary(model, X, y, X_unlabeled=None, iteration=None):
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdYlBu)
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, edgecolor='k', marker='o', cmap=plt.cm.RdYlBu)
if X_unlabeled is not None:
plt.scatter(X_unlabeled[:, 0], X_unlabeled[:, 1], c='grey', s=20, edgecolor='k', marker='x', label='Unlabeled')
if iteration is not None:
plt.title(f'Iteration {iteration}')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.legend()
plt.show()
# 初始模型訓(xùn)練
model = RandomForestClassifier(random_state=42)
model.fit(X_labeled, y_labeled)
# 初始數(shù)據(jù)分布和決策邊界
plot_decision_boundary(model, X_labeled, y_labeled, X_unlabeled, iteration=0)
# 自訓(xùn)練過程
confidence_threshold = 0.9 # 置信度閾值
max_iterations = 10
for iteration in range(1, max_iterations + 1):
# 預(yù)測未標(biāo)注數(shù)據(jù)
probas = model.predict_proba(X_unlabeled)
max_probas = np.max(probas, axis=1) # 找到每個樣本的最大置信度
high_confidence_mask = max_probas >= confidence_threshold # 篩選出高置信度樣本
if np.sum(high_confidence_mask) == 0:
print(f"迭代 {iteration}: 無高置信度樣本可供選擇,結(jié)束訓(xùn)練。")
break
# 將高置信度的未標(biāo)注樣本加入到訓(xùn)練集中
X_high_confidence = X_unlabeled[high_confidence_mask]
y_high_confidence = model.predict(X_high_confidence)
X_labeled = np.vstack((X_labeled, X_high_confidence))
y_labeled = np.hstack((y_labeled, y_high_confidence))
# 從未標(biāo)注集中移除這些樣本
X_unlabeled = X_unlabeled[~high_confidence_mask]
# 重新訓(xùn)練模型
model.fit(X_labeled, y_labeled)
# 可視化當(dāng)前的決策邊界
plot_decision_boundary(model, X_labeled, y_labeled, X_unlabeled, iteration=iteration)
# 最終模型性能測試(假設(shè)有測試集)
# y_pred = model.predict(X_test)
#?print("模型準(zhǔn)確率:",?accuracy_score(y_test,?y_pred))
# 輸出
迭代 6: 無高置信度樣本可供選擇,結(jié)束訓(xùn)練。
混合高斯模型(Gaussian Mixture Model, GMM)示例:
下面我們使用 sklearn 庫實(shí)現(xiàn) GMM :
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
# 生成一些樣本數(shù)據(jù)
np.random.seed(42)
X = np.vstack([np.random.normal(0, 1, (100, 2)),
np.random.normal(5, 1, (100, 2)),
np.random.normal(10, 1, (100, 2))])
# 擬合 GMM 模型
gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=42)
gmm.fit(X)
# 預(yù)測每個樣本的標(biāo)簽
labels = gmm.predict(X)
# 繪制聚類結(jié)果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.title("GMM Clustering")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()