更新、更全的《機器學習》的更新網站,更有python、go、數據結構與算法、爬蟲、人工智能教學等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlpython
相信大家外出遊玩的時候,都不會帶上你的牛逼plus諾基亞手機出門,而是帶上你的智能手機給本身美美的拍上一張。當你用手機鏡頭對準人臉的時候,都會出現一個矩形框,以下圖所示(前方高能),那麼這個技術是怎麼作到的呢?算法
相機中的人臉定位技術用的是二分類技術。該技術流程以下圖所示。數據庫
如上圖所示,相機首先會將照片分割成一塊塊的圖像塊,一張照片每每會有成千上萬的圖像塊被切割出來。網絡
而後每個圖像塊都會通過人臉分類器去判別是不是人臉。人臉分類器是預先訓練好的分類器,相似於咱們以前講的手寫數字識別應用程序中的支持向量機分類器。若是人臉分類器預測該圖像塊爲人臉,相機則會在這個圖像塊中顯示出框的位置。數據結構
在人臉定位中,爲了解決因爲手機離人的距離不一樣,致使手機上顯示的人臉大小不一致的問題。手機在切割圖像的時候,並非只用一種尺寸的圖像塊切割圖像,而是有從小到大不少尺寸的圖像塊,所以保證了圖像塊切割圖像時能涵蓋幾乎各類大小的人臉。架構
因爲相機使用不一樣尺寸的圖像塊判別圖像塊是否爲人臉,所以會致使不一樣尺寸、不一樣位置的圖像塊可能同時都被判別爲是人臉,所以會有不少重疊框。對於該問題,一般在後期使用後處理融合技術,將這些框融合爲一個框。機器學習
在我國古代的時候,人們就對識圖認物有了必定的認知。《史記》中曾記載:趙高混淆是非;《艾子雜說》中記載:有人慾以鶻(hú,鷹屬猛禽)獵兔而不識鶻,買鳧(fú,鴨子)而去,逼鳧捉兔,成爲笑談。ide
現在千年以後深度學習技術,可讓避免讓咱們成爲識物盲?函數
曾經講到鳶尾花分類的時候,咱們給出了分類任務的兩個核心步驟:特徵提取和特徵分類。以下圖所示。
上圖咱們爲了減小麻煩,因此我也直接給出了手工提取特徵的圖像分類的過程,從圖中能夠看出在圖像分類過程當中,咱們主要停滯在了特徵提取的步驟,咱們該如何提取圖像的特徵,提取什麼特徵呢?若是要解決上述問題,咱們首先須要把本身當作計算機去看圖像。
圖像在計算機中的表示以下圖所示。
如上圖所示,若是將一副計算機眼中的圖放大,咱們能夠看到一幅圖像在計算機眼中就是一個由數字組成的矩形陣列,即矩陣,也正是如此圖像才能夠存儲在計算機中。對於矩陣內的每個元素,咱們稱之爲像素;而矩陣的行數和列數,咱們稱爲分辨率。咱們常常說的1280×720分辨率,值得就是這張圖由1280行、720列的像素組成的。反之,若是咱們給出一個數字組成的矩陣,而後將矩陣中的每一個元素轉換爲對應的顏色後,並在電腦屏幕上顯示出來,既能夠復原出這張圖像。
細心的同窗會發現矩陣中的每一個元素都是介於0-255之間的整數。對於上圖所示的黑白圖像,因爲只有明暗的區別,所以只須要一個數字就能夠表示不一樣的灰度,一般咱們使用0表示最暗的黑色,255表示最亮的白色,因此矩陣的每個元素都是介於0-255之間的整數。
如上圖所示,如今咱們最常看到的是彩色圖像,彩色圖像因爲使用(R,G,B)三個數字表示一個顏色,他表示用紅(R),綠(G),藍(B)三種基本顏色疊加的顏色,而且三種顏色也都是介於0-255之間的整數。因爲使用三種基本顏色疊加成顏色的明亮程度,如(255,0,0)表示純紅色、(136,200,255)表示天藍色,因此通常一張彩色圖像,須要使用一個由整數的立方體陣列來表示,這樣的立方體陣列咱們稱之爲三階張量。這個三階張量的長度與寬度即爲圖像的分辨率,高度爲3。對於黑白圖像,他實際上是高度爲1的三階張量。
現在咱們已經瞭解了計算機眼中的圖像,可是僅僅瞭解了圖像並無用。若是如今在你眼前有貓、小鳥和樹葉,咱們能夠想一想,咱們人類是如何對圖片分類的。
經過上圖,咱們很容易得出下表,經過「有沒有翅膀」和「有沒有眼睛」這兩個特徵對貓、鳥、和樹葉分類。如:沒有翅膀有眼睛的是貓、有翅膀又有眼睛的是鳥、沒有翅膀沒有眼睛的是樹葉。
特徵 | 貓 | 鳥 | 樹葉 |
---|---|---|---|
有沒有翅膀 | 沒有 | 有 | 沒有 |
有沒有眼睛 | 有 | 有 | 沒有 |
因爲圖像在計算機眼中是一個三階張量的東西(黑白圖像是特殊的三階張量),因此計算機並不知道圖像中的物體有沒有翅膀、有沒有眼睛。很早以前爲了讓計算機認識翅膀、認識眼睛,人們一般手工設計各類圖像特徵,如:設計翅膀圖畫的顏色、邊緣、紋理等性質,而後結合機器學習技術,達到物體識別的目的。
因爲圖像在計算機眼中能夠表示爲三階張量,從圖像中提取特徵,即對這個三階張量進行運算的過程。其中咱們最經常使用的運算是卷積。
卷積運算目前在圖像處理中有着普遍的應用,他如咱們熟知的加減乘除同樣也是一種數學運算。只是參加卷積運算的是向量、矩陣或三階張量。
如上圖所示,兩個向量的卷積仍然是一個向量。他的計算過程如上圖所示:
卷積結果的維數一般比長向量低,所以有時候咱們爲了使得卷積後的結果向量與原始長向量的長度一直,會在長向量的兩端補上一些0.對於如上圖所示的長向量\((5,4,3,2,1)\),咱們能夠將其兩端補零變成\((0,5,4,3,2,1,0)\),以後再進行卷積運算,獲得結果向量爲\((0,22,16,10,0)\)。
經過向量的卷積運算,咱們能夠定義矩陣的卷積運算,對於兩個形狀相同的矩陣,他們的內積是每一個對應位置的數字相乘以後的和,以下圖所示。
進行向量的卷積時,咱們只須要朝着一個方向移動;進行矩陣卷積時,咱們一般須要沿着橫向和縱向兩個方向滑動,以下圖所示。
定義矩陣的卷積以後,相似的也能夠定義三階張量的卷積,以下圖所示。進行三階張量的卷積時,當兩個張量的通道數相同時(下圖的圖像和卷積核都爲兩通道),滑動操做和矩陣卷積同樣,只須要在長和寬兩個方向進行,卷積的結果是一個通道數爲1的三階張量。
# 卷積計算 import tensorflow as tf sess = tf.InteractiveSession() input_x = tf.constant([ [ [[0., 2.], [8., 0.], [6., 8.], [6., 6.]], [[1., 9.], [2., 2.], [0., 4.], [8., 8.]], [[4., 6.], [2., 4.], [3., 2.], [0., 3.]], [[6., 3.], [4., 1.], [2., 2.], [3., 3.]], ] ], shape=[1, 4, 4, 2]) kernel = tf.constant([ [ [[1.], [0.]], [[0.], [-2.]], [[0.], [2.]], [[-1.], [0.]] ], ], shape=[2, 2, 2, 1]) conv2d = tf.nn.conv2d(input_x, kernel, strides=[ 1, 1, 1, 1], padding='VALID') (sess.run(conv2d)).reshape(3, 3)
array([[ 16., -4., -6.], [ 7., -1., -12.], [ -2., -2., -2.]], dtype=float32)
卷積運算在圖像處理中應用十分普遍,許多圖像特徵提取的方法都會用到卷積。以灰度圖爲例,灰度圖在計算機的眼中被表示爲一個整數的矩陣。若是咱們使用一個形狀較小的矩陣和這個圖像矩陣作卷積運算,就能夠獲得一個新的矩陣,這個新的矩陣則能夠當作是一副新的圖像。經過卷積運算獲得的新圖像有時候比原圖更清楚的表示了某些性質,咱們就能夠把他當作原圖像的一個特徵。而這裏使用的小矩陣稱爲卷積核。
經過卷積,咱們能夠從圖像中提取邊緣特徵,因此在沒有邊緣的比較平坦的區域(物體內部),圖像像素值的變化較小;因爲0偏暗、255偏亮,而橫向邊緣兩側(物體側邊的兩側)的像素差別明顯。以下圖所示,咱們利用了卷積核分別計算了原圖像上每一個3×3區域內左右像素或上下像素的差值(爲了將運算結果以圖像的形式展現出來,咱們對運算結果取了絕對值)。
上圖咱們使用了三列一、0、-1組成的卷積核與原圖像進行卷積運算,能夠從圖像中提取出豎向邊緣
上圖咱們使用了三行一、0、-1組成的卷積核,從圖像中提取出了橫向邊緣。
上一節,咱們學會了如何手工設計圖像特徵,經過手工設計特徵的過程能夠發現手工設計圖像特徵是很是慢的,甚至有時候手工設計的圖像特徵毫無心義,所以致使圖像分類的準確率曾經在一段時間內達到瓶頸。
# 2010-1017ImageNet挑戰賽最低錯誤率圖例 import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc') plt.style.use('ggplot') years = ['2010', '2011', '2012', '2013', '2014', '人類', '2015', '2016', '2017'] years_index = range(len(years)) error_rates = [28.2, 25.8, 16.4, 11.7, 7.3, 5.2, 4.9, 3.5, 2.3] plt.bar(years_index[:2], error_rates[:2], align='center', color='skyblue', label='傳統方法') plt.bar(years_index[2:5], error_rates[2:5], align='center', color='darkcyan', label='深度學習') plt.bar(years_index[5:6], error_rates[5:6], align='center', color='gray', label='人類') plt.bar(years_index[6:], error_rates[6:], align='center', color='darkcyan') plt.xticks(years_index, years, rotation=0, fontsize=13, fontproperties=font) plt.ylabel('分類錯誤率', fontproperties=font, fontsize=15) plt.title('2010-1017ImageNet挑戰賽最低錯誤率', fontproperties=font, fontsize=20) plt.savefig(fname='2010-1017ImageNet挑戰賽最低錯誤率圖例') plt.legend(prop=font) plt.show()
在2012年以後,深度神經網絡在Image Net挑戰賽(圖片識別挑戰賽)中大放異彩,如上圖所示,也由於深度神經網絡的加入,在2015年的Image Net挑戰賽中,微軟團隊研究的神經網絡架構將圖片識別的錯誤率下降到了4.9%,首次超過了人類的正確率,而且在2017年,圖片分類錯誤率也達到了2.3%,這也是舉辦Image Net挑戰賽的最後一年,由於深度神經網絡已經很好地解決了圖片分類的問題。
深度神經網絡之因此有這麼強大的能力,就是由於他解決了傳統圖像分類中手工提取特徵的缺點,而深度神經網絡自己能夠自動從圖像中學習有效的特徵。以下圖所示看,以前傳統的圖像分類系統中,特徵提取和分類是兩個獨立的步驟,而深度神經網絡將二者集成在了一塊兒。從這個角度來講,深度神經網絡並非在圖像分類上作出某種創新,而是對傳統的圖像分類系統作出了改進與加強。
一個深度神經網絡一般由多個順序鏈接的層構成。
上述深度神經網絡的流程能夠理解成咱們平常學習英語的過程
其中句子的語義和句子所表達的思想,即爲高級別的抽象的特徵。
上圖所示的即是一個神經網絡架構,該神將網絡架構是由2012年得到Image Net挑戰賽冠軍的Alex Net神經網絡架構。這個神經網絡架構出現了卷積層、ReLU非線性激活層、池化層、全鏈接層、softmax歸一化指數層等概念,以後會逐一介紹。
這個神經網絡由5個卷積層和3個全聯接層組成。五個卷積層位於輸入層右側,依次對圖像進行變化以提取特徵。每一個卷積層以後都會有一個ReLU非線性激活層完成非線性變換。上圖5個卷積層中第1、2、五個卷積層以後鏈接有最大池化層,能夠用來下降特徵圖分辨率。在上述流程中,通過5個卷積層和池化層以後,特徵圖轉換爲4096維的特徵向量;再通過兩次全鏈接層和ReLU層的變換以後,成爲最終的特徵向量;最後通過一個全鏈接層和一個softmax歸一化指數層以後,便可獲得對圖片所屬類別的預測。
卷積層是深度神經網絡在處理圖像時十分經常使用的一種層。當一個深度神經網絡以卷積層爲主體時,咱們也會把這種深度神經網絡稱爲卷積神經網絡。卷積層主要的做用是使用卷積運算對原始圖像或者上一層的特徵進行變換的層,爲了從圖像中提取多種形式的特徵,咱們一般使用多個卷積覈對輸入圖像進行不一樣的卷積操做,以下圖所示。
# 卷積計算 import tensorflow as tf sess = tf.InteractiveSession() input_x = tf.constant([ [ [[0., 2.], [8., 0.], [6., 8.], [6., 6.]], [[1., 9.], [2., 2.], [0., 4.], [8., 8.]], [[4., 6.], [2., 4.], [3., 2.], [0., 3.]], [[6., 3.], [4., 1.], [2., 2.], [3., 3.]], ] ], shape=[1, 4, 4, 2]) kernel = tf.constant([ [ [[[1., 1., 1.], [0., 1., 1.]], [[0., 2., -1.], [-2., 0., 0.]]], [[[0., -1., 0.], [2., -1., -2.]], [[-1., -2., 0.], [0., 0., -1.]]] ], ], shape=[2, 2, 2, 3]) conv2d = tf.nn.conv2d(input_x, kernel, strides=[ 1, 1, 1, 1], padding='VALID') (sess.run(conv2d))
array([[[[ 16., 4., -26.], [ -4., 16., -6.], [ -6., 6., -8.]], [[ 7., 0., -8.], [ -1., -8., -6.], [-12., 15., -11.]], [[ -2., -3., 1.], [ -2., 3., -1.], [ -2., -5., -2.]]]], dtype=float32)
從上圖能夠看出一個卷積核能夠獲得一個通道爲1的三階張量,多個卷積核就能夠獲得多個通道爲1的三階張量結果。咱們把這些結果做爲不一樣的通道組合起來,便可以獲得一個新的三階張量,這個三階張量的通道數爲咱們使用的卷積核的個數。因爲每個通道都是從原圖像中提取的一種特徵,咱們有時候也會把這個三階張量稱爲特徵圖,這個特徵圖就是卷積層的輸出。
也就是說若是一個神經網絡有多個卷積層,第一個卷積層以圖像做爲輸入,而以後的卷積層會之前面的層輸出的特徵圖做爲輸入。
在講解卷積層的時候,咱們假設圖像的分辨率是4*4,可是若是圖像或者特徵圖的分辨率很大,因爲卷積核會滑過圖像或特徵圖的每個像素,那麼卷積層的計算開銷會很大。爲了解決這個問題,咱們通常會使用池化層下降特徵圖的分辨率。最大池化層的步驟以下圖所示。
如上圖所示:
對每個區塊取最大值的池化層,咱們稱之爲最大池化層;對於取平均值的池化層,咱們稱之爲平均池化層。上圖通過池化層處理,特徵圖的長和寬都會減少到原來的一半,即特徵圖的分辨率減少了一半,大大減少了計算開銷。
當圖像通過多層卷積層處理以後,會將獲得的特徵圖轉換爲特徵向量。全鏈接層的做用則是對這個特徵向量作處理。
在全鏈接層中,咱們會使用若干維數相同的向量與輸入向量(特徵向量)作內積操做,而且將全部結果拼成一個向量做爲輸出。即假設全鏈接層以一個向量\(X=(x_1,x_2,\cdots,x_n)\)做爲輸入,咱們會用\(K\)個維數相同的參數(K通常等於類別個數)向量\(W_k=(w_{k1},w_{k2},\cdots,w_{kn})\)與\(X\)作內積運算,而且在每一個結果上面加上標量\(b_k\)(偏置單元),即完成
\(y_k=X·W_k+b_k,k=1,2,3,\cdots,K\)的運算。最後咱們將\(K\)個標量結果\(y_k\)組成向量\(Y=(y_1,y_2,\cdots,y_K)\)做爲這一層的輸出。
歸一化指數層(softmax layer)通常是分類網絡的最後一層,它以一個長度和類別個數相等的特徵向量做爲輸入(通常這個特徵向量是全鏈接層的輸出),而後輸出圖像屬於各個類別的機率。
再講非線性激活層以前,咱們首先要回過頭去看咱們以前的卷積層和全鏈接層,咱們能夠發現卷積層和全鏈接層中的運算都是關於自變量的一次函數,即所謂的線性函數。而線性函數有一個性質,若干個線性函數複合時,只是自變量在不斷的變化,複合後的函數仍然是線性的。也就是說,若是不使用非線性激活層,咱們只是將卷積層和全鏈接層直接堆疊起來,那麼他們對輸入圖片產生的效果就能夠被一個全鏈接層替代。如此作的話,咱們雖然堆疊了不少層,但每一層的變換效果實際上被合併到了一塊兒。
若是在每次線性計算後,咱們再進行一次非線性運算,那麼每次變換的效果將能夠保留。神經網絡中的非線性激活層方式有不少種,可是他們的基本形式都是對特徵圖或特徵向量中的每個元素,使用某種你非線性函數進行轉換,而後獲得輸出。
Sigmoid函數是較爲原始的激活層使用的方法,能夠在卷積層將數據擴大以後,把數據壓縮在0-1之間。
\[ s(x)=\frac{1}{1+e^{-x}} \]
# Sigmoid激活函數圖例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = (1/(1+np.e**(-x))) y2 = np.sign(x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('Sigmoid(x)', fontsize=20) plt.show()
雙曲正切函數相比較激活函數能夠減輕梯度消失的影響。
\[ tanh(x)=\frac{e^x-e^{-x}}{e^{-x}+e^{-x}} \]
# 雙曲正切激活函數圖例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = np.tanh(x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('tanh(x)', fontsize=20) plt.show()
ReLU激活函數以下圖所示,ReLu會使一部分神經元的輸出爲0,這樣就形成了網絡的稀疏性,而且減小了參數的相互依存關係,緩解了過擬合問題的發生。而且ReLU激活函數將小於零的元素變成零,而保持其他元素的值不變。所以ReLU的計算很是簡單,因此他的計算速度每每比其餘非線性激活層快不少,而且他在實際應用中的效果很是好,所以在深度神經網絡中被普遍的使用。
\[ ReLU(x)= \begin{cases} 0, & x<0 \\ x, & x\geq{0} \end{cases} \]
# ReLU激活函數圖例 import numpy as np import matplotlib.pyplot as plt x = np.linspace(-10, 10, 100) y = np.where(x < 0, 0, x) plt.hlines(0, -10, 10, alpha=0.3, linestyles='--') plt.plot(x, y, c='r') plt.title('ReLU(x)', fontsize=20) plt.show()
傳統的分類器須要通過訓練才能夠區分屬於不一樣類別的特徵向量,深度神經網絡也須要經過訓練才能學習出有效的圖像特徵,二者相同之處都是在訓練的過程當中找打最佳參數的組合。在線性分類器中,參數包括線性函數的全部係數;在神經網絡中,卷積層中全部的卷積核的元素值、全鏈接層全部內積運算的係數都是參數。爲了將4個特徵的鳶尾花數據分類,咱們只須要訓練5個參數;而在Alex Net中,須要學習的參數多達六千萬個,其難度遠高於線性分類器的訓練。所以爲了解決神經網絡參數多,難訓練的問題,科學家們提出了反向傳播算法,以下圖所示。
反向傳播算法的流程爲:
隨着科技的發展,圖像分類技術在平常生活中已經到處可見,有着普遍的應用,如人臉識別、圖像搜索等。2014年,香港中文大學團隊的工做使得機器在人臉識別任務上的表現第一次超越了人類,今後「人臉識別」也成爲了深度學習算法着力研究的任務之一,並在不斷的發展和演進中變成了最早實現落地和改變咱們生活的深度學習應用之一。接下來咱們主要介紹圖像你分類計數在人臉識別上的應用。
人臉識別是從一張數字圖像或一幀視頻中,由「找到人臉」到「認出人臉」的過程,其中「認出人臉」就是一個圖像分類的任務。人臉識別的整個流程能夠包括如下幾個步驟:人臉檢測、特徵提取、人臉對比和數據保存。
話很少說,上圖!
經過本章的對神經網絡的描述,咱們學習瞭如下幾個知識點: