譯者 | 朱先忠?
審校 | 孫淑娟?
深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)最近受到了大量關(guān)注,原因在于它是當(dāng)今語音識(shí)別、人臉檢測(cè)、語音控制、自動(dòng)駕駛汽車、腦腫瘤檢測(cè)技術(shù)背后的技術(shù),而這些在20年前并不屬于我們生活的內(nèi)容。盡管這些神經(jīng)網(wǎng)絡(luò)看起來很復(fù)雜,但它們也像人類一樣地學(xué)習(xí)——通過各種案例來進(jìn)行。只不過,神經(jīng)網(wǎng)絡(luò)是使用大量數(shù)據(jù)集進(jìn)行訓(xùn)練,并通過多個(gè)網(wǎng)絡(luò)層和多次迭代進(jìn)行優(yōu)化,以便獲得最佳的運(yùn)算結(jié)果而已。?
在過去20年中,計(jì)算能力和數(shù)據(jù)量的指數(shù)級(jí)增長為深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)創(chuàng)造了完美的發(fā)展條件。盡管我們?cè)跈C(jī)器學(xué)習(xí)和人工智能等華而不實(shí)的術(shù)語上磕磕絆絆;但其實(shí),這些技術(shù)只不過是線性代數(shù)和微積分與計(jì)算的結(jié)合結(jié)果罷了。?
Keras、PyTorch和TensorFlow等框架有助于定制深度神經(jīng)網(wǎng)絡(luò)的艱難構(gòu)建、訓(xùn)練、驗(yàn)證和部署過程。在現(xiàn)實(shí)生活中,創(chuàng)建深度學(xué)習(xí)應(yīng)用程序時(shí),這幾款框架顯然成為首選。?
盡管如此,有時(shí)后退一步繼續(xù)前進(jìn)是至關(guān)重要的,我的意思是真正理解框架幕后發(fā)生的事情。在本文中,我們將通過僅使用NumPy這個(gè)基礎(chǔ)框架來創(chuàng)建一個(gè)深度神經(jīng)網(wǎng)絡(luò)并將其應(yīng)用于圖像分類問題來實(shí)現(xiàn)這一點(diǎn)。在計(jì)算過程中,你可能會(huì)迷失在某個(gè)地方,特別是在與微積分相關(guān)的反向傳播環(huán)節(jié),但不要擔(dān)心。在框架處理過程中,對(duì)過程的直覺比計(jì)算更重要。?
在本文中,我們將構(gòu)建一個(gè)圖像分類(貓或無貓)神經(jīng)網(wǎng)絡(luò),該網(wǎng)絡(luò)將使用兩組共1652張圖像進(jìn)行訓(xùn)練。其中,852張圖像來自??狗和貓圖像數(shù)據(jù)集??的貓圖像,另外800張來自Unsplash隨機(jī)圖像集的??隨機(jī)圖像??。開始時(shí),首先需要將圖像轉(zhuǎn)換為數(shù)組,我們將通過將原始尺寸減小到128x128像素來加快計(jì)算速度,因?yàn)槿绻覀儽3衷夹螤?,則需要很長時(shí)間來訓(xùn)練模型。所有這些128x128圖像都有三個(gè)顏色層(紅色、綠色和藍(lán)色);當(dāng)混合時(shí),這些顏色會(huì)達(dá)到圖像的原始顏色。每幅圖像上的128x128像素中的每一個(gè)像素都具有從0到255的紅色、綠色和藍(lán)色值范圍,這些值是我們圖像矢量中的值。因此,在我們的計(jì)算中,我們將處理1652幅圖像的共計(jì)128x128x3個(gè)矢量。
要在網(wǎng)絡(luò)中運(yùn)行上述矢量,需要通過將三層顏色堆疊成單個(gè)數(shù)組來重構(gòu)它,如下圖所示。然后,我們將獲得一個(gè)(49152,1652)大小的向量,該向量將通過使用1323個(gè)圖像向量來訓(xùn)練模型,并通過使用訓(xùn)練后的模型預(yù)測(cè)圖像分類(貓或無貓)來對(duì)其進(jìn)行測(cè)試。在將這些預(yù)測(cè)與圖像的真實(shí)分類標(biāo)簽進(jìn)行比較之后,將有可能估計(jì)模型的準(zhǔn)確性。?
圖像1:將圖像轉(zhuǎn)換為矢量的過程?
隨著訓(xùn)練向量的解釋,現(xiàn)在是討論網(wǎng)絡(luò)架構(gòu)的時(shí)候了,如圖2所示。由于訓(xùn)練向量中使用了49152個(gè)值,模型的輸入層必須具有相同數(shù)量的節(jié)點(diǎn)(或神經(jīng)元)。然后,在輸出層之前有三個(gè)隱藏層,這將是該圖片中貓的概率。在現(xiàn)實(shí)生活中的模型中,通常有3個(gè)以上的隱藏層,因?yàn)榫W(wǎng)絡(luò)需要更深入才能在大數(shù)據(jù)環(huán)境中表現(xiàn)良好。?
在本文中,我們僅使用了三個(gè)隱藏層,這是因?yàn)樗鼈儗?duì)于簡(jiǎn)單的分類模型來說已經(jīng)足夠好。盡管該架構(gòu)只有4層(輸出層不計(jì)算在內(nèi)),但該代碼可以通過使用層的維度作為訓(xùn)練函數(shù)的參數(shù)來創(chuàng)建更深層的神經(jīng)網(wǎng)絡(luò)。?
圖2:網(wǎng)絡(luò)架構(gòu)?
到現(xiàn)在為止,我們已經(jīng)解釋了圖像向量和所采用的網(wǎng)絡(luò)架構(gòu);接下來,我們將使用優(yōu)化算法在圖3所示的梯度下降算法中進(jìn)行描述。同樣,如果您不能立即完成所有步驟,請(qǐng)不要擔(dān)心,因?yàn)楸疚纳院髮⒃诰幋a部分詳細(xì)介紹其圖中所示的每個(gè)步驟。?
圖3:訓(xùn)練過程?
首先,我們啟動(dòng)網(wǎng)絡(luò)的參數(shù)。這些參數(shù)是圖像2中顯示的節(jié)點(diǎn)的每個(gè)連接的權(quán)重(w)和偏差(b)。在代碼中,更容易理解每個(gè)權(quán)重和偏差參數(shù)的工作方式以及它們的初始化方式。稍后,當(dāng)這些參數(shù)初始化后,是時(shí)候運(yùn)行正向傳播塊并在最后一次激活中應(yīng)用sigmoid函數(shù)以獲得概率預(yù)測(cè)。?
在我們的例子中,這是一只貓出現(xiàn)在照片中的概率。隨后,我們通過交叉熵成本(一種廣泛用于優(yōu)化分類模型的損失函數(shù))將我們的預(yù)測(cè)與圖像的真實(shí)標(biāo)簽(貓或非貓)進(jìn)行比較。最后,在計(jì)算出成本的情況下,我們通過反向傳播模塊將其返回,以計(jì)算其相對(duì)于參數(shù)w和b的梯度。隨著損失函數(shù)相對(duì)于w和b所具有的梯度已經(jīng)為我們所掌握,可以通過對(duì)各個(gè)梯度求和來更新參數(shù),因?yàn)樗鼈冎赶蚴箵p失函數(shù)最小化的w和b值的方向。?
由于目標(biāo)是使損失函數(shù)最小化,所以該循環(huán)應(yīng)該經(jīng)過預(yù)定義的迭代次數(shù),朝著損失函數(shù)的最小值邁出一小步。在某一點(diǎn)上,參數(shù)將停止改變,因?yàn)楫?dāng)最小值接近時(shí),梯度會(huì)趨于零。?
1. 加載數(shù)據(jù)?
首先,需要加載庫。除了使用keras.preprrocessing.image將圖像轉(zhuǎn)換為向量之外,只需要導(dǎo)入Numpy、Pandas和OS三個(gè)庫模塊,而另一方面我們使用sklearn.model_selection將圖像向量拆分為訓(xùn)練向量和測(cè)試向量?jī)刹糠帧?/span>
數(shù)據(jù)必須從兩個(gè)文件夾下加載:cats和random_images。這可以通過獲取所有文件名并構(gòu)建每個(gè)文件的路徑來完成。然后,只需合并數(shù)據(jù)幀中的所有文件路徑,并創(chuàng)建一個(gè)條件列“is_cat”。如果該路徑位于cats文件夾中,則值為1;否則值為0。?
有了路徑數(shù)據(jù)集,是時(shí)候通過分割圖像來構(gòu)建我們的訓(xùn)練和測(cè)試向量了;其中80%用于訓(xùn)練,20%用于測(cè)試。Y表示特征的真實(shí)標(biāo)簽,而X表示圖像的RGB值,因此X被定義為數(shù)據(jù)幀中具有圖像文件路徑的列,然后使用load_img函數(shù)加載它們,target_size設(shè)置為128x128像素,以便實(shí)現(xiàn)更快的計(jì)算。最后,使用img_to_array函數(shù)將圖像轉(zhuǎn)換為數(shù)組。這些是X_train和X_test向量的形狀:?
圖4:X_train和X_test向量的形狀?
2. 初始化參數(shù)?
由于線性函數(shù)是z=w*x+b并且網(wǎng)絡(luò)具有4個(gè)層,所以要初始化的參數(shù)向量是w1、w2、w3、w4、b1、b2、b3和b4。在代碼中,這是通過在層維度列表的長度上循環(huán)來完成的——稍后將定義;但是在這里它是一個(gè)硬編碼列表,其中包含網(wǎng)絡(luò)中每個(gè)層中的神經(jīng)元數(shù)量。?
參數(shù)w和b必須使用不同的初始化方式:w必須初始化為隨機(jī)小數(shù)字矩陣,b必須初始化為零矩陣。這是因?yàn)槿绻覀儗?quán)重初始化為零,則權(quán)重wrt(相對(duì)于)損失函數(shù)的導(dǎo)數(shù)將全部相同,因此后續(xù)迭代中的值將始終相同,隱藏層將全部對(duì)稱,導(dǎo)致神經(jīng)元只學(xué)習(xí)相同的幾個(gè)特征。因此,我們把權(quán)重初始化為隨機(jī)數(shù),以打破這種對(duì)稱性,從而允許神經(jīng)元學(xué)習(xí)不同的特征。需要注意的是,偏置可以初始化為零,因?yàn)閷?duì)稱性已經(jīng)被權(quán)重打破,并且神經(jīng)元中的值都將不同。?
最后,為了理解參數(shù)向量初始化時(shí)定義的形狀,必須知道權(quán)重參與矩陣乘法,而偏差參與矩陣和運(yùn)算(還記得z1=w1*x+b1嗎?)。得益于Python廣播技術(shù),可以使用不同大小的數(shù)組進(jìn)行矩陣加法運(yùn)算。另一方面,矩陣乘法只有在形狀兼容時(shí)才可能進(jìn)行運(yùn)算,如(m,n)x(n,k)=(m,k)。這意味著,第一個(gè)陣列上的列數(shù)需要與第二個(gè)陣列上行數(shù)匹配,最終矩陣將具有陣列1的行數(shù)和陣列2的列數(shù)。圖5顯示了神經(jīng)網(wǎng)絡(luò)上使用的所有參數(shù)向量的形狀。?
圖5:參數(shù)向量的形狀?
在第一層中,當(dāng)我們將w1參數(shù)向量乘以原始49152個(gè)輸入值時(shí),我們需要w1形狀為(20,49152)*(49152,1323)=(20,1323),這是第一個(gè)隱藏層激活的形狀。b1參數(shù)與矩陣乘法的結(jié)果相加(記住z1=w1*x+b1),因此我們可以將(20,1)數(shù)組添加到乘法的(20,1323)結(jié)果中,因?yàn)閺V播會(huì)自動(dòng)考慮不匹配的形狀。這一邏輯繼續(xù)到下一層,因此我們可以假設(shè)w(l)形狀的公式是(節(jié)點(diǎn)數(shù)量層l+1,節(jié)點(diǎn)數(shù)量層l),而b(l)的公式為(節(jié)點(diǎn)數(shù)量,層l+1)。?
最后,我們對(duì)權(quán)重向量初始化進(jìn)行重要分析。我們應(yīng)該將隨機(jī)初始化值除以正在初始化w參數(shù)向量的各個(gè)層上節(jié)點(diǎn)數(shù)量的平方根。例如,輸入層有49152個(gè)節(jié)點(diǎn),因此我們將隨機(jī)初始化的參數(shù)除以√49152,即222,而第一個(gè)隱藏層有20個(gè)節(jié)點(diǎn);所以,我們將隨機(jī)初始的w2參數(shù)除以√20,即結(jié)果值為45。初始化必須保持較小,因?yàn)檫@是隨機(jī)梯度下降的要求。?
3. 正向傳播?
現(xiàn)在,參數(shù)向量已經(jīng)被初始化,現(xiàn)在我們可以進(jìn)行正向傳播了。該正向傳播將線性操作z=w*x+b與ReLU激活相結(jié)合,直到最后一層,當(dāng)sigmoid激活函數(shù)替代ReLU激活函數(shù)時(shí),我們得到最后一次激活的概率。線性運(yùn)算的輸出通常用字母“z”表示,稱為預(yù)激活參數(shù)。因此,預(yù)激活參數(shù)z將是ReLU和sigmoid激活的輸入。?
在輸入層之后,給定層L上的線性操作將是z[L]=w[L]*a[L-1]+b[L],使用前一層的激活值而不是數(shù)據(jù)輸入x。線性操作和激活函數(shù)的參數(shù)都將存儲(chǔ)在緩存列表中,用作稍后在反向傳播塊上計(jì)算梯度的輸入。?
因此,首先定義線性正向函數(shù):?
接下來,我們來定義Sigmoid和ReLU兩個(gè)激活函數(shù)。圖6顯示了這兩個(gè)函數(shù)的圖形示意。其中,Sigmoid激活函數(shù)通常用于二類分類問題,以預(yù)測(cè)二元變量的概率。這是因?yàn)镾形曲線使大多數(shù)值接近0或1。因此,我們將僅在網(wǎng)絡(luò)的最后一層使用Sigmoid激活函數(shù)來預(yù)測(cè)貓出現(xiàn)在圖片中的概率。?
另一方面,如果輸入為正,ReLU函數(shù)將直接輸出;否則,將輸出零。這是一個(gè)非常簡(jiǎn)單的操作,因?yàn)樗鼪]有任何指數(shù)運(yùn)算,有助于加快內(nèi)層的計(jì)算速度。此外,與tanh和sigmoid函數(shù)不同,使用ReLU作為激活函數(shù)降低了消失梯度問題的可能性。?
值得注意的是,ReLU激活函數(shù)不會(huì)同時(shí)激活所有節(jié)點(diǎn),因?yàn)榧せ詈笏胸?fù)值將變?yōu)榱?。在整個(gè)網(wǎng)絡(luò)中設(shè)置一些0值很重要,因?yàn)樗黾恿松窠?jīng)網(wǎng)絡(luò)的一個(gè)理想特性——稀疏性;這意味著網(wǎng)絡(luò)具有更好的預(yù)測(cè)能力和更少的過度擬合。畢竟,神經(jīng)元正在處理有意義的信息部分。像我們的例子中一樣,可能存在一個(gè)特定的神經(jīng)元可以識(shí)別貓耳朵;但是,如果圖像是人或風(fēng)景的話,顯然應(yīng)該將其設(shè)置為0。?
圖6:Sigmoid和ReLU激活函數(shù)圖形示意?
現(xiàn)在可以實(shí)現(xiàn)全部的激活函數(shù)了。?
最后,是時(shí)候根據(jù)前面預(yù)先計(jì)劃的網(wǎng)絡(luò)架構(gòu)在一個(gè)完整的函數(shù)中整合上面的激活函數(shù)了。首先,創(chuàng)建緩存列表,將第一次激活函數(shù)設(shè)置為數(shù)據(jù)輸入(訓(xùn)練向量)。由于網(wǎng)絡(luò)中存在兩個(gè)參數(shù)(w和b),因此可以將層的數(shù)量定義為參數(shù)字典長度的一半。然后,該函數(shù)在除最后一層外的所有層上循環(huán);在最后一層應(yīng)用線性前向函數(shù),隨后應(yīng)用的是ReLU激活函數(shù)。?
4. 交叉熵?fù)p失函數(shù)?
損失函數(shù)通過將預(yù)測(cè)的概率(最后一次激活的結(jié)果)與圖像的真實(shí)標(biāo)簽進(jìn)行比較來量化模型對(duì)給定數(shù)據(jù)的性能。如果網(wǎng)絡(luò)使用數(shù)據(jù)進(jìn)行學(xué)習(xí),則每次迭代后成本(損失函數(shù)的結(jié)果)必須降低。在分類問題中,交叉熵?fù)p失函數(shù)通常用于優(yōu)化目的,其公式如下圖7所示:?
圖7:神經(jīng)網(wǎng)絡(luò)的成本(損失函數(shù)的輸出結(jié)果)示意圖?
在本例中,我們使用NumPy定義交叉熵成本函數(shù):?
5. 反向傳播?
在反向傳播模塊中,我們應(yīng)該在網(wǎng)絡(luò)上從右向左移動(dòng),計(jì)算與損失函數(shù)相關(guān)的參數(shù)梯度,以便稍后更新。就像在前向傳播模塊中一樣的順序,接下來,我們首先介紹一下線性反向傳播,然后是sigmoid和relu,最后通過一個(gè)函數(shù)整合網(wǎng)絡(luò)架構(gòu)上的所有功能。?
對(duì)于給定的層L,線性部分為z[L]=w[L]*a[L-1]+b[L]。假設(shè)我們已經(jīng)計(jì)算了導(dǎo)數(shù)dZ[L],即線性輸出的成本導(dǎo)數(shù),對(duì)應(yīng)的公式稍后很快就會(huì)給出。但首先讓我們看看下圖8中dW[L]、dA[L-1]和db[L]的導(dǎo)數(shù)公式,以便首先實(shí)現(xiàn)線性后向函數(shù)。?
圖8:成本相關(guān)權(quán)重、偏差和先前激活函數(shù)的導(dǎo)數(shù)?
這些公式是交叉熵成本函數(shù)相對(duì)于權(quán)重、偏差和先前激活(a[L-1])的導(dǎo)數(shù)。本文不打算進(jìn)行導(dǎo)數(shù)計(jì)算,但它們已經(jīng)在我的另一篇文章??《走向數(shù)據(jù)科學(xué)》??一文中進(jìn)行了介紹。
定義線性向后函數(shù)需要使用dZ作為輸入,因?yàn)樵诜聪騻鞑ブ芯€性部分位于sigmoid或relu向后激活函數(shù)之后。在下一段代碼中,將計(jì)算dZ,但為了在正向傳播上遵循相同的函數(shù)實(shí)現(xiàn)邏輯,首先應(yīng)用線性反向函數(shù)。?
在執(zhí)行梯度計(jì)算之前,必須從前一層加載參數(shù)權(quán)重、偏置和激活,所有這些都在線性傳播期間存儲(chǔ)在緩存中。參數(shù)m最初來自交叉熵成本公式,是先前激活函數(shù)的向量大小,可以通過previous_activation.shape[1]獲得。然后,可以使用NumPy實(shí)現(xiàn)梯度公式的矢量化計(jì)算。在偏置梯度中,keepdims=True和axis=1參數(shù)是必要的,因?yàn)榍蠛托枰谙蛄康男兄羞M(jìn)行,并且必須保持向量的原始維度,這意味著dB將具有與dZ相同的維度。?
成本wrt對(duì)線性輸出(dZ)公式的導(dǎo)數(shù)如圖9所示,其中g(shù)’(Z[L])代表激活函數(shù)的導(dǎo)數(shù)。?
圖9——線性輸出成本的導(dǎo)數(shù)。?
因此,必須首先計(jì)算Sigmoid函數(shù)和ReLU函數(shù)的導(dǎo)數(shù)。在ReLU中,如果該值為正,則導(dǎo)數(shù)為1;否則,未定義。但是,為了計(jì)算ReLU后向激活函數(shù)中的dZ,有可能只復(fù)制去激活向量(因?yàn)閐activation * 1 = dactivation),并在z為負(fù)時(shí)將dZ設(shè)置為0。對(duì)于Sigmoid函數(shù)s,其導(dǎo)數(shù)為s*(1-s),將該導(dǎo)數(shù)乘以去激活,矢量dZ在Sigmoid向后函數(shù)中實(shí)現(xiàn)。?
現(xiàn)在可以實(shí)現(xiàn)linear_activation_backward函數(shù)。?
首先,必須從緩存列表中檢索線性緩存和激活緩存。然后,對(duì)于每一次激活,首先運(yùn)行activation_backward函數(shù),獲得dZ,然后將其作為輸入,與線性緩存結(jié)合,用于linear_backward函數(shù)。最后,函數(shù)返回dW、dB和dprevious_activation梯度。請(qǐng)記住,這是正向傳播的逆序,因?yàn)槲覀冊(cè)诰W(wǎng)絡(luò)上從右向左傳播。?
現(xiàn)在,我們可以為整個(gè)網(wǎng)絡(luò)實(shí)現(xiàn)后向傳播函數(shù)了。該函數(shù)將從最后一層L開始向后迭代所有隱藏層。因此,代碼需要計(jì)算dAL;dAL是上次激活時(shí)成本函數(shù)的導(dǎo)數(shù),以便將其用作sigmoid激活函數(shù)的linear_activation_backward函數(shù)的輸入。dAL的公式如下圖10所示:?
圖10:最后激活函數(shù)的成本導(dǎo)數(shù)?
現(xiàn)在,實(shí)現(xiàn)后向傳播函數(shù)的一切都設(shè)置到位。?
首先,創(chuàng)建梯度字典。網(wǎng)絡(luò)的層數(shù)是通過獲取緩存字典的長度來定義的,因?yàn)槊總€(gè)層在前向傳播塊期間都存儲(chǔ)了其線性緩存和激活緩存,因此緩存列表長度與層數(shù)相同。稍后,該函數(shù)將遍歷這些層的緩存,以檢索線性激活反向函數(shù)的輸入值。此外,真正的標(biāo)簽向量(Y_train)被重構(gòu)為與上一次激活的形狀相匹配的維度,因?yàn)檫@是dAL計(jì)算中一個(gè)除以另一個(gè)的要求,即代碼的下一行。?
創(chuàng)建current_cache對(duì)象并將其設(shè)置為檢索最后一層的線性緩存和激活緩存(請(qǐng)記住,python索引從0開始,因此最后一層是n_layers-1)。然后,到最后一層,在linear_activation_backward函數(shù)上,激活緩存將用于sigmoid_backward函數(shù),而線性緩存將作為linear_backward的輸入。最后,該函數(shù)收集函數(shù)的返回值并將它們分配給梯度字典。在dA的情況下,因?yàn)橛?jì)算的梯度公式來自于先前的激活,所以有必要在索引上使用n_layer-1來分配它。在該代碼塊之后,計(jì)算網(wǎng)絡(luò)的最后一層的梯度。?
按照網(wǎng)絡(luò)的反向順序,下一步是在線性層向relu層上反向循環(huán)并計(jì)算其梯度。但是,在反向循環(huán)期間,linear_activation_backward函數(shù)必須使用“relu”參數(shù)而不是“sigmoid”,因?yàn)樾枰獮槠溆鄬诱{(diào)用relu_backward函數(shù)。最后,該函數(shù)返回計(jì)算的所有層的dA、dW和dB梯度,并完成反向傳播。?
6. 參數(shù)更新?
隨著梯度的計(jì)算,我們將通過用梯度更新原始參數(shù)以向成本函數(shù)的最小值移動(dòng)來結(jié)束梯度下降。?
該函數(shù)通過在層上循環(huán)并將w和b參數(shù)的原始值減去學(xué)習(xí)率輸入乘以相應(yīng)的梯度來實(shí)現(xiàn)。乘以學(xué)習(xí)率是控制每次更新模型權(quán)重時(shí)響應(yīng)于估計(jì)誤差改變網(wǎng)絡(luò)參數(shù)w和b的程度的方法。?
7. 預(yù)處理矢量?
最后,我們實(shí)現(xiàn)了計(jì)算梯度下降優(yōu)化所需的所有函數(shù),從而可以對(duì)訓(xùn)練和測(cè)試向量進(jìn)行預(yù)處理,為訓(xùn)練做好準(zhǔn)備。?
初始化函數(shù)的layers_dimensions輸入必須進(jìn)行硬編碼,這是通過創(chuàng)建一個(gè)包含每個(gè)層中神經(jīng)元數(shù)量的列表來實(shí)現(xiàn)的。隨后,必須將X_train和X_test向量展平,以作為網(wǎng)絡(luò)的輸入,如圖11所示。這可以通過使用NumPy函數(shù)重構(gòu)來完成。此外,有必要將X_train和X_test值除以255,因?yàn)樗鼈兪且韵袼貫閱挝坏模ǚ秶鷱?到255),并且將值標(biāo)準(zhǔn)化為0到1是一個(gè)很好的做法。這樣,數(shù)字會(huì)更小,計(jì)算速度更快。最后,Y_train和Y_test被轉(zhuǎn)換為數(shù)組,并被展平。?
這些是訓(xùn)練和測(cè)試向量的最終形狀打印結(jié)果:?
圖11:訓(xùn)練和測(cè)試向量的形狀大小?
8. 訓(xùn)練?
有了所有的函數(shù),只需要將它們組織成一個(gè)循環(huán)來創(chuàng)建訓(xùn)練迭代即可。?
但首先,創(chuàng)建一個(gè)空列表來存儲(chǔ)cross_entropy_cost函數(shù)的成本輸出,并初始化參數(shù),因?yàn)檫@必須在迭代之前完成一次,因?yàn)檫@些參數(shù)將由梯度更新。?
現(xiàn)在,在輸入的迭代次數(shù)上創(chuàng)建循環(huán),以正確的順序調(diào)用實(shí)現(xiàn)的函數(shù):l_layer_model_forward、cross_entropy_cost、l_layer_mmodel_backward和update_parameters。最后,是一個(gè)每50次迭代或最后一次迭代打印一次成本的條件語句。?
調(diào)用函數(shù)2500次迭代的形式如下:?
調(diào)用訓(xùn)練函數(shù)的代碼?
下面輸出展示了成本從第一次迭代的0.69下降到最后一次迭代的0.09。?
圖12:成本輸出值越來越小?
這意味著,在NumPy中開發(fā)的梯度下降函數(shù)優(yōu)化了訓(xùn)練過程中的參數(shù),這必將導(dǎo)致更好的預(yù)測(cè)結(jié)果,從而降低了成本。?
訓(xùn)練結(jié)束以后,接下來我們可以檢查訓(xùn)練后的模型是如何預(yù)測(cè)測(cè)試圖像標(biāo)簽的。?
9. 預(yù)測(cè)?
通過使用訓(xùn)練的參數(shù),該函數(shù)運(yùn)行X_test向量的正向傳播以獲得預(yù)測(cè),然后將其與真標(biāo)簽向量Y_test進(jìn)行比較以返回精度。?
圖13:調(diào)用預(yù)測(cè)函數(shù)?
該模型在測(cè)試圖像上檢測(cè)貓的準(zhǔn)確率達(dá)到了77%??紤]到僅使用NumPy構(gòu)建網(wǎng)絡(luò),這已經(jīng)是一個(gè)相當(dāng)不錯(cuò)的準(zhǔn)確性了。將新圖像添加到訓(xùn)練數(shù)據(jù)集、增加網(wǎng)絡(luò)的復(fù)雜性或使用數(shù)據(jù)增強(qiáng)技術(shù)將現(xiàn)有訓(xùn)練圖像轉(zhuǎn)換為新圖像都是提高準(zhǔn)確性的可能方案。?
最后,值得再次強(qiáng)調(diào)的是,當(dāng)我們深入數(shù)學(xué)基礎(chǔ)時(shí),準(zhǔn)確性并不是重點(diǎn)。這正是本文所強(qiáng)調(diào)的。努力學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)的基礎(chǔ)知識(shí)將為以后深入學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)應(yīng)用的迷人世界奠定扎實(shí)的基礎(chǔ)。真誠希望您繼續(xù)深入下去!?
譯者介紹?
朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計(jì)算機(jī)教師,自由編程界老兵一枚。?
原文標(biāo)題:??Behind the Scenes of a Deep Learning Neural Network for Image Classification??,作者:Bruno Caraffa?