深度學習入門教程:手把手帶你用Numpy實現卷積神經網絡(一)

2020-12-05 愛學習愛AI

本教程由深度學習中文社區(Studydl.com)持續發布與更新, 教程中完整代碼已上傳至github上, 可關注我百家號後發送消息"CNN代碼", 獲得地址.

前言

Numpy是一個非常好用的python科學計算的庫,CNN是現在視覺領域深度學習的基礎之一。雖然好的框架很多,不過自己用Numpy實現一個可以使用的CNN的模型有利於初學者加深對CNN的理解。

後面我們將通過一系列文章介紹如何用Numpy從零實現一個可以訓練的CNN簡易網絡,同時對深度學習(CNN)的相關基礎知識進行一些複習,也希望能夠給正在入門的同學一些簡單的歸納。

在這一系列的文章中,我們主要需要做以下一些工作:

Numpy實現如下圖中所示的基本的CNN網絡組件:conv, pooling, relu, fullyconnect, softmax

用實現的基本組件搭建可以訓練的網絡,完成mnist的訓練與測試,畫出一個下圖的訓練曲線從貫序連接的層模型到計算圖模型的引入,完成自動求值,求導等功能常見的初始化方法,激活函數,優化方法,Loss函數的實現與比較,例如relu系與sigmoid系的比較,sgd,momentum,Adam的比較等等常見的trick的實現,例如dropout, batchnorm, residual

絕大部分的同學入門深度學習,第一個接觸的應該就是LeNet,我們也將以此為例子介紹卷積神經網絡的基本組件。參考上面的的網絡結構圖,它包含了卷積層(Convolutions),池化層(pooling), 全連接層(Full connection)。

卷積層(Convolutions)

卷積:如果你有圖像處理的基礎,對於卷積操作我想你一定不會陌生。在傳統的圖像處理中,卷積操作多用來進行濾波,銳化或者邊緣檢測啥的。我們可以認為卷積是利用某些設計好的參數組合(卷積核)去提取圖像空域上相鄰的信息。

卷積計算圖解

在二維圖像上,卷積操作一方面可以高效地按照我們的需求提取圖像的鄰域信息,在全局上又有著非常好的平移等變性,簡單就是說你將輸入圖像的某一部分移動到另外一部分,在輸出圖像上也會有著相應的移動。比如下圖是花書裡用來闡述卷積在特徵提取的效率優勢上的一張圖片,我們用來演示卷積的效果。假設我們把狗狗的鼻子移動到左上角,那麼相應輸出裡面的狗鼻子也會出現在左上角。(照片來源Paula Goodfellow)

卷積計算效果圖

卷積神經網絡之所以非常適合處理視覺問題,卷積的平移等變性是一大功臣。卷積神經網絡中的卷積層可以理解成是在二維圖像卷積的基礎上增廣而來。在二維圖像卷積操作裡,對於一個固定的卷積核,它能夠提取輸入圖像的某種特徵,但在實際的視覺問題裡,某一個尺度下的某種空間特徵不足以解決我們的需求。所以我們需要改進原始的卷積操作使得可以提取不同尺度下的不同特徵。

一次操作(一層)中使用多個卷積核得到該尺度下的多張特徵映射多層(次)提取不同尺度下的不同特徵信息

由於第一點改進,自然而然,即使第一張圖片輸入只有一個通道,後面其他層的輸入都是多通道。所以對應的我們的卷積核也是多通道。即輸入圖像和卷積核都添加了channel這個維度,那麼卷積層中的卷積操作變為了如下的定義:

到這裡,我們大概可以總結出一個卷積層的前向計算(Forward)和他的功能。當然正如我們前面提到過,需要讀者懂一點BP算法,因為即使我們知道如何通過卷積層提取輸入圖像的特徵,卷積層依舊無法正常的工作,因為卷積操作最關鍵的部分卷積核的數值沒有被確定下來。BP算法就是告訴我們,如何通過監督學習的方法來優化我們的卷積核的數值,使得我們能夠找到在對應任務下表現最好的卷積核(特徵),當然這個說法不是很準確。所以在我們實現的卷積層的類中,還會包含一個Backward方法,用於反向傳播求導。考慮到一次篇幅不要太長這一部分的原理和實現將放在下一篇文章裡。

在這篇接下來的部分裡我們就將逐一用Numpy實現一個可以運行的Conv2D類以及Forward方法。

Show me your code

PS:文章看到的版本是不基於graph模型的,Conv2D直接繼承自Object,所有的數據和操作都是裸露的,單純為了實現功能。github上面這一部分代碼已經不用了,放在layers文件夾下。

初始化

根據上面的公式,我們知道實現一個卷積前向計算的操作,我們需要知道以下信息:

輸入數據的shape = [N,W,H,C] N=Batchsize/W=width/H=height/C=channels卷積核的尺寸ksize ,個數output_channels, kernel shape [output_channels,k,k,C]卷積的步長,基本默認為1.卷積的方法,VALID or SAME,即是否通過padding保持輸出圖像與輸入圖像的大小不變

實際上還需要知道核參數的初始化方法

class Conv2D(object):def __init__(self, shape, output_channels, ksize=3, stride=1, method='VALID'):self.input_shape = shapeself.output_channels = output_channelsself.input_channels = shape[-1]self.batchsize = shape[0]self.stride = strideself.ksize = ksizeself.method = methodweights_scale = math.sqrt(ksize*ksize*self.input_channels/2)self.weights = np.random.standard_normal((ksize, ksize, self.input_channels, self.output_channels)) / weights_scaleself.bias = np.random.standard_normal(self.output_channels) / weights_scale

我們通過初始化函數確定上面提到的所需參數,在第一次聲明的時候完成了對該層的構建。如下:

conv1 = Conv2D([batch_size, 28, 28, 1], 12, 5, 1)

這個conv1的實例就代表了該層,自然也會包含該層所需要的參數,例如kernel weights, kernel bias,我們用 np.random.standard_noral(kernel_shape)生成對應的kernel weights和kernel bias。因為 np.random.standard_noral()生成的mean=0,stdev=1的隨機Numpy數組,這裡我們後面除以相應的weights_scale(msra方法)去控制一下初始化生成的weights的stdev,好的初始化可以加速收斂。

下面這一部分是反向傳播中用到的,這篇文章中暫時不會用到,self.eta用於儲存backward傳回來的

他與該層的out是一個同樣維度的數組.

這裡我們就可以看到method時如何控制輸出數據的形狀的。「SAME」就表示添加padding使得輸出長寬不變。self.w_gradient,self.b_gradient則分別用於儲存backward計算過後得到的該次的

if method == 'VALID':self.eta = np.zeros((shape[0], (shape[1] - ksize ) / self.stride + 1, (shape[1] - ksize ) / self.stride + 1,self.output_channels))if method == 'SAME':self.eta = np.zeros((shape[0], shape[1]/self.stride, shape[2]/self.stride,self.output_channels))self.w_gradient = np.zeros(self.weights.shape)self.b_gradient = np.zeros(self.bias.shape)self.output_shape = self.eta.shape

前向計算(forward)

如何實現卷積層前向計算,是一個非常老生常談的問題,賈揚清大神對這個問題解釋的比較清楚,可以參考查詢下在Caffe中如何計算卷積

這裡主要使用的就是im2col優化方法:通過將圖像展開,使得卷積運算可以變成兩個矩陣乘法

圖解im2col

詳情參見論文 High Performance Convolutional Neural Networks for Document Processing

我們的forward方法的實現基本就是實現了上圖,主要分為以下四個步驟:

完整的代碼如下

def forward(self, x):col_weights = self.weights.reshape([-1, self.output_channels])if self.method == 'SAME':x = np.pad(x, ((0, 0), (self.ksize / 2, self.ksize / 2), (self.ksize / 2, self.ksize / 2), (0, 0)),'constant', constant_values=0)self.col_image = []conv_out = np.zeros(self.eta.shape)for i in range(self.batchsize):img_i = x[i][np.newaxis, :]self.col_image_i = im2col(img_i, self.ksize, self.stride)conv_out[i] = np.reshape(np.dot(self.col_image_i, col_weights) + self.bias, self.eta[0].shape)self.col_image.append(self.col_image_i)self.col_image = np.array(self.col_image)return conv_out

首先我們將卷積層的參數weights通過ndarray自帶的reshape方法reshape到上圖中Kernal Matrix的形狀。根據self.method,選擇是否對輸入的數據進行padding,這裡我們調用 np.pad()方法,對我們的輸入數據四維ndarray的第二維和第三維分別padding上與卷積核大小相匹配的0元素。聲明一個list用於存儲轉換為column的image,在backward中我們還會用到。對於batch中的每一個數據,分別調用im2col方法,將該數據轉化為上圖中的Input features(Matrix), 然後調用 np.dot()完成矩陣乘法得到Output features(Matrix), reshape輸出的shape,填充到輸出數據中。

im2col的代碼如下:

def im2col(image, ksize, stride):# image is a 4d tensor([batchsize, width ,height, channel])image_col = []for i in range(0, image.shape[1] - ksize + 1, stride):for j in range(0, image.shape[2] - ksize + 1, stride):col = image[:, i:i + ksize, j:j + ksize, :].reshape([-1])image_col.append(col)image_col = np.array(image_col)return image_col

到這裡我們就基本實現了簡單的卷積層的forward方法,你可以通過輸入圖片,指定weights的值,進行簡單的運算,測試是否能夠正確的進行前向的計算,完整的代碼可以去我的github直接看最新版,雖然有很較大的出入,但一樣是非常容易理解的。我們也能看出,之所以選用python+Numpy實現,是因為大多數需要用到的方法,例如reshape,pad,dot,都已經在Numpy中實現好了,同時,也很方便我們實時的去檢查。

第一篇文章裡就只介紹到這裡。整篇文章基本上是以圖像的視角,介紹了如何利用Numpy實現CNN中的卷積層的前向計算。這只是CNN精彩的地方,但不是最關鍵的地方,下一篇中我們將先介紹BP算法以及從機器學習相關視角來看待CNN,然後實現卷積層裡面的backward()與apply_gradient()。教程中完整代碼已上傳至github上, 可關注我百家號後發送私信"CNN代碼", 獲得地址.

TensorFlow入門系列教程文章地址:

只需以下兩步就可獲取到零基礎入門教教程啦:

回到文章最上方點擊關注按鈕關注我的百家號,方便接收最新教程.點擊標題下方的頭像位置, 就可進入我的主頁, 裡面就有我之前發布的TensorFlow入門系列教程啦.

目前已發布的TensorFlow入門教程列表:

相關焦點

  • 深度學習入門:淺析卷積神經網絡
    至今已有數種深度學習方法,如卷積神經網絡(CNN)、自編碼神經網絡(包括Auto encoder和Sparse Coding)和深度置信網絡(DBN),並在各個領域中取得了極好的效果。由於它的數據量小、識別任務簡單而成為圖像識別入門的第一課。但是由於其計算量小,識別難度較低(很多深度學習算法在這個測試集上的準確率已經達到99.6%),能在該數據集上有較好表現的模型並不一定能用在更複雜的圖片識別中。深度學習框架Keras的創建者François Chollet在Twitter上說道:「在MNIST上看似有效的想法沒法遷移到真正的機器視覺問題上。」
  • 大話卷積神經網絡CNN,小白也能看懂的深度學習算法教程,全程乾貨...
    深度學習從大類上可以歸入神經網絡,不過在具體實現上有許多變化,並不像大家聽到的一樣,覺得這兩個概念其實是同一個東西:從廣義上說深度學習的網絡結構也是多層神經網絡的一種。這是大多數初級深度學習工程師的現狀。當然,並不是這樣不好,對於demo俠來說,已經進步了不少了,起碼有思考。然而如果你問,你調整的這個參數為什麼會對模型的準確率帶來這些影響,這個參數調大調小對結果又會有哪些影響,就又是一問三不知了。懂原理俠:抱歉起了個這麼蠢的名字。但是,進階到這一步,已經可以算是入門了,可以找一份能養活自己的工作了。
  • ...請收下這份2018學習清單:150個最好的機器學習,NLP和Python教程
    那為什麼不買一本書呢? 因為教程能更好地幫助你學一技之長或者打開新視野。我把這博文分成四個部分,機器學習,NLP,Python,和數學基礎。在每一小節我會隨機引入一些問題。由於這方面學習材料太豐富了,本文並未涵括所有內容。
  • 乾貨 | 請收下這份2018學習清單:150個最好的機器學習,NLP和Python教程
    因為教程能更好地幫助你學一技之長或者打開新視野。 我把這博文分成四個部分,機器學習,NLP,Python,和數學基礎。在每一小節我會隨機引入一些問題。由於這方面學習材料太豐富了,本文並未涵括所有內容。 深度學習教程 (Quoc V.
  • Numpy入門詳細教程
    >numpy入門詳細教程python數據科學基礎庫主要是三劍客:numpy,pandas以及matplotlib,每個庫都集成了大量的方法接口,配合使用功能強大。平時雖然一直在用,也看過很多教程,但紙上得來終覺淺,還是需要自己系統梳理總結才能印象深刻。本篇先從numpy開始,對numpy常用的方法進行思維導圖式梳理,多數方法僅拉單列表,部分接口輔以解釋說明及代碼案例。最後分享了個人關於axis和廣播機制的理解。
  • 深度學習中的NumPy基礎
    與機器學習和深度學習應用工作涉及複雜的數字操作與大量的數據集。與純 Python 實現相比,NumPy 使得實現這些操作相對簡單和有效。從核心上說,NumPy 實現了Python(n 維數組)數據結構,類似於常規的 Python 列表。大多數程式語言只有數組的概念。Python 實現了列表,它作為數組工作,但是有區別。
  • PyTorch 深度學習官方入門中文教程 pdf 下載|PyTorchChina
    它主要由Facebookd的人工智慧小組開發,不僅能夠 實現強大的GPU加速,同時還支持動態神經網絡,這一點是現在很多主流框架如TensorFlow都不支持的。 PyTorch提供了兩個高級功能: 1.具有強大的GPU加速的張量計算(如Numpy) 2.包含自動求導系統的深度神經網絡 除了Facebook之外,Twitter、GMU和Salesforce等機構都採用了PyTorch。
  • 教程| 基礎入門:深度學習矩陣運算的概念和代碼實現
    本文從向量的概念與運算擴展到矩陣運算的概念與代碼實現,對機器學習或者是深度學習的入門者提供最基礎,也是最實用的教程指導,為以後的機器學習模型開發打下基礎。在我們學習機器學習時,常常遇到需要使用矩陣提高計算效率的時候。如在使用批量梯度下降迭代求最優解時,正規方程會採用更簡潔的矩陣形式提供權重的解析解法。
  • 【PPT下載】深度學習入門指南!六步構建深度神經網絡
    侯宇濤此前還主講了第三講和第五講,主題分別為《不需要寫代碼,如何用開源軟體DIGITS實現圖像分類》和《手把手教你使用開源軟體DIGITS實現目標檢測》。主講環節侯宇濤:感謝智東西公開課的邀請,非常榮幸今天能有機會跟大家一起分享深度學習這一新概念在市場上盛行的情況。
  • 神奇GIF動畫讓你秒懂各種深度學習卷積神經網絡操作原理
    打開APP 神奇GIF動畫讓你秒懂各種深度學習卷積神經網絡操作原理 深度學習思考者 發表於 2017-11-15 18:58:34
  • 實踐入門NLP:基於深度學習的自然語言處理
    【NLP工程師入門實踐班】——基於深度學習的自然語言處理開車啦!!還不趕緊上車!?【課程亮點】三大模塊,五大應用,手把手快速入門NLP算法+實踐,搭配典型行業應用海外博士講師,豐富項目經驗專業學習社群在算法和神經網絡方面,側重卷積神經網絡,遞歸神經網絡,增強學習,對抗學習,無監督學習等。發表多篇人工智慧及計算機視覺頂級會議和期刊,包括ICCV、AAAI oral、PR等,並為多個會議和期刊審稿人。曾在中科院參與負責基於龍芯的安全晶片項目,後成功轉行深度學習領域,講課風格深入淺出通俗易懂,有獨家學習和轉行經驗。
  • 乾貨| 請收下這份2018學習清單:150個最好的機器學習,NLP和Python...
    因為教程能更好地幫助你學一技之長或者打開新視野。我把這博文分成四個部分,機器學習,NLP,Python,和數學基礎。在每一小節我會隨機引入一些問題。由於這方面學習材料太豐富了,本文並未涵括所有內容。機器學習1、機器學習就是這麼好玩!
  • 用谷歌圖片搜索自製深度學習數據集 | 教程
    用谷歌圖片搜索自製深度學習數據集 | 教程 銅靈 編譯整理 就怕前腳剛立志搞個新研究,後腳就發現沒有合適的數據集可用。AI工程師從入門到放棄,可能就是這麼一會的功夫。 別找了,現在深度學習數據集也能自制了。
  • 關於機器學習,這可能是目前最全面最無痛的入門路徑和資源!
    我已經完全腦補出還沒開始學習的你看得一臉懵逼的樣子,一如以前的我...... 《Machine Learning》有兩版,一版是斯坦福教室裡錄製的版本,一版是Ng後來錄製的版本,李傑克這裡給大家推薦的是後者,相信我,前者直接上手真的可能會看哭的,別問我怎麼知道...... 如果非常簡要地把深度學習概括為兩個方向,那就是圖像處理和語音處理,看過我前一篇文章的童鞋會知道兩者分別主要對應的是卷積神經網絡和遞歸神經網絡的應用。
  • 資源|用Python和NumPy學習《深度學習》中的線性代數基礎
    本文系巴黎高等師範學院在讀博士 Hadrien Jean 的一篇基礎學習博客,其目的是幫助初學者/高級初學者基於深度學習和機器學習來掌握線性代數的概念。掌握這些技能可以提高你理解和應用各種數據科學算法的能力。
  • 從框架優缺點說起,這是一份TensorFlow入門極簡教程
    隨著 TensorFLow 在研究及產品中的應用日益廣泛,很多開發者及研究者都希望能深入學習這一深度學習框架。而在昨天機器之心發起的框架投票中,2144 位參與者中有 1441 位都在使用 TensorFlow 框架,是所有框架中使用率最高的。但 TensorFLow 這種靜態計算圖有一定的學習成本,因此也阻擋了很多初學者入坑。
  • 60分鐘入門深度學習工具PyTorch
    >他是一個基於Python的科學計算包,目標用戶有兩類為了使用GPU來替代numpy一個深度學習研究平臺:提供最大的靈活性和速度開始張量(Tensors你可以使用所有的numpy索引操作。它是一個簡單的前饋神經網絡,它接受一個輸入,然後一層接著一層的輸入,直到最後得到結果。
  • 手把手教你用PyTorch實現圖像分類器(第一部分)
    通過3篇短文,介紹如何實現圖像分類器的概念基礎——這是一種能夠理解圖像內容的算法。本文的目標不是提供手把手的指導,而是幫助理解整個過程。如果你正在考慮學習機器學習或人工智慧,你將不得不做類似的項目,並理解本系列文章中介紹的概念。文章主要進行概念上的解釋,不需要知道如何編寫代碼。
  • 想入門機器學習?機器之心為你準備了一份中文資源合集
    機器之心也介紹過許多數學基礎與概念:基礎入門:深度學習矩陣運算的概念和代碼實現想了解概率圖模型?你要先理解圖論的基本定義與形式深度神經網絡中的數學,對你來說會不會太難?Reddit 熱門話題:如何閱讀並理解論文中的數學內容?
  • 高效「煉丹」必備技能:一文實現深度學習數學原理入門,還有吳恩達...
    尤其是深度學習算法開發人員,追求模型結構優化和提高編程效率是永遠的目標。但是,如果只做代碼「搬運工」,不了解神經網絡背後的數學原理,很難對項目有深刻全面的理解,debug反而會更難、耗時更長。就以深度學習中常用的神經網絡來說,典型模型包括多層感知機(DLP)、卷積神經網絡(CNN)、循環神經網絡(RNN)等等,不同的項目,對神經網絡的調參需求也不相同。