影像是貓還是狗?情感是正還是負?貸還是不貸?這些問題,該如何使用合適的機器學習模型來解決呢?
問題
暑假後,又有一批研究生要開題了。這幾天陸續收到他們發來的研究計劃大綱。
其中好幾個,打算使用機器學習做分類。
但是,從他們的文字描述來看,不少人對機器學習進行分類的方法,還是一知半解。
考慮到之前分享機器學習處理分類問題的文章,往往針對具體的任務案例。似乎對分類問題的整體步驟與注意事項,還沒有詳細論述過。於是我決定寫這篇文章,幫他們梳理一下。
他們和你一樣,也是我專欄的讀者。
如果你對機器學習感興趣,並且實際遇到了分類任務,那我解答他們遇到的一些疑問,可能對於你同樣有用。
所以,我把這篇文章也分享給你。希望能有一些幫助。
監督
監督式機器學習任務很常見。主要模型,是分類與迴歸。
就分類問題而言,二元分類是典型應用。
例如決策輔助,你利用結構化資料,判定可否貸款給某個客戶;
例如情感分析,你需要通過一段文字,來區分情感的正負極性;
例如影像識別,你得識別出圖片是貓,還是狗。
今天我們們就先介紹一下,二元分類,這個最為簡單和常見的機器學習應用場景。
注意要做分類,你首先得有合適的資料。
什麼是合適的資料呢?
這得回到我們對機器學習的大類劃分。
分類任務,屬於監督式學習。
監督式學習的特點,是要有標記。
例如給你1000張貓的圖片,1000張狗的圖片,扔在一起,沒有打標記。這樣你是做不了分類的。
雖然你可以讓機器學習不同圖片的特徵,讓它把圖片區分開。
但是這叫做聚類,屬於非監督學習。
天知道,機器是根據什麼特徵把圖片分開的。
你想得到的結果,是貓放在一類,狗放在另一類。
但是機器抓取特徵的時候,也許更喜歡按照顏色區分。
結果白貓白狗放在了一個類別,黃貓黃狗放在了另一個類別。跟你想要的結果大相徑庭。
如果你對非監督學習感興趣,可以參考《如何用Python從海量文字抽取主題?》一文。
所以,要做分類,就必須有標記才行。
但是標記不是天上掉下來的。
大部分情況下,都是人打上去的。
標記
打標記(Labeling),是個專業化而繁複的勞動。
你可以自己打,可以找人幫忙,也可以利用眾包的力量。
例如亞馬遜的“土耳其機器人”(Amazon Mechanical Turk)專案。
別被名字唬住,這不是什麼人工智慧專案,而是普通人可以利用業餘時間賺外快的機會。
你可以幫別人做任務拿佣金。任務中很重要的一部分,就是人工分類,打標記。
因此如果你有原始資料,但是沒有標記,就可以把資料扔上去。
說明需求,花錢找人幫你標記。
類似的服務,國內也有很多。
建議找知名度比較高的平臺來做,這樣標記的質量會比較靠譜。
如果你還是在校學生,可能會覺得這樣的服務價格太貴,個人難以負擔。
沒關係。假如你的研究是有基金資助專案的一部分,可以正大光明地找導師申請資料採集費用。
但若你的研究屬於個人行為,就得另想辦法了。
不少學生選擇的辦法,是依靠團隊支援。
例如找低年級的研究生幫忙標記。
人家幫了忙,讓你發表了論文,順利畢業。你總得請大家吃一頓好吃的,是吧?
學習
有了標記以後,你就能夠實施監督學習,做分類了。
這裡我們順帶說一下,什麼叫做“機器學習”。
這個名字很時髦。
其實它做的事情,叫做“基於統計的資訊表徵”。
先說資訊表徵(representation)。
你的輸入,可能是結構化的資料,例如某個人的各項生理指標;可能是非結構化資料,例如文字、聲音甚至是影像,但是最終機器學習模型看到的東西,都是一系列的數字。
這些數字,以某種形式排布。
可能是零維的,叫做標量(scalar);
可能是一維的,叫做向量(vector);
可能是二維的,叫做矩陣(Matrice);
可能是高維的,叫做張量(Tensor)。
但是,不論輸入的資料,究竟有多少維度,如果你的目標是做二元分類,那麼經過一個或簡單、或複雜的模型,最後的輸出,一定是個標量數字。
你的模型,會設定一個閾值。例如0.5。
超出這個數字的,被分類到一處。
反之,被分類到另一處。
任務完成。
那麼模型究竟在做什麼呢?
它的任務,就是把輸入的資料,表徵成最終的這個標量。
打個不恰當的比方,就如同高考。
每一個考生,其實都是獨特的。
每個人都有自己的家庭,自己的夢想,自己的經歷,自己的故事。
但是高考這個模型,不可能完整準確表徵上述全部細節。
它簡單地以考生們的試卷答題紙作為輸入,以一個最終的總成績作為輸出。
然後,劃定一個叫做錄取分數線的東西,作為閾值(判定標準)。
達到或超出了,錄取。
否則,不錄取。
這個分數,就是高考模型對每個考生的資訊表徵。
所謂分類模型的優劣,其實就是看模型是否真的達到了預期的分類效果。
什麼是好的分類效果?
大學想招收的人,錄取了(True Positive, TP);
大學不想招收的人,沒被錄取(True Negative, TN)。
什麼是不好的分類效果?
大學想招收的人,沒能被錄取(False Negative, FN);
大學不想招收的人,被錄取了(False Positive, FP)。
好的模型,需要盡力增大 TP 和 TN 的比例,降低 FN 和 FP 的比例。
評判的標準,視你的類別資料平衡而定。
資料平衡,例如1000張貓照片,1000張狗照片,可以使用 ROC AUC。
資料不平衡,例如有1000張貓的照片,卻只有100張狗的照片,可以使用 Precision 和 Recall ,或者二者相結合的 F1 score。
因為有這樣明確的評估標準,所以二元分類模型不能滿足於“分了類”,而需要向著“更好的分類結果”前進。
辦法就是利用統計結果,不斷改進模型的表徵方法。
所以,模型的引數需要不斷迭代。
恢復高考後的40年,高考的形式、科目、分值、大綱……包括加分政策等,一直都在變化。這也可以看作是一種模型的迭代。
“表徵”+“統計”+“迭代”,這基本上就是所謂的“學習”。
結構化
看到這裡,希望你的頭腦裡已經有了機器學習做二元分類問題的技術路線概貌。
下面我們們針對不同的資料型別,說說具體的操作形式和注意事項。
先說最簡單的結構化資料。
例如《貸還是不貸:如何用Python和機器學習幫你決策?》一文中,我們見到過的客戶資訊。
處理這樣的資料,你首先需要關注資料的規模。
如果資料量大,你可以使用複雜的模型。
如果資料量小,你就得使用簡單的模型。
為什麼呢?
因為越複雜的模型,表徵的資訊就越多。
表徵的資訊多,未必是好事。
因為你抓住的,既有可能是訊號,也有可能是噪聲。
如果表徵資訊多,可是學習過的資料不多,它可能就會對不該記住的資訊,形成記憶。
在機器學習領域,這是最恐怖的結果——過擬合(overfitting)。
翻譯成人話,就是見過的資料,分類效果極好;沒見過的資料,表現很糟糕。
舉一個我自己的例子。
我上學前班後沒多久,我媽就被請了家長。
因為我漢語拼音默寫,得了0分。
老師嘴上說,是懷疑我不認真完成功課;心裡想的,八成是這孩子智商餘額不足。
其實我挺努力的。
每天老師讓回家默寫的內容,都默了。
但是我默寫的時候,是嚴格按照“a o e i u ……”的順序默的。
因為每天都這樣默寫,所以我記住的東西,不是每個讀音對應的符號,而是它們出現的順序。
結果上課的時候,老師是這樣唸的“a b c d e ……”
我毫無懸念沒跟下來。
我的悲劇,源於自己的心智模型,實際上只反覆學習了一條資料“a o e i u ……”。每天重複,導致過擬合,符號出現在順序中,才能辨識和記憶。
因此,見到了新的組合方式,就無能為力了。
看,過擬合很糟糕吧。
確定了模型的複雜度以後,你依然需要根據特徵多少,選擇合適的分類模型。
上圖來自於 Scikit-learn ,我擷取了其中“分類”模型部分,你可以做參考。
注意模型的效果,實際上是有等級劃分的。
例如根據 Kaggle 資料科學競賽多年的實踐結果來看,Gradient Boosting Machine 優於隨機森林,隨機森林優於決策樹。
這麼比有些不厚道,因為三者的出現,也是有時間順序的。
讓爺爺跟孫子一起賽跑,公平性有待商榷。
因此,你不宜在論文中,將不同的分類模型,分別調包跑一遍,然後來個橫向對比大測評。
許多情況下,這是沒有意義的。
雖然顯得工作量很大。
但假如你發現在你自己的資料集上面,決策樹的效果就是明顯優於 Gradient Boosting Machine ,那你倒是很有必要通過論文做出彙報。
儘管大部分審稿人都會認為,一定是你算錯了。
另一個需要注意的事項,是特徵工程(feature engineering)。
什麼叫特徵工程呢?
就是手動挑選特徵,或者對特徵(組合)進行轉化。
例如《如何用Python和深度神經網路鎖定即將流失的客戶?》一文中,我們就對特徵進行了甄別。其中三列資料,我們直接剔除掉了:
- RowNumber:行號,這個肯定沒用,刪除
- CustomerID:使用者編號,這個是順序發放的,刪除
- Surname:使用者姓名,對流失沒有影響,刪除
正式學習之前,你需要把手頭掌握的全部資料分成3類:
- 訓練集
- 驗證集
- 測試集
我在給期刊審稿的時候,發現許多使用機器學習模型的作者,無論中外,都似乎不能精確理解這些集合的用途。
訓練集讓你的模型學習,如何利用當前的超引數(例如神經網路的層數、每一層的神經元個數等)組合,儘可能把表徵擬合標記結果。
就像那個笑話說的一樣:
Machine Learning in a Nutshell:
Interviewer: what`s you biggest strength?
Me: I`m a quick learner.
Interviewer: What`s 11*11?
Me: 65.
Interviewer: Not even close. It`s 121.
Me: It`s 121.
而驗證集的存在,就是為了讓你對比不同的超引數選擇,哪一組更適合當前任務。它必須用訓練集沒有用過的資料。
驗證集幫你選擇了合適的超引數後,它的歷史任務也就結束了。
這時候,你可以把訓練集、驗證集合並在一起,用最終確定的超引數組合進行訓練,獲得最優模型。
這個模型表現怎麼樣?
你當然需要其他的資料來評判。這就是為什麼你還要劃分出另外的測試集。
影像
François Chollet 在自己的書中舉過一個例子,我覺得很有啟發,一併分享給你。
假如你看到了這樣的原始資料:
你該怎麼做分類?
有的同學一看是影像,立刻決定,上卷積神經網路!
別忙,想想看,真的需要“直接上大錘”嗎?
別的不說,那一圈的刻度,就對我們的模型毫無意義。
你可以利用特徵工程,將其表達為這樣的座標點:
你看,這樣處理之後,你立刻就擁有了結構化資料。
注意這個轉換過程,並不需要人工完成,完全可以自動化。
但是舉一反三的你,估計已經想到了“更好的”解決方案:
對,這樣一來,表達鐘錶時間的資料,就從原先的4個數字,變成了只需要2個。
一個本來需要用複雜模型解決的問題,就是因為簡單的特徵工程轉化,複雜度和難度顯著下降。
其實,曾經人們進行圖片分類,全都得用特徵工程的方法。
那個時候,圖片分類問題極其繁瑣、成本很高,而且效果還不理想。
手動提取的特徵,也往往不具備良好的可擴充套件性和可遷移性。
於是,深度卷積神經網路就登場了。
如果你的圖片資料量足夠多的話,你就可以採用“端到端”的學習方式。
所謂“端到端”,是指不進行任何的特徵工程,構造一個規模合適的神經網路模型,扔圖片進去就可以了。
但是,現實往往是殘酷的。
你最需要了解的,是圖片不夠多的時候,怎麼辦。
這時候,很容易出現過擬合。
因為深度神經網路,屬於典型的複雜模型。
這個時候,可以嘗試以下幾個不同的方法:
首先,如果有可能,蒐集更多的帶標註圖片。這是最簡單的辦法,如果成本可以接受,你應該優先採用。
其次,使用資料增強(Data Augmentation)。名字聽起來很強大,其實無非是把原始的資料進行映象、剪裁、旋轉、扭曲等處理。這樣“新的”圖片與老圖片的標註肯定還是一樣的。但是圖片內容發生的變化,可以有效防止模型記住過多噪聲。
第三,使用遷移學習。
所謂遷移學習,就是利用別人訓練好的模型,保留其中從輸入開始的大多數層次(凍結保留其層次數量、神經元數量等網路結構,以及權重數值),只把最後的幾層敲掉,換上自己的幾層神經網路,對小規模資料做訓練。
上圖同樣來自於 François Chollet 的著作。
這種做法,用時少,成本低,效果還特別好。如果重新訓練,圖片數少,就很容易過擬合。但是用了遷移學習,過擬合的可能性就大大降低。
其原理其實很容易理解。
卷積神經網路的層次,越是靠近輸入位置,表達的特徵就越是細節;越到後面,就越巨集觀。
識別貓和狗,要從形狀邊緣開始;識別哆啦a夢和瓦力,也一樣要從形狀邊緣開始。因此模型的底層,可以被拿來使用。
你訓練的,只是最後幾層表徵方式。結構簡單,當然也就不需要這麼多資料了。
第四,引入 Dropout, Regularization 和 Early Stopping 等常規方法。注意這些方法不僅適用於影像資料。
以 Dropout 為例。假如一個模型因為複雜,所以記住了很多噪聲,那麼訓練的時候,每次都隨機將一定比例的神經元“扔掉”(設定權重為0),那麼模型的複雜度降低。而且因為隨機,又比降低層數與神經元個數的固化模型適用性更高。
文字
前面說過了,機器不認得文字,只認得數字。
所以,要對文字做二元分類,你需要把文字轉換成為數字。
這個過程,叫做向量化。
向量化的方式,有好幾種。大致上可以分成兩類:
第一類,是無意義轉換。也就是轉換的數字,只是個編號而已,本身並不攜帶其他語義資訊。
這一類問題,我們在《如何用Python和機器學習訓練中文文字情感分類模型?》中,已經非常詳細地介紹過了。
你需要做的,包括分詞(如果是中文)、向量化、去除停用詞,然後丟進一個分類模型(例如樸素貝葉斯,或者神經網路),直接獲取結果,加以評估。
但是,這個過程,顯然有大量的語義和順序資訊被丟棄了。
第二類,是有意義轉換。這時候,每個語言單元(例如單詞)轉換出來的數字,往往是個高維向量。
這個向量,你可以自己通過訓練來產生。
但是這種訓練,需要對海量語料進行建模。
建模的過程,成本很高,佔用龐大儲存空間,運算量極大。
因此更常見的做法,是使用別人通過大規模語料訓練後的結果。也就是我們曾經介紹過的詞嵌入預訓練模型。
具體內容,請參見《如何用Python處理自然語言?(Spacy與Word Embedding)》和《如何用 Python 和 gensim 呼叫中文詞嵌入預訓練模型?》。
注意如果你有多個預訓練模型可以選擇,那麼儘量選擇與你要解決任務的文字更為接近的那種。
畢竟預訓練模型來自於統計結果。兩種差別很大的語料,詞語在上下文中的含義也會有顯著差異,導致語義的刻畫不夠準確。
如果你需要在分類的過程中,同時考慮語義和語言單元順序等資訊,那麼你可以這樣做:
第一步,利用詞嵌入預訓練模型,把你的輸入語句轉化為張量,這解決了詞語的語義問題;
第二步,採用一維卷積神經網路(Conv1D)模型,或者迴圈神經網路模型(例如 LSTM),構造分類器。
注意這一步中,雖然兩種不同的神經網路結構,都可以應用。但是一般而言,處理二元分類問題,前者(卷積神經網路)表現更好。
因為卷積神經網路實際上已經充分考慮了詞語的順序問題;而迴圈神經網路用在此處,有些“大炮轟蚊子”。很容易發生過擬合,導致模型效果下降。
實施
如果你瞭解二元分類問題的整體流程,並且做好了模型的選擇,那麼實際的機器學習過程,是很簡單的。
對於大部分的普通機器學習問題,你都可以用 Scikit-learn 來呼叫模型。
注意其實每一個模型,都有引數設定的需要。但是對於很多問題來說,預設初始引數,就能帶來很不錯的執行結果。
Scikit-learn 雖好,可惜一直不能很好支援深度學習任務。
因而不論是影像還是文字分類問題,你都需要挑選一個好用的深度學習框架。
注意,目前主流的深度學習框架,很難說有好壞之分。
畢竟,在深度學習領域如此動盪激烈的競爭環境中,“壞”框架(例如功能不完善、效能低下)會很快被淘汰出局。
然而,從易用性上來說,框架之間確實有很大區別。
易用到了一種極致,便是蘋果的 Turi Create 。
從《如何用Python和深度神經網路識別影像?》和《如何用Python和深度神經網路尋找近似圖片?》這兩篇文章中,你應該有體會,Turi Create 在影像識別和相似度查詢問題上,已經易用到你自己都不知道究竟發生了什麼,任務就解決了。
但是,如果你需要對於神經網路的結構進行深度設定,那麼 Turi Create 就顯得不大夠用了。
畢竟,其開發的目標,是給蘋果移動裝置開發者賦能,讓他們更好地使用深度學習技術。
對於更通用的科研和實踐深度學習任務,我推薦你用 Keras 。
它已經可以把 Theano, Tensorflow 和 CNTK 作為後端。
對比上面那張深度學習框架全家福,你應該看到,Keras 覆蓋了 Google 和 微軟自家框架,幾乎佔領了深度學習框架界的半壁江山。
照這勢頭髮展下去,一統江湖也說不定哦。
為什麼 Keras 那麼厲害?
因為簡單易學。
簡單易學到,顯著拉低了深度學習的門檻。
就連 Tensorflow 的主力開發人員 Josh Gordon,也已經認為你根本沒必要去學習曾經的 Tensorflow 繁複語法了。
直接學 Keras ,用它完成任務,結束。
另外,使用深度學習,你可能需要 GPU 硬體裝置的支援。這東西比較貴。建議你採用租用的方式。
《如何用雲端 GPU 為你的 Python 深度學習加速?》提到的 FloydHub,租賃一個小時,大概需要1美元左右。註冊賬號就贈送你2個小時;
至於《如何免費雲端執行Python深度學習框架?》中提到的 Google Colab ,就更慷慨了——到目前為止,一直是免費試用。
喜歡請點贊。還可以微信關注和置頂我的公眾號“玉樹芝蘭”(nkwangshuyi)。
如果你對資料科學感興趣,不妨閱讀我的系列教程索引貼《如何高效入門資料科學?》,裡面還有更多的有趣問題及解法。