更新、更全的《機器學習》的更新網站,更有python、go、數據結構與算法、爬蟲、人工智能教學等着你: https://www.cnblogs.com/nickchen121/p/11686958.html
深度學習-圖像識別
一、人臉定位
相信你們外出游玩的時候,都不會帶上你的牛逼plus諾基亞手機出門,而是帶上你的智能手機給自己美美的拍上一張。當你用手機鏡頭對准人臉的時候,都會出現一個矩形框,如下圖所示(前方高能),那么這個技術是怎么做到的呢?
相機中的人臉定位技術用的是二分類技術。該技術流程如下圖所示。
如上圖所示,相機首先會將照片分割成一塊塊的圖像塊,一張照片往往會有成千上萬的圖像塊被切割出來。
然后每一個圖像塊都會經過人臉分類器去判別是否是人臉。人臉分類器是預先訓練好的分類器,類似於我們之前講的手寫數字識別應用程序中的支持向量機分類器。如果人臉分類器預測該圖像塊為人臉,相機則會在這個圖像塊中顯示出框的位置。
在人臉定位中,為了解決由於手機離人的距離不同,導致手機上顯示的人臉大小不一致的問題。手機在切割圖像的時候,並不是只用一種尺寸的圖像塊切割圖像,而是有從小到大很多尺寸的圖像塊,因此保證了圖像塊切割圖像時能涵蓋幾乎各種大小的人臉。
由於相機使用不同尺寸的圖像塊判別圖像塊是否為人臉,因此會導致不同尺寸、不同位置的圖像塊可能同時都被判別為是人臉,因此會有很多重疊框。對於該問題,通常在后期使用后處理融合技術,將這些框融合為一個框。
二、手工提取特征的圖像分類
2.1 識圖認物
在我國古代的時候,人們就對識圖認物有了一定的認知。《史記》中曾記載:趙高指鹿為馬;《艾子雜說》中記載:有人欲以鶻(hú,鷹屬猛禽)獵兔而不識鶻,買鳧(fú,鴨子)而去,逼鳧捉兔,成為笑談。
如今千年之后深度學習技術,可以讓避免讓我們成為識物盲?
2.2 傳統分類系統的特征提取
曾經講到鳶尾花分類的時候,我們給出了分類任務的兩個核心步驟:特征提取和特征分類。如下圖所示。
上圖我們為了減少麻煩,所以我也直接給出了手工提取特征的圖像分類的過程,從圖中可以看出在圖像分類過程中,我們主要停滯在了特征提取的步驟,我們該如何提取圖像的特征,提取什么特征呢?如果要解決上述問題,我們首先需要把自己看成計算機去看圖像。
2.3 計算機眼中的圖像
圖像在計算機中的表示如下圖所示。
如上圖所示,如果將一副計算機眼中的圖放大,我們可以看到一幅圖像在計算機眼中就是一個由數字組成的矩形陣列,即矩陣,也正是如此圖像才可以存儲在計算機中。對於矩陣內的每一個元素,我們稱之為像素;而矩陣的行數和列數,我們稱為分辨率。我們經常說的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的三階張量。
2.4 什么是圖像特征?
如今我們已經了解了計算機眼中的圖像,但是僅僅了解了圖像並沒有用。如果現在在你眼前有貓、小鳥和樹葉,我們可以想想,我們人類是如何對圖片分類的。
通過上圖,我們很容易得出下表,通過“有沒有翅膀”和“有沒有眼睛”這兩個特征對貓、鳥、和樹葉分類。如:沒有翅膀有眼睛的是貓、有翅膀又有眼睛的是鳥、沒有翅膀沒有眼睛的是樹葉。
特征 | 貓 | 鳥 | 樹葉 |
---|---|---|---|
有沒有翅膀 | 沒有 | 有 | 沒有 |
有沒有眼睛 | 有 | 有 | 沒有 |
由於圖像在計算機眼中是一個三階張量的東西(黑白圖像是特殊的三階張量),所以計算機並不知道圖像中的物體有沒有翅膀、有沒有眼睛。很早之前為了讓計算機認識翅膀、認識眼睛,人們通常手工設計各種圖像特征,如:設計翅膀圖畫的顏色、邊緣、紋理等性質,然后結合機器學習技術,達到物體識別的目的。
由於圖像在計算機眼中可以表示為三階張量,從圖像中提取特征,即對這個三階張量進行運算的過程。其中我們最常用的運算是卷積。
2.5 卷積運算
卷積運算目前在圖像處理中有着廣泛的應用,他如我們熟知的加減乘除一樣也是一種數學運算。只是參加卷積運算的是向量、矩陣或三階張量。
如上圖所示,兩個向量的卷積仍然是一個向量。他的計算過程如上圖所示:
- 我們首先將兩個向量的第一個元素對齊,並截去長向量中多於的元素,然后計算這兩個維數相同的向量的內積,並將算得的結果作為結果向量的第一個元素。
- 我們將短向量向下滑動一個元素,從長向量中截去不能與之對應的元素,並計算內積作為結果向量的第二個元素。
- 重復“滑動-截取-計算內積”這個過程,直到短向量的最后一個元素與長向量的最后一個元素對齊為止。
卷積結果的維數通常比長向量低,因此有時候我們為了使得卷積后的結果向量與原始長向量的長度一直,會在長向量的兩端補上一些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)
2.6 利用卷積提取圖像特征
卷積運算在圖像處理中應用十分廣泛,許多圖像特征提取的方法都會用到卷積。以灰度圖為例,灰度圖在計算機的眼中被表示為一個整數的矩陣。如果我們使用一個形狀較小的矩陣和這個圖像矩陣做卷積運算,就可以得到一個新的矩陣,這個新的矩陣則可以看成是一副新的圖像。通過卷積運算得到的新圖像有時候比原圖更清楚的表示了某些性質,我們就可以把他看成原圖像的一個特征。而這里使用的小矩陣稱為卷積核。
通過卷積,我們可以從圖像中提取邊緣特征,所以在沒有邊緣的比較平坦的區域(物體內部),圖像像素值的變化較小;由於0偏暗、255偏亮,而橫向邊緣兩側(物體側邊的兩側)的像素差異明顯。如下圖所示,我們利用了卷積核分別計算了原圖像上每個3×3區域內左右像素或上下像素的差值(為了將運算結果以圖像的形式展示出來,我們對運算結果取了絕對值)。
上圖我們使用了三列1、0、-1組成的卷積核與原圖像進行卷積運算,可以從圖像中提取出豎向邊緣
上圖我們使用了三行1、0、-1組成的卷積核,從圖像中提取出了橫向邊緣。
三、基於神經網絡的圖像分類
3.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挑戰賽的最后一年,因為深度神經網絡已經很好地解決了圖片分類的問題。
深度神經網絡之所以有這么強大的能力,就是因為他解決了傳統圖像分類中手工提取特征的缺點,而深度神經網絡本身可以自動從圖像中學習有效的特征。如下圖所示看,之前傳統的圖像分類系統中,特征提取和分類是兩個獨立的步驟,而深度神經網絡將兩者集成在了一起。從這個角度來說,深度神經網絡並不是在圖像分類上做出某種創新,而是對傳統的圖像分類系統做出了改進與增強。
3.2 深度神經網絡的架構
一個深度神經網絡通常由多個順序連接的層構成。
- 第一層一般是以圖像為輸入的輸入層,通過某種特定的運算從圖像中提取特征
- 接下來每一層以前一層提取的特征為輸入,通過特定形式的變換,得到一個更為復雜的特征
- 重復上一步,對這種特征特定形式的變換進行累加,將原始圖片轉換為高層次的抽象的特征(因此賦予了神經網絡強大的特征提取能力)
上述深度神經網絡的流程可以理解成我們日常學習英語的過程
- 通過對字母的組合,得到單詞
- 通過單詞的組合,得到句子
- 通過句子的分析,了解句子的語義
- 通過語義的分析,獲得句子所表達的思想
其中句子的語義和句子所表達的思想,即為高級別的抽象的特征。
上圖所示的便是一個神經網絡架構,該神將網絡架構是由2012年獲得Image Net挑戰賽冠軍的Alex Net神經網絡架構。這個神經網絡架構出現了卷積層、ReLU非線性激活層、池化層、全連接層、softmax歸一化指數層等概念,之后會逐一介紹。
這個神經網絡由5個卷積層和3個全聯接層組成。五個卷積層位於輸入層右側,依次對圖像進行變化以提取特征。每個卷積層之后都會有一個ReLU非線性激活層完成非線性變換。上圖5個卷積層中第一、二、五個卷積層之后連接有最大池化層,可以用來降低特征圖分辨率。在上述流程中,經過5個卷積層和池化層之后,特征圖轉換為4096維的特征向量;再經過兩次全連接層和ReLU層的變換之后,成為最終的特征向量;最后經過一個全連接層和一個softmax歸一化指數層之后,即可得到對圖片所屬類別的預測。
3.3 卷積層
卷積層是深度神經網絡在處理圖像時十分常用的一種層。當一個深度神經網絡以卷積層為主體時,我們也會把這種深度神經網絡稱為卷積神經網絡。卷積層主要的作用是使用卷積運算對原始圖像或者上一層的特征進行變換的層,為了從圖像中提取多種形式的特征,我們通常使用多個卷積核對輸入圖像進行不同的卷積操作,如下圖所示。
# 卷積計算
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的三階張量結果。我們把這些結果作為不同的通道組合起來,即可以得到一個新的三階張量,這個三階張量的通道數為我們使用的卷積核的個數。由於每一個通道都是從原圖像中提取的一種特征,我們有時候也會把這個三階張量稱為特征圖,這個特征圖就是卷積層的輸出。
也就是說如果一個神經網絡有多個卷積層,第一個卷積層以圖像作為輸入,而之后的卷積層會以前面的層輸出的特征圖作為輸入。
3.4 池化層
在講解卷積層的時候,我們假設圖像的分辨率是4*4,但是如果圖像或者特征圖的分辨率很大,由於卷積核會滑過圖像或特征圖的每一個像素,那么卷積層的計算開銷會很大。為了解決這個問題,我們一般會使用池化層降低特征圖的分辨率。最大池化層的步驟如下圖所示。
如上圖所示:
- 首先我們將特征圖按通道分開,然后對於每個通道對應的矩陣,將其切割成若干個大小相等的正方形小塊。上圖我們將4×4的矩陣切割成4個2×2的正方形小塊。
- 切割矩陣之后,對每個正方形小塊取最大值和平均值,並將結果組成一個新的矩陣。
- 將所有通道的結果矩陣按原順序堆疊形成一個三階張量,這個三階張量就是池化層的輸出。
對每一個區塊取最大值的池化層,我們稱之為最大池化層;對於取平均值的池化層,我們稱之為平均池化層。上圖經過池化層處理,特征圖的長和寬都會減小到原來的一半,即特征圖的分辨率減小了一半,大大減小了計算開銷。
3.5 全連接層
當圖像經過多層卷積層處理之后,會將得到的特征圖轉換為特征向量。全連接層的作用則是對這個特征向量做處理。
在全連接層中,我們會使用若干維數相同的向量與輸入向量(特征向量)做內積操作,並且將所有結果拼成一個向量作為輸出。即假設全連接層以一個向量\(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)\)作為這一層的輸出。
3.6 歸一化指數層
歸一化指數層(softmax layer)一般是分類網絡的最后一層,它以一個長度和類別個數相等的特征向量作為輸入(一般這個特征向量是全連接層的輸出),然后輸出圖像屬於各個類別的概率。
3.7 非線性激活層
再講非線性激活層之前,我們首先要回過頭去看我們之前的卷積層和全連接層,我們可以發現卷積層和全連接層中的運算都是關於自變量的一次函數,即所謂的線性函數。而線性函數有一個性質,若干個線性函數復合時,只是自變量在不斷的變化,復合后的函數仍然是線性的。也就是說,如果不使用非線性激活層,我們只是將卷積層和全連接層直接堆疊起來,那么他們對輸入圖片產生的效果就可以被一個全連接層替代。如此做的話,我們雖然堆疊了很多層,但每一層的變換效果實際上被合並到了一起。
如果在每次線性計算后,我們再進行一次非線性運算,那么每次變換的效果將可以保留。神經網絡中的非線性激活層方式有很多種,但是他們的基本形式都是對特征圖或特征向量中的每一個元素,使用某種你非線性函數進行轉換,然后得到輸出。
3.7.1 Sigmoid函數
Sigmoid函數是較為原始的激活層使用的方法,可以在卷積層將數據擴大之后,把數據壓縮在0-1之間。
# 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()
3.7.2 雙曲正切函數
雙曲正切函數相比較激活函數可以減輕梯度消失的影響。
# 雙曲正切激活函數圖例
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()
3.7.3 ReLU函數
ReLU激活函數如下圖所示,ReLu會使一部分神經元的輸出為0,這樣就造成了網絡的稀疏性,並且減少了參數的相互依存關系,緩解了過擬合問題的發生。並且ReLU激活函數將小於零的元素變成零,而保持其余元素的值不變。因此ReLU的計算非常簡單,所以他的計算速度往往比其他非線性激活層快很多,並且他在實際應用中的效果非常好,因此在深度神經網絡中被廣泛的使用。
# 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中,需要學習的參數多達六千萬個,其難度遠高於線性分類器的訓練。因此為了解決神經網絡參數多,難訓練的問題,科學家們提出了反向傳播算法,如下圖所示。
4.0.4 反向傳播算法
反向傳播算法的流程為:
- 將訓練圖片輸入網絡中,經過逐層的計算,得到最終預測的結果
- 將預測結果和正確答案進行對比,如果預測結果不夠好,那么會從最后一層開始,逐層調整神經網絡的參數,使得網絡對這個訓練樣本能夠做出更好的預測
- 具體的調整算法有隨機梯度下降(此處不多贅述)
五、圖像分類應用——人臉識別
隨着科技的發展,圖像分類技術在日常生活中已經處處可見,有着廣泛的應用,如人臉識別、圖像搜索等。2014年,香港中文大學團隊的工作使得機器在人臉識別任務上的表現第一次超越了人類,從此“人臉識別”也成為了深度學習算法着力研究的任務之一,並在不斷的發展和演進中變成了最先實現落地和改變我們生活的深度學習應用之一。接下來我們主要介紹圖像你分類計數在人臉識別上的應用。
5.1 人臉識別的流程
人臉識別是從一張數字圖像或一幀視頻中,由“找到人臉”到“認出人臉”的過程,其中“認出人臉”就是一個圖像分類的任務。人臉識別的整個流程可以包括以下幾個步驟:人臉檢測、特征提取、人臉對比和數據保存。
- 人臉檢測:人臉檢測就是對含有用戶臉部的圖像檢測,找到人臉所在的位置、人臉角度等信息,人臉檢測就是我們本章最早提出的人臉定位的問題。也就是完成“看到”的過程。
- 特征提取:特征提取可以通過對人臉檢測到的人臉進行分析,得到人臉相應的特征,如五官等特點。也就是完成“看得懂”的過程
- 人臉對比:人臉對比則是拿特征提取提取的特征與數據庫中已經記錄的人像(如身份證照片)以一定的方法相比對。也就是完成“和誰像”的過程。
- 數據保存:這些分析結果最終將會保存, 服務於最終的實際應用場景。
5.2 人臉識別應用場景
話不多說,上圖!
- 無人便利店
- 銀行取錢
- 刷臉消費
- 人臉布控系統
六、小結
通過本章的對神經網絡的描述,我們學習了以下幾個知識點:
- 我們了解了看起來高大上的卷積運算,並了解了如何使用卷積運算提取圖像特征。
- 由於手工設計特征的局限性較大,所以本章重點介紹了如何使用深度神經網絡進行圖像分類。
- 在神經網絡中,我們主要介紹的是卷積神經網絡架構,並且介紹了卷積神經網絡架構中的卷積層、池化層、全連接層、非線性激活層和會議華指數層。
- 由於神經網絡相比較傳統的分類器,有較多的參數,為了解決訓練難的問題,我們可以利用反向傳播算法進行網絡訓練。
- 最后,我們介紹了神將網絡的圖像分類目前在日常生活中的應用。