標籤: 半監督學習html
做者:煉己者
歡迎你們訪問 個人簡書 以及 個人博客
本博客全部內容以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,而且是非商業用途,謝謝!
---git
摘要:半監督學習很重要,爲何呢?由於人工標註數據成本過高,如今你們參加比賽的數據都是標註好的了,那麼若是老闆給你一份沒有標註的數據,並且有幾百萬條,讓你作個分類什麼的,你怎麼辦?不可能等標註好數據再去訓練模型吧,因此你得會半監督學習算法。算法
不過我在這裏先打擊你們一下,用sklearn的包作不了大數據量的半監督學習,我用的數據量大概在15000條以上就要報MemoryError錯誤了,這個是我最討厭的錯誤。暫時我尚未解決的辦法,若是同志們是小數據量,那就用這個作着玩玩吧。你們若是有興趣也能夠看一下這篇文章——用半監督算法作文本分類apache
報MemoryError錯誤怎麼辦?sklearn提供這麼全的文檔固然會有這部分的考慮啦。看這裏——sklearn 中的模型對於大數據集的處理。能夠用partial_fit增量式計算,惋惜只針對部分算法,對於半監督學習沒有辦法。數組
好了,該說正題了,最近看了sklearn關於半監督學習的例子,它裏面有三個例子,在這裏我主要想分享一下第三個例子——用半監督學習算法作數字識別dom
首先咱們來看一下這份數據集的特色
函數
sklearn官方例子——用半監督學習作數字識別學習
咱們來看一下操做流程測試
- 一共330個點,都是已經標註好的了,咱們把其中的320個點賦值爲-1,這樣就能夠僞裝這320個點都是沒有標註的了
- 訓練一個只有10個標記點的標籤傳播模型
- 而後從全部數據中選擇要標記的前五個最不肯定的點,把它們(帶有正確標籤)放到原來的10個點中
- 接下來能夠訓練15個標記點(原始10個 + 5個新點)
- 重複這個過程四次,就可使用30個標記好的點來訓練模型
- 能夠經過改變max_iterations將這個值增長到30以上
以上是sklearn的操做流程,你們可能會有點糊塗
實際任務應該是這樣的。假設咱們有一份數據集,共330個數字,其中前十個是已知的,已經標註好了,後320個是未知的,須要咱們預測出來的。大數據
- 首先把這330個數據所有都放到半監督學習算法裏,訓練模型,預測那320個標籤
- 而後用某種方法(看下面代碼的操做)得知這320個數據裏最不肯定的前5個數據,對它進行人工標註,而後把它放到以前的10個數據裏,如今就有15個已知數據了
- 這樣循環個幾回,已標註的數據就變多了,那麼分類器的效果確定也就變好了
import numpy as np import matplotlib.pyplot as plt from scipy import stats from sklearn import datasets from sklearn.semi_supervised import label_propagation from sklearn.metrics import classification_report,confusion_matrix # 再加下面這個,否則會報錯 from scipy.sparse.csgraph import *
digits = datasets.load_digits() rng = np.random.RandomState(0) # indices是隨機產生的0-1796個數字,且打亂 indices = np.arange(len(digits.data)) rng.shuffle(indices) # 取前330個數字來玩 X = digits.data[indices[:330]] y = digits.target[indices[:330]] images = digits.images[indices[:330]] n_total_samples = len(y) # 330 n_labeled_points = 10 # 標註好的數據共10條 max_iterations = 5 # 迭代5次 unlabeled_indices = np.arange(n_total_samples)[n_labeled_points:] # 未標註的數據320條 f = plt.figure() # 畫圖用的
建議你們把本身不懂的地方打印出來看看是啥意思,好比下面
for i in range(max_iterations): if len(unlabeled_indices) == 0: print("no unlabeled items left to label") # 沒有未標記的標籤了,所有標註好了 break y_train = np.copy(y) y_train[unlabeled_indices] = -1 #把未標註的數據所有標記爲-1,也就是後320條數據 lp_model = label_propagation.LabelSpreading(gamma=0.25,max_iter=5) # 訓練模型 lp_model.fit(X,y_train) predicted_labels = lp_model.transduction_[unlabeled_indices] # 預測的標籤 true_labels = y[unlabeled_indices] # 真實的標籤 cm = confusion_matrix(true_labels,predicted_labels, labels = lp_model.classes_) print("預測標籤") print(predicted_labels) print("真實標籤") print(true_labels) print('----------------------------------------------')
預測標籤 [2 8 6 6 6 6 1 9 5 8 8 2 8 7 7 6 7 9 2 9 7 7 6 8 9 1 8 1 9 1 1 6 7 7 9 9 7 6 2 1 9 6 7 9 9 9 9 1 6 9 9 2 8 7 2 9 2 6 9 1 8 9 5 1 2 1 2 2 9 7 2 8 6 9 9 8 7 5 1 2 9 9 8 1 7 7 1 1 6 1 5 9 2 6 8 9 2 1 7 7 9 7 8 9 7 5 8 2 1 9 2 9 8 1 1 7 9 6 1 5 8 9 9 6 9 9 5 7 9 6 2 8 6 9 6 1 5 1 5 9 9 1 8 9 6 1 8 9 1 7 6 7 6 5 6 9 8 8 9 8 6 1 9 7 2 6 8 8 6 7 1 9 6 9 9 8 9 8 9 7 7 9 7 8 9 7 8 9 6 7 5 9 1 7 6 1 9 8 9 9 9 9 2 1 1 2 1 1 1 9 2 1 9 8 7 6 1 8 8 1 6 9 9 6 9 2 2 9 7 6 1 1 9 7 2 7 8 6 6 7 5 2 8 7 2 7 9 5 7 9 9 2 6 5 9 7 1 8 8 9 8 6 7 6 9 2 6 1 8 8 1 6 7 5 2 1 5 8 2 1 6 9 1 5 7 9 1 6 2 9 9 1 2 2 9 9 6 9 7 2 9 7 5 8 6 7 8 2 8 7 9 7 2 6 5 1 5 1 9 8] 真實標籤 [2 8 6 6 6 6 1 0 5 8 8 7 8 4 7 5 4 9 2 9 4 7 6 8 9 4 3 1 0 1 8 6 7 7 1 0 7 6 2 1 9 6 7 9 0 0 5 1 6 3 0 2 3 4 1 9 2 6 9 1 8 3 5 1 2 8 2 2 9 7 2 3 6 0 5 3 7 5 1 2 9 9 3 1 7 7 4 8 5 8 5 5 2 5 9 0 7 1 4 7 3 4 8 9 7 9 8 2 6 5 2 5 8 4 8 7 0 6 1 5 9 9 9 5 9 9 5 7 5 6 2 8 6 9 6 1 5 1 5 9 9 1 5 3 6 1 8 9 8 7 6 7 6 5 6 0 8 8 9 8 6 1 0 4 1 6 3 8 6 7 4 5 6 3 0 3 3 3 0 7 7 5 7 8 0 7 8 9 6 4 5 0 1 4 6 4 3 3 0 9 5 9 2 1 4 2 1 6 8 9 2 4 9 3 7 6 2 3 3 1 6 9 3 6 3 2 2 0 7 6 1 1 9 7 2 7 8 5 5 7 5 2 3 7 2 7 5 5 7 0 9 1 6 5 9 7 4 3 8 0 3 6 4 6 3 2 6 8 8 8 4 6 7 5 2 4 5 3 2 4 6 9 4 5 4 3 4 6 2 9 0 1 7 2 0 9 6 0 4 2 0 7 9 8 5 4 8 2 8 4 3 7 2 6 9 1 5 1 0 8] ----------------------------------------------
for i in range(max_iterations): if len(unlabeled_indices) == 0: print("no unlabeled items left to label") # 沒有未標記的標籤了,所有標註好了 break y_train = np.copy(y) y_train[unlabeled_indices] = -1 #把未標註的數據所有標記爲-1,也就是後320條數據 lp_model = label_propagation.LabelSpreading(gamma=0.25,max_iter=5) # 訓練模型 lp_model.fit(X,y_train) predicted_labels = lp_model.transduction_[unlabeled_indices] # 預測的標籤 true_labels = y[unlabeled_indices] # 真實的標籤 cm = confusion_matrix(true_labels,predicted_labels, labels = lp_model.classes_) print("iteration %i %s" % (i,70 * "_")) # 打印迭代次數 print("Label Spreading model: %d labeled & %d unlabeled (%d total)" % (n_labeled_points,n_total_samples-n_labeled_points,n_total_samples)) print(classification_report(true_labels,predicted_labels)) print("Confusion matrix") print(cm) # 計算轉換標籤分佈的熵 # lp_model.label_distributions_做用是Categorical distribution for each item pred_entropies = stats.distributions.entropy( lp_model.label_distributions_.T) # 選擇分類器最不肯定的前5位數字的索引 # 首先計算出全部的熵,也就是不肯定性,而後從320箇中選擇出前5個熵最大的 # numpy.argsort(A)提取排序後各元素在原來數組中的索引。具體狀況可看下面 # np.in1d 用於測試一個數組中的值在另外一個數組中的成員資格,返回一個布爾型數組。具體狀況可看下面 uncertainty_index = np.argsort(pred_entropies)[::1] uncertainty_index = uncertainty_index[ np.in1d(uncertainty_index,unlabeled_indices)][:5] # 這邊能夠肯定每次選前幾個做爲不肯定的數,最終都會加回到訓練集 # 跟蹤咱們得到標籤的索引 delete_indices = np.array([]) # 可視化前5次的結果 if i < 5: f.text(.05,(1 - (i + 1) * .183), 'model %d\n\nfit with\n%d labels' % ((i + 1),i*5+10),size=10) for index,image_index in enumerate(uncertainty_index): # image_index是前5個不肯定標籤 # index就是0-4 image = images[image_index] # 可視化前5次的結果 if i < 5: sub = f.add_subplot(5,5,index + 1 + (5*i)) sub.imshow(image,cmap=plt.cm.gray_r) sub.set_title("predict:%i\ntrue: %i" % ( lp_model.transduction_[image_index],y[image_index]),size=10) sub.axis('off') # 從320條裏刪除要那5個不肯定的點 # np.where裏面的參數是條件,返回的是知足條件的索引 delete_index, = np.where(unlabeled_indices == image_index) delete_indices = np.concatenate((delete_indices,delete_index)) unlabeled_indices = np.delete(unlabeled_indices,delete_indices) # n_labeled_points是前面不肯定的點有多少個被標註了 n_labeled_points += len(uncertainty_index) f.suptitle("Active learning with label propagation.\nRows show 5 most" "uncertain labels to learn with the next model") plt.subplots_adjust(0.12,0.03,0.9,0.8,0.2,0.45) plt.show()
import numpy as np B=np.array([[4,2,3,55],[5,6,37,8],[-7,68,9,0]]) print('B:') print(B) print('') print('默認輸出') print(np.argsort(B))#默認的輸出每行元素的索引值。這些索引值對應的元素是從小到大排序的。
B: [[ 4 2 3 55] [ 5 6 37 8] [-7 68 9 0]] 默認輸出 [[1 2 0 3] [0 1 3 2] [0 3 2 1]]
values = np.array([6, 0, 0, 3, 2, 5, 6]) np.in1d(values, [2, 3, 6])
array([ True, False, False, True, True, False, True])
此次主要是想用半監督學習算法作NLP文本分類,看到sklearn庫里正好有這個算法包,想拿來試一下,結果跑不了那麼大的數據量,算是失敗了。可是我以爲仍是從中瞭解了不少,後面會寫一篇關於它的博客,裏面關於文本的處理讓我學到了不少,走了不少的彎路。接下來我還會繼續探索怎麼用少標註的數據來作文本分類。