前面幾篇文章可以算作是機(jī)器學(xué)習(xí)中計算機(jī)視覺處理的范疇但并未真正涉及到學(xué)習(xí)二字,現(xiàn)在開始準(zhǔn)備寫一系列真正的學(xué)習(xí)相關(guān)的文章,還是主要和圖片識別相關(guān),包括這個入門篇,手寫數(shù)字識別,時尚商品識別,魚類甚至是細(xì)分魚的品種的識別。
寫這篇文章也希望讓我媽也能看懂機(jī)器學(xué)習(xí),所以力求從不同視角用大白話把這件事說清楚,文中也會盡量避免出現(xiàn)數(shù)學(xué)公式,如果我媽都能看懂,那么非技術(shù)人員也就能看懂。正如一篇近日刷屏的文章提到那樣,真正的AI并未實現(xiàn),現(xiàn)在無非是在做一些比較高效的統(tǒng)計概率分析工作而已,但是這已經(jīng)足夠?qū)Ω餍懈鳂I(yè)帶來深遠(yuǎn)影響,前提是非技術(shù)人員也能明白機(jī)器學(xué)習(xí)是怎么回事,它能做什么,能給業(yè)務(wù)場景創(chuàng)造什么樣的價值。
機(jī)器學(xué)習(xí)打開了一個新世界的大門,我們不需告訴機(jī)器如何做,只需要給大量樣本,它就能自動從中發(fā)掘規(guī)律,這也是一個哲學(xué)問題,改變?nèi)祟愃伎紗栴}的方式,將關(guān)注點從數(shù)學(xué)科學(xué)轉(zhuǎn)移到自然科學(xué)上,觀察不確定的未知世界,用統(tǒng)計信息而非邏輯來分析實驗結(jié)果。
因為后續(xù)文章會用到TensorFlow來計算,所以這里先提一下。Google開源的TensofFlow是目前最流行的深度學(xué)習(xí)框架,在計算機(jī)視覺,音頻處理,自然語言處理,推薦系統(tǒng)等場景下都有廣泛應(yīng)用,雖然深度學(xué)習(xí)框架有很多選擇,但我相信選擇最主流的框架是最安全的。
TensorFlow 按照字面理解就是張量(Tensor)流(Flow), 表示通過張量的流動來表達(dá)計算。下圖簡單的解釋了TensorFlow的工作原理,它就象我媽用的壓面機(jī)一樣,把和好的面團(tuán)塞進(jìn)去,攪拌幾下,可以擠壓出不同形狀的面條: 刀削面,掛面等,粗細(xì)寬窄隨人。TensorFlow 的內(nèi)核是數(shù)據(jù)流圖(Data Flow Graphs), 所有的變量和計算都是存儲在這個圖上,構(gòu)建完這張圖后,打開一個會話(Session)就可以運(yùn)行整張圖了。

Tensor到底是什么?
首先要明白什么是張量(Tensor)。這個名詞起源于力學(xué),它最初是用來表示彈性介質(zhì)中各點應(yīng)力狀態(tài)的,愛因斯坦的廣義相對論就是用張量語言來表述的,后來張量也成為了數(shù)學(xué)的一個重要分支學(xué)科。解釋張量之前,我們再看幾個名詞: 標(biāo)量(Scalar), 向量(Vector)和矩陣(Matrix), 用我媽可以看懂的語言來描述,標(biāo)量是點(即0階張量),向量是線(即1階張量),矩陣是平面(即2階張量),不僅于此,張量還可以有無窮多階的形式存在,3階張量就想象成三維空間吧,N階張量自然就是N維空間了。
之所以引入張量,是因為這是讓機(jī)器理解世間萬物的基礎(chǔ),任何物體用機(jī)器的語言描述都是多維的特征向量,為了形象的說明這個道理我們還是拿Playboy美女Lena圖片來做分析。

寫兩行代碼打開圖片直接打印出來
import cv2
image = cv2.imread('C:/dev/lena_std.jpg')
print(image)

原來在機(jī)器的理解中,這張圖片就是一大堆的數(shù)字的張量形式表達(dá)。每行有三個數(shù)字代碼的是每個像素點的顏色,RGB(紅綠藍(lán))三種顏色。
再寫一行代碼看看數(shù)據(jù)結(jié)構(gòu)
print(image.shape)
得到輸出結(jié)果是(512, 512, 3), 這就是一個3階張量啊,說明這個圖片的高和寬都是512像素,有三個顏色通道。如果是黑白圖片的話只有一個顏色通道,那么用2階張量來描述即可。如果有多張彩色圖片則可以用4階張量來描述,加多一個圖片編號的維度即可。
最后寫一行代碼看看數(shù)據(jù)結(jié)構(gòu)的長度
print(image.size)
打印結(jié)果是786432,等于512x512x3, 多階數(shù)據(jù)扁平化以后TensorFlow才能線性的使用它。
機(jī)器到底是怎么學(xué)習(xí)的?
現(xiàn)在已經(jīng)了解一個對象如何用數(shù)字化呈現(xiàn)讓機(jī)器可以理解和計算,可是到底機(jī)器學(xué)習(xí)是怎么個學(xué)習(xí)法? 如何讓機(jī)器能夠通過自我學(xué)習(xí)判斷一張圖片是貓還是狗呢? 簡單來說就是通過已知數(shù)據(jù)預(yù)測未來,我買榴蓮比較多,買多了自然就有經(jīng)驗什么樣的榴蓮好吃。

要挑選榴蓮第一個關(guān)心的問題是熟了沒有,不能買生榴蓮也不能買熟過頭的,所以先看開裂情況,要找開裂了一點點但裂口不能太大的,然后聞一聞氣味是否誘人,如果有發(fā)酵的味道就是熟過頭了。還可以捏一下尖刺,如果捏不動就是太生。
第二個問題是果肉多不多,主要看形狀,挑比較渾圓的可能肉包多一些。
第三個問題是肉質(zhì),挑果肉小的,顏色黃的,不能有水分。也可以聽聲辨認(rèn),狠狠地拍下果殼,邦邦聲的就好吃,哼哼聲的就不好。當(dāng)然了,挑選的時候帶好創(chuàng)可貼。
有了這些經(jīng)驗以后我就能預(yù)測一個榴蓮是否好吃,不是百分百準(zhǔn)確但是概率比較高,如果要讓機(jī)器學(xué)會挑選榴蓮就要把我的經(jīng)驗用機(jī)器能夠理解的語言傳遞給機(jī)器。因此我定義了三個評估指標(biāo),還定義了決定每個評估指標(biāo)的關(guān)鍵因子。
成熟度: (裂口[無/小/大],氣味[無/香/發(fā)酵],硬度[軟/硬/適中])
飽滿度: (形狀[渾圓/長條/異形])
肉質(zhì): (顏色[黃/白],肉包大小[大/中/小], 聲音[邦邦/哼哼],濕度[干燥/多水])
根據(jù)這些規(guī)則機(jī)器要對水果店里的所有榴蓮掃描一次收集全部數(shù)據(jù),通過計算得到一個量化分值,對榴蓮品質(zhì)的好壞進(jìn)行預(yù)測,分值越高的好吃的概率就越高。三個評估指標(biāo)對于判斷一個榴蓮好壞的影響力有大有效小,如果我覺得肉質(zhì)最重要,成熟度其次,飽滿度最次,那么大概會有一個類似這樣的公式:
overall_score = 成熟度 * 0.3 + 飽滿度 * 0.2 + 肉質(zhì) * 0.5
這里我假設(shè)了幾個權(quán)重值,因為肉質(zhì)最重要因此權(quán)重最高,所有權(quán)重值的總和為1
同樣對于成熟度這個評估指標(biāo)而言,關(guān)鍵因子也有主次之分,可能味道最靠譜,其次看裂口,最后看硬度,那么成熟度的分值大概也有個公式:
maturity_score = 氣味 * 0.6 + 裂口 * 0.2 + 硬度 * 0.1
飽滿度和肉質(zhì)的計算也類似,都代入overall_score的計算就是完整的公式。
overall_score = (味道 * 0.6 + 裂口 * 0.2 + 硬度 * 0.1) * 0.3 + (形狀 * 1) * 0.2 + (顏色 * 0.3 + 肉包大小 * 0.2 + 聲音 * 0.2 + 濕度 * 0.3) * 0.5
這個公式就是用來預(yù)測榴蓮好壞的模型,我以前購買過的榴蓮所擁有的數(shù)據(jù)就是訓(xùn)練集,未來要預(yù)測的榴蓮數(shù)據(jù)就是測試集,訓(xùn)練集數(shù)量越多代表經(jīng)驗越豐富,預(yù)測也越準(zhǔn)確。假設(shè)我以前購買過100個榴蓮,現(xiàn)在給它們編號生成100條記錄,包括所有特征向量,還有我對這些榴蓮好壞的一個經(jīng)驗評估分(好榴蓮3分,普通榴蓮2分,差榴蓮1分),也就是我把榴蓮的好壞分成三個檔次,把這個問題轉(zhuǎn)化成了一個分類問題。
這個表格里有些字段屬性可能空缺,比如榴蓮沒有裂口的話很可能就聞不到氣味,看不到果肉顏色,更無從觀察果肉的濕度。你可能也會注意到有的特征維度是冗余的,即從其它特征維度能推導(dǎo)出這些維度的屬性,比如裂口大則果殼肯定是軟的,那么有可能這個冗余特征是一個無效因子。

注意上表中所有特征向量的屬性值在實際計算的時候也都會用數(shù)字來量化,比如形狀(圓型=1,長條=2, 異形=3)
不過先等一等,如果就用上面這個固定規(guī)律來計算榴蓮好壞算什么機(jī)器學(xué)習(xí),所謂機(jī)器學(xué)習(xí)是要通過訓(xùn)練集的數(shù)據(jù)對公式的參數(shù)不斷進(jìn)行調(diào)整以求最大化逼近目標(biāo)。也就是說,機(jī)器要通過訓(xùn)練集數(shù)據(jù)調(diào)參優(yōu)化,overall_score的計算公式里那些權(quán)重值都是我拍腦袋定出來的,一定不是最優(yōu)組合,機(jī)器需要發(fā)現(xiàn)規(guī)律找到最合理的權(quán)重設(shè)置對未來的目標(biāo)榴蓮做出最精準(zhǔn)的預(yù)測。
前面寫了這么多廢話才引入下面的機(jī)器學(xué)習(xí)第一公式,也是機(jī)器學(xué)習(xí)中最常見的公式,實際上就是線性分類函數(shù)(linear classifier),訓(xùn)練分類器的目標(biāo)就是求出(w,b)。

一般用向量形式表達(dá)簡化為

w就是前面提到的權(quán)重設(shè)置的d維向量,b是bias, 即一個偏差值。為什么還需要這個偏差值呢? 如果沒有偏差值,無論權(quán)重如何,在x=0時分類分值始終為0。這樣所有分類器的直線都不得不穿過原點(左圖),這顯然不合理,實際上絕大多數(shù)情況下這條線肯定不過原點。偏差值允許分類器代表的直線左右平移(右圖),它影響輸出,但并不和原始數(shù)據(jù)產(chǎn)生關(guān)聯(lián)。在右圖中,w就是直線的斜率,而b則是直線的位移。

線性分類器主要由兩個部分組成:
一個是評分函數(shù)(score function),它是一個從原始圖像到類別分值的映射函數(shù),就是我計算榴蓮overall_score的那個函數(shù)。另一個是損失函數(shù)(loss function),它是用來量化預(yù)測得到的分類標(biāo)簽的得分與真實標(biāo)簽之間的一致性, 評估算法的好壞,損失函數(shù)越小則預(yù)測結(jié)果越準(zhǔn)。所以線性分類器可以轉(zhuǎn)化成為一個最優(yōu)化問題,在最優(yōu)化過程中,通過更新score function的參數(shù)來最小化loss function。上面的右圖中,所有紅點到直線的距離之和就是損失函數(shù)的誤差。我們的目標(biāo)不是縮小某一個點和直線間的最大誤差,而是所有點和直線間的誤差最小,因此引入了方差的評估方式,即數(shù)據(jù)集上的L2損失。

將方差值除以樣本的數(shù)量就可以得到均方差,也就是以前的文章中用來對比圖像的指標(biāo)MSE
下面兩張圖中,左邊更符合預(yù)期,但是如果簡單的計算所有點到直線的距離之和就變成右邊損失更小,如果用方差來評估會發(fā)現(xiàn)左邊更優(yōu)。

用我媽能看懂的話來說,要讓機(jī)器找到最準(zhǔn)確的規(guī)律,判斷一個好的榴蓮到底是看熟不熟更重要,還是看果肉多不多重要,或者是看肉質(zhì)好壞重要,三者之中的權(quán)重到底如何設(shè)定最佳,判斷熟不熟到底是觀察裂口靠譜還是聞味道或者試硬度靠譜,這幾個特征的權(quán)重又該如何設(shè)置最好。當(dāng)然了,我媽定義好榴蓮的標(biāo)準(zhǔn)和我可能不一樣,她也可以自己對過往的榴蓮數(shù)據(jù)做標(biāo)注打上分?jǐn)?shù),重新訓(xùn)練數(shù)據(jù)再去預(yù)測出符合她預(yù)期的結(jié)果。
用官話來總結(jié),我定義了一個監(jiān)督式機(jī)器學(xué)習(xí)的任務(wù),因為規(guī)則是我提供的,標(biāo)注也是我提供的。同時我已經(jīng)生成了一個有標(biāo)注的樣本,包含一百條歷史購買榴蓮的數(shù)據(jù)信息,其中既有榴蓮的特征(氣味,硬度,顏色等),也有榴蓮品質(zhì)的標(biāo)注(1到3分)。我希望通過一個評分函數(shù)的模型定義了特征和標(biāo)注之間的關(guān)系,讓機(jī)器逐漸學(xué)習(xí)和發(fā)現(xiàn)特征與標(biāo)注的關(guān)系完善模型,這是機(jī)器學(xué)習(xí)的核心。最終目標(biāo)是對未來要購買的榴蓮進(jìn)行預(yù)測,找到最優(yōu)的權(quán)重和偏差組合,讓預(yù)測結(jié)果盡可能逼近真相。也就是讓預(yù)測的分值和我人工判斷的分值,也就是讓損失函數(shù)最小化, 損失函數(shù)的評估是L2方差。如果我預(yù)測榴蓮是需要分為三種離散值(好/普通/差),這就是一個分類模型,如果我預(yù)測榴蓮需要給出連續(xù)的分值(10分最高,0分最低,允許小數(shù)),這就是一個回歸模型。
最后說一下機(jī)器如何逼近真相將損失降到最低,先想想猜數(shù)字游戲,讓朋友想一個1到100的數(shù)字不要說出來,我們?nèi)ゲ逻@個數(shù)字的時候可能會用二分法,先問這個數(shù)字是否小于50,小于50的話是否小于25,大于50的話是否大于75,就這么經(jīng)過幾次迭代離答案越來越近。機(jī)器也是這么多次迭代找到答案的,關(guān)鍵點在于如何高效的找到答案,尤其是當(dāng)我們有幾十萬數(shù)百萬數(shù)據(jù)集的時候。
回歸問題可以映射到下圖中的曲線函數(shù)找最低點問題,最低點就是損失函數(shù)最小的解。通過計算整個數(shù)據(jù)集中 w 每個可能值的損失函數(shù)來找到收斂點這種方法效率太低,所以通過梯度下降法來逼近,梯度具備兩個特征: 方向和大小,即往哪個方向移動,每次移動的步長有多大。步長太小迭代速度慢,步長過大則可能沖過頭了。所以要看梯度的傾斜度來決定,如果梯度斜率很大,下降的很快,就縮小步長,否則可以放心使用較大的步長。
雖然樣本數(shù)可能非常多但是其中有很多冗余樣本,所以拿樣本的子集來回歸可以加快學(xué)習(xí)速度,一個折中的方案是采取小批量隨機(jī)梯度下降法(SGD)來回歸, 每次迭代只抽樣拿少量樣本(10-1000)

Reference:
1. Google 十幾天前新出的 Machine Learning Crash Course
2. 香港科技大學(xué)TensorFlow課件