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

2021-01-08 愛學習愛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入門教程列表:

相關焦點

  • Keras 教程: Python 深度學習終極入門指南
    在這篇 Keras 教程中, 你將學到如何用 Python 建立一個卷積神經網絡!事實上, 我們將利用著名的 MNIST 數據集, 訓練一個準確度超過 99% 的手寫數字分類器.開始之前, 請注意, 本指南是面向對應用深度學習感興趣的初學者的.
  • 卷積神經網絡小白入門手冊
    學習深度學習,最常接觸到的就是各式各樣的神經網絡了,其中卷積神經網絡是諸多神經網絡中最典型最常用的神經網絡了。本文原始素材來源於freecodecamp博客,經本人翻譯首發於此。希望能幫助到大家!覺得不錯就點個讚,或者關注下我吧,後續我還會分享更多相關的精彩內容。
  • 深度學習入門:淺析卷積神經網絡
    至今已有數種深度學習方法,如卷積神經網絡(CNN)、自編碼神經網絡(包括Auto encoder和Sparse Coding)和深度置信網絡(DBN),並在各個領域中取得了極好的效果。由於它的數據量小、識別任務簡單而成為圖像識別入門的第一課。但是由於其計算量小,識別難度較低(很多深度學習算法在這個測試集上的準確率已經達到99.6%),能在該數據集上有較好表現的模型並不一定能用在更複雜的圖片識別中。深度學習框架Keras的創建者François Chollet在Twitter上說道:「在MNIST上看似有效的想法沒法遷移到真正的機器視覺問題上。」
  • 手把手帶你走進卷積神經網絡!
    在這篇文章中,我們將基於神經網絡的基本背景知識,探索CNN是什麼,理解它們是如何工作的,並使用Python中的numpy從頭開始構建一個真正的卷積神經網絡。本文假設讀者有一定的神經網絡的基本知識。如果你想要了解一些關於神經網絡的知識,你可以讀一下我的關於對神經網絡的介紹(https://victorzhou.com/blog/intro-to-neural-networks/)。
  • python深度學習---帶你從入門到精通
    分類識別問題)6、Python機器學習庫Scikit-learn庫講解7、案例講解:(1)回歸擬合問題:近紅外光譜預測汽油辛烷值        (2)時間序列預測:新冠肺炎流行趨勢預測(3)分類識別問題:人臉朝向識別8、實操練習第三章深度學習入門基礎與卷積神經網絡1、深度學習與傳統機器學習的區別與聯繫
  • 大話卷積神經網絡CNN,小白也能看懂的深度學習算法教程,全程乾貨...
    深度學習從大類上可以歸入神經網絡,不過在具體實現上有許多變化,並不像大家聽到的一樣,覺得這兩個概念其實是同一個東西:從廣義上說深度學習的網絡結構也是多層神經網絡的一種。這是大多數初級深度學習工程師的現狀。當然,並不是這樣不好,對於demo俠來說,已經進步了不少了,起碼有思考。然而如果你問,你調整的這個參數為什麼會對模型的準確率帶來這些影響,這個參數調大調小對結果又會有哪些影響,就又是一問三不知了。懂原理俠:抱歉起了個這麼蠢的名字。但是,進階到這一步,已經可以算是入門了,可以找一份能養活自己的工作了。
  • 不堆砌公式,用最直觀的方式帶你入門深度學習
    所以花了大量時間查資料看論文,有的博客或者論文寫得非常贊,比如三巨頭 LeCun,Bengio 和 Hinton 2015 年在 Nature 上發表綜述論文的「Deep Learning」,言簡意賅地引用了上百篇論文,但適合閱讀,不適合 presentation 式的分享;再如 Michael Nielsen 寫的電子書《神經網絡與深度學習》(中文版,英文版)通俗易懂,用大量的例子解釋了深度學習中的相關概念和基本原理
  • 教程詳解:用卷積神經網絡檢測臉部關鍵點(一)
    這是一個手把手教你學習深度學校的教程。一步一步,我們將要嘗試去解決Kaggle challenge中的臉部關鍵點的檢測問題。我們將用Lasagne去模擬一系列的神經網絡結構,討論一下數據增強(data augmentaTIon)、流失(dropout)、結合動量(momentum)和預先訓練(pre-training)。這裡有很多方法可以將我們的結果改善不少。我假設諸位已經知道了一些關於神經網絡的只是。所以我們就不介紹神經網絡的背景知識了。
  • 60分鐘入門PyTorch,官方教程手把手教你訓練第一個深度學習模型(附連結)
    那麼,入門 PyTorch 深度學習需要多久?PyTorch 的一份官方教程表示:只需要 60 分鐘。教程連結:https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html這是一份非常簡潔的學習材料,目標是讓學習者了解 PyTorch 的 Tensor 庫和神經網絡,以及如何訓練一個可以進行圖像分類的神經網絡。
  • 【專知國慶特刊-PyTorch手把手深度學習教程系列01】一文帶你入門優雅的PyTorch
    < 一文帶你入門優雅的Pytorch >< 快速理解系列(一): 圖文+代碼, 讓你快速理解CNN>< 快速理解系列(二): 圖文+代碼, 讓你快速理解LSTM>>< 快速理解系列(三): 圖文+代碼, 讓你快速理解GAN >< 快速理解系列(四): 圖文+代碼, 讓你快速理解Dropout >< NLP系列(一) 用Pytorch 實現 Word Embedding ><
  • 使用GPU和Theano加速深度學習
    GPU和Theano加速深度學習,教程從多層感知器到卷積神經網絡,由淺入深,是不錯的入門資料。【編者按】GPU因其浮點計算和矩陣運算能力有助於加速深度學習是業界的共識,Theano是主流的深度學習Python庫之一,亦支持GPU,然而Theano入門較難,Domino的這篇博文介紹了如何使用GPU和Theano加速深度學習,使用更簡單的基於Theano的 Nolearn庫。教程由多層感知器及卷積神經網絡,由淺入深,是不錯的入門資料。
  • 深度學習預習資料:圖靈獎得主Yann LeCun《深度學習》春季課程
    對於這一方向的新生來說,提前了解、學習這一專業領域的知識,會讓研究生涯有一個更加順暢的開端。這份資料手把手教會你入門 | 獻給新手的深度學習綜述……列出的這些課程僅是冰山一角。,重點包括監督深度學習、無監督深度學習、嵌入方法、度量學習、卷積和遞歸網絡等。
  • 深度學習入門必看---吳恩達深度學習課程
    在五門課程中,將學習深度學習的基礎知識,了解如何構建神經網絡,並學習如何實踐機器學習項目,學習卷積網絡,RNN,LSTM,Adam,Dropout,BatchNorm,Xavier/He初始化等等。同時可以了解醫療,自動駕駛,手語閱讀,音樂創作和自然語言處理的案例研究,掌握深度學習的基礎理論,還會看到它在工業中的應用。課程的內容都將在Python和TensorFlow的練習中所實現。
  • LeCun親授的深度學習入門課:從飛行器的發明到卷積神經網絡
    這是深度學習入門者繞不過的幾個問題。很幸運,這裡有位大牛很樂意為你講解。2月6日,UCLA(加州大學洛杉磯分校)與純數學與應用數學研究所(IPAM)跨界組織主辦的論壇上,「卷積神經網絡之父」Yann LeCun操著一口濃重的法國口音,給數學界的科學家們介紹了深度學習。
  • 圖深度學習入門教程(六)——注意力機制與圖注意力
    摘要:深度學習還沒學完,怎麼圖深度學習又來了?別怕,這裡有份系統教程,可以將0基礎的你直接送到圖深度學習。
  • 2018AI學習清單丨150個最好的機器學習和Python教程
    深度學習教程 (Quoc V. 12、長短期記憶(LSTM) 老司機帶你簡易入門長短期神經網絡/chap6.html#introducing_convolutional_networks 深度學習與卷積神經網絡模型(medium.com/@ageitgey)https://medium.com/@ageitgey/machine-learning-is-fun-part-3-deep-learning-and-convolutional-neural-networks-f40359318721
  • 深度學習第17講:keras入門和快速上手指南
    作者:魯偉一個數據科學踐行者的學習日記。
  • 深度學習、圖像分類入門,從VGG16卷積神經網絡開始
    、卷積神經網絡的時候非常懵逼,不知道從何入手,我覺得應該有一個進階的過程,也就是說,理應有一些基本概念作為奠基石,讓你有底氣去完全理解一個龐大的卷積神經網絡:本文思路:一、我認為學習卷積神經網絡必須知道的幾個概念:1、卷積過程:  我們經常說卷積神經網絡卷積神經網絡,到底什麼才是卷積?網絡層卷積過程到底怎麼實現?
  • 深度學習大講堂之pytorch入門
    ,他們也一直在支持一些開源的深度學習框架,有 TensorFlow 、Pytorch、Caffe、Theano、Keras等。這其中,TensorFlow和Pytorch佔據了深度學習的半壁江山。今天小天就帶大家從數據操作、自動求梯度和神經網絡設計的pytorch版本三個方面來入門pytorch。
  • AI | 怎樣快速入門機器學習和深度學習?
    編者按:入門機器學習和深度學習並不是一件容易的事情。需要學習大量的知識,初學者常常會迷茫不知所措。現在我們給你帶來一篇純乾貨,幫助你入門機器學習和深度學習。機器學習算法書籍:《統計學習方法》:李航博士的經典教材。用最精煉的語言描述機器學習算法,轉行AI必讀書籍《機器學習》:周志華教授的西瓜書。統計學習方法涵蓋面太窄,配合西瓜書來擴展寬度。《python機器學習及實現》:適合入門,學習曲線平滑,理論書看累了,就跟著這本書打一遍代碼,對kaggle就會大致的了解。