【他山之石】利用Tensorflow構建CNN圖像多分類模型及圖像參數、數據維度變化情況實例分析

2021-02-13 人工智慧前沿講習

「他山之石,可以攻玉」,站在巨人的肩膀才能看得更高,走得更遠。在科研的道路上,更需藉助東風才能更快前行。為此,我們特別搜集整理了一些實用的代碼連結,數據集,軟體,編程技巧等,開闢「他山之石」專欄,助你乘風破浪,一路奮勇向前,敬請關注。

地址:https://blog.csdn.net/hurry0808

本文以CIFAR-10(https://www.cs.toronto.edu/~kriz/cifar.html)為數據集,基於Tensorflow介紹了CNN(卷積神經網絡)圖像分類模型的構建過程,著重分析了在建模過程中卷積層、池化層、扁平化層、全連接層、輸出層的運算機理,以及經過運算後圖像尺寸、數據維度等參數的變化情況。

01

CIFAR-10數據集由60000張彩色圖片構成,其中包括50000張訓練集圖片、10000張測試集圖片,每張圖片的shape為(32,32,3),即圖片尺寸為32*32,通道數為3;所有圖片可以被分為10類,包括:

02

TensorFlow™(https://www.tensorflow.org/?hl=zh-cn) 是一個使用數據流圖進行數值計算的開放原始碼軟體庫,其API可在Python、C++、Java、Go、Swift (Early Release)語言中調用,其中Python API是目前最完整且易用的。TensorFlow擅長訓練深度神經網絡,被認定為是神經網絡中最好用的庫之一。通過使用TensorFlow我們可以快速入門神經網絡, 大大降低了深度學習(也就是深度神經網絡)的開發成本和開發難度。
Tensorflow使用數據流圖進行數值計算,圖中的節點代表數學運算,圖中的邊代表在這些節點之間傳遞的多維數組(張量)。在使用其構建模型時,先搭建好流圖結構——類似於鋪好管道,然後再加載數據——向管道中注水,讓數據在各節點計算、沿各管道流動;數據在流圖中計算、傳遞時採用多維數組(張量)的形式,因此在Tensorflow中參與計算的均為數組數據類型。
本文使用Tensorflow構建簡單的CNN圖像多分類模型,其由3個卷積(含激活函數)與池化層、1個扁平層、3個全連接層、1個輸出層構成,示意圖如下所示:

輸入(Input)層圖像數據經過標準化(normalize)、ont-hot編碼等預處理後形成的4D張量,本文輸入層張量shape為[batch, height, width, channels]。卷積(Convolution)層卷積層與池化層的作用在於:
1. invariance(不變性),這種不變性包括translation(平移),rotation(旋轉),scale(尺度);
2. 保留主要的特徵同時減少參數(降維,效果類似PCA)和計算量,防止過擬合,提高模型泛化能力。最左側為輸入層圖像(加padding後的shape:(7,7,3)),中部為2個卷積核W0、W1及與之相對應的Bias b0、b1,最右側為輸入圖像與核w0、w1進行卷積計算後的結果——前者對應於上部圖、後者對應於下部圖,卷積計算得到的結果即為feature map。每個卷積核與上層圖像進行卷積運算後均會得到1個feature map。對於3通道圖像,參考本圖,卷積運算的過程如下:
1. 輸入圖像的每個通道分別從左上角開始,每次取與卷積核大小相同的部分(稱之為patch),與卷積核對應部分分別相乘後再相加(內積運算);如R通道與W0的最上部核(0核)對應元素相乘再相加得到0,G通道與w0的1核做內積運算得到2,B通道與w0的2核做內積運算後得到0;
2. 內積運算得到的結果相加,再加上w0的bias值(b0),得到feature map左上的元素值;即0+2+0+1=3;
3. 按照指定步長移動卷積核,直至輸入圖像被整個覆蓋,得到最終的feature map;本圖中步長(stride)為(2,2)。

tf.nn.conv2d(    input,    filter,    strides,    padding,    use_cudnn_on_gpu=True,    data_format='NHWC',    dilations=[1, 1, 1, 1],    name=None)

input:需要做卷積的輸入圖像,它要求是一個Tensor,shape為[batch, in_height, in_width, in_channels],具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 圖像通道數],注意這是一個4維的Tensor,要求類型為float32和float64其中之一;filter:相當於CNN中的卷積核,它要求是一個Tensor,shape為[filter_height, filter_width, in_channels, out_channels],具體含義是[卷積核的高度,卷積核的寬度,圖像通道數,卷積核個數],要求類型與參數input相同,filter的通道數要求與input的in_channels一致,有一個地方需要注意,第三維in_channels,就是參數input的第四維;strides:卷積時在圖像每一維的步長,這是一個一維的向量,長度4,strides[0]=strides[3]=1;padding:string類型的量,只能是」SAME」、」VALID」其中之一,這個值決定了不同的卷積方式;卷積運算時卷積核滑動過程中當輸入圖像(input)的in_height、in_width不是filter的filter_height、filter_width的整數倍時,」SAME」方式是在input周圍填充0以將其in_height、in_width補充為filter相應部分的整數倍,」VALID」方式將input的多餘部分丟棄,詳細介紹請參看這裡;use_cudnn_on_gpu:bool類型,是否使用cudnn加速,默認為true;data_format:指定輸入數據、輸出數據的格式,取值為」NHWC」、」NCHW」,前者對應於 [batch, height, width, channels],後者對應於 [batch, channels, height, width],默認為』NHWC』。dilations:一個可選的ints列表;默認為[1,1,1,1]。長度為4的一維張量,每個input維度的膨脹係數;如果設置為k> 1,則每個該維度上的過濾器元素之間會有k-1個跳過的單元格;維度順序由data_format的值決定;在Dilations中批次和深度尺寸必須為1;返回值:Tensor,也就是我們常說的feature map。輸入圖像經過卷積運算後,其高度、寬度變為——
『SAME』 類型的padding,其輸出的height和width計算如下:
out_height = ceil(float(in_height) / float(strides[1])) ceil:向上取整
out_width = ceil(float(in_width) / float(strides[2]))『VALID』類型的padding, 其輸出的height和width計算如下:
out_height = ceil(float(in_height – filter_height + 1) / float(strides[1]))
out_width = ceil(float(in_width – filter_width + 1) / float(strides[2]))驗證該函數的文章,請看這裡(https://blog.csdn.net/u012609509/article/details/71215859)。激活函數(Activation Function)池化層、全連接層等通過線性運算構建的是線性模型,該模型的表達能力有限;激活函數能夠加入非線性因素,從而使模型的表達能力得到極大提升。常用的激活函數有Tanh函數 、ReLU函數 、Leaky ReLU函數 、Maxout函數 等,本文使用ReLU函數作為激活函數。
Tensorflow中的relu激活函數為:

tf.nn.relu(    features,    name=None)

features: 張量,必須為以下類型中的一種:float32, float64, int32, uint8, int16, int8, int64, bfloat16, uint16, half, uint32, uint64;池化(Pooling)層池化層與卷積層的作用、計算方法類似,也有池化filter、步長、填充方式等參數,所不同的是,池化計算比較簡單,常取filter覆蓋部分的最大值、或者均值,分別稱之為最大池化、平均池化,最大池化的示意圖如下所示:

最大池化的filter shape為(2,2), 步長也為(2,2),每個filter滑動覆蓋處取最大值,得到右側所示的結果。
Tensorflow實現最大池化運算的函數為:

tf.nn.max_pool(    value,    ksize,    strides,    padding,    data_format='NHWC',    name=None)

value:輸入4D張量, 其格式由data_format指定;ksize:含有4個元素的1D張量,指定池化核的尺寸;strides:含有4個元素的1D int 張量,指定池化時在圖像每一維的步長,strides[0]=strides[3]=1;padding:邊界填充方式,string類型的量,只能是」SAME」、」VALID」其中之一;data_format:數據格式,string類型的量, 只能是』NHWC』、 『NCHW』 、』NCHW_VECT_C』 其中之一;返回值:Tensor,也就是我們常說的feature map。上層feature map經池化運算後,其batch、channels均不發生變化,只有height、width會發生變化,輸出height、width計算方式同卷積層。扁平化(Flatten)層將上一層得到的全部feature map拉直成列向量,作為全連接網絡的輸入。拉直方式為height*width*channels。
Tensorflow實現扁平化層運算的函數為:

tf.contrib.layers.flatten(    inputs,    outputs_collections=None,    scope=None)

inputs:形如 [batch_size, …]的張量,注意張量的第1個元素必須為batch_size;outputs_collections:添加到輸出的集合;返回值:形如[batch_size, k]的扁平化張量。圖像分類模型訓練完成後,本層返回張量的shape(主要是k)就確定了,從而限定了模型預測時輸入圖像的尺寸——因為在模型確定的情況下,卷積層、池化層等結構、數量均不再改變,預測圖像與訓練圖像尺寸一致時,經卷積、池化等運算後,扁平化輸出shape與模型一致;預測圖像與訓練圖像尺寸不一致時,經卷積、池化等運算後,扁平化輸出的shape與模型不一致,從而無法繼續運算。這也是遷移學習時,預訓練模型均約定輸入圖像height、width的原因。從該層開始,分類模型的網絡結構類似於「多層前饋神經網絡」。全連接(Fully Connected)層全連接層在整個卷積神經網絡中起到「分類器」的作用、也是模型表示能力的「防火牆」。全連接層的運算形如X*W+b,X*W為矩陣乘法,其中X為輸入2維數組(shape為[batch_size, k]),W為權重2維數組(shape為[k,out_k]),b為偏置,W的第2個元素(out_k)決定了全連接層運算後輸出的2維數組形狀(shape為[batch_size, out_k])。
由於全連接層參數冗餘(僅全連接層參數就可佔整個網絡參數80%左右),需要使用tf.nn.dropout來隨機丟棄一些節點,或者使用一些性能優異的網絡模型如ResNet和GoogLeNet等來取代全連接層融合學到的深度特徵。

tf.layers.dense(    inputs,    units,    activation=None,    use_bias=True,    kernel_initializer=None,    bias_initializer=tf.zeros_initializer(),    kernel_regularizer=None,    bias_regularizer=None,    activity_regularizer=None,    kernel_constraint=None,    bias_constraint=None,    trainable=True,    name=None,    reuse=None)

units: Integer or Long, dimensionality of the output space.activation: Activation function (callable). Set it to None to maintain a linear activation.use_bias: Boolean, whether the layer uses a bias.kernel_initializer: Initializer function for the weight matrix. If None (default), weights are initialized using the default initializer used by tf.get_variable.bias_initializer: Initializer function for the bias.kernel_regularizer: Regularizer function for the weight matrix.bias_regularizer: Regularizer function for the bias.activity_regularizer: Regularizer function for the output.kernel_constraint: An optional projection function to be applied to the kernel after being updated by an Optimizer (e.g. used to implement norm constraints or value constraints for layer weights). The function must take as input the unprojected variable and must return the projected variable (which must have the same shape). Constraints are not safe to use when doing asynchronous distributed training.bias_constraint: An optional projection function to be applied to the bias after being updated by an Optimizer.trainable: Boolean, if True also add variables to the graph collection GraphKeys.TRAINABLE_VARIABLES (see tf.Variable).name: String, the name of the layer.reuse: Boolean, whether to reuse the weights of a previous layer by the same name.Returns:Output tensor the same shape as inputs except the last dimension is of size units.

tf.nn.dropout(    x,    keep_prob,    noise_shape=None,    seed=None,    name=None)

x: A floating point tensor.keep_prob: A scalar Tensor with the same type as x. The probability that each element is kept.noise_shape: A 1-D Tensor of type int32, representing the shape for randomly generated keep/drop flags.seed: A Python integer. Used to create random seeds. See tf.set_random_seed for behavior.name: A name for this operation (optional).Returns: A Tensor of the same shape of x.輸出(Output)層輸出層運算與全連接層類似,只是在設定運算參數時輸出節點數量需與分類標記數量相一致,並且在運算完成後再使用tf.nn.softmax函數,得到測試圖像屬於各分類的概率,該所有概率值之和為1。
Tensorflow中的tf.nn.softmax函數如下所示:

tf.nn.softmax(    logits,    axis=None,    name=None,    dim=None)

logits: A non-empty Tensor. Must be one of the following types: half, float32, float64.axis: The dimension softmax would be performed on. The default is -1 which indicates the last dimension.name: A name for the operation (optional).dim: Deprecated alias for axis.Returns: A Tensor. Has the same type and shape as logits.訓練得到分類模型按照輸入層、卷積層與池化層(共3層)、扁平化層、全連接層(共3層)、輸出層的順序搭建好模型,以交叉熵均值作為cost,以Adam優化算法尋找全局最優點,以cost、Accuracy(分類準確率)作為評估模型的指標,各層參數設置如下圖所示:
batch為訓練時每批輸入的圖像數量,視訓練環境的硬體配置而定,本文設置為512訓練構建好的CNN圖像分類模型時,單張圖片用3D數組表示,多張圖片用4D數組表示,經過卷積、激活函數、池化、扁平化、全連接、Dropout等運算,其batch、height、width、channels、feature map數量、節點數量、數據shape有的會發生變化,有的不會發生變化,如下表所示:

使用CIFAR-10訓練集進行訓練,在訓練集和測試集上的準確率均為0.73,如下圖所示:


03

本文以CIFAR-10數據集為例,使用Tensorflow構建了簡單的CNN圖像分類模型,該模型包含輸入層、卷積與池化層、扁平化層、全連接層、輸出層,這些層均是構建CNN分類模型必要且重要的層;訓練後分類模型的準確率雖然不夠高,但本文重在分析各層運算時圖像數據shape的變化及其它尺寸數據的改變情況。

本文目的在於學術交流,並不代表本公眾號贊同其觀點或對其內容真實性負責,版權歸原作者所有,如有侵權請告知刪除。

更多他山之石專欄文章,請點擊文章底部「閱讀原文」查看

分享、點讚、在看,給個三連擊唄!

相關焦點

  • 【乾貨】快速上手圖像識別:用TensorFlow API實現圖像分類實例
    作者通過TensorFlow API快捷地實現一個命令行圖像分類例子,詳細介紹了如何按步驟下載模型、加載圖像、執行圖像識別命令。你不需要GPU,只要有一臺筆記本就可以按照作者的步驟進行操作,並最終完成圖像識別任務。教程非常方便快捷,讀完本文之後相信你能秒秒鐘實現一個圖像分類任務。專知內容組編輯整理。
  • TensorFlow圖像分類教程
    利用TensorFlow,你可以獲得具有強大能力的複雜功能,其強大的基石來自於TensorFlow的易用性。在這個由兩部分組成的系列中,我將講述如何快速的創建一個應用於圖像識別的卷積神經網絡。TensorFlow計算步驟是並行的,可對其配置進行逐幀視頻分析,也可對其擴展進行時間感知視頻分析。
  • 【乾貨】TensorFlow實戰——圖像分類神經網絡模型
    2.訓練(Training)的過程是在我們標註的數據(圖像)的基礎上,使用某種工具隨機抓取其中的一些數據(圖像),然後輸入到模型中,再使用模型來猜測每種花的類型並且測試猜測的準確性,重複這一過程直到大部分訓練數據都被使用。最後一批未使用的圖像(測試集)用於檢驗訓練模型的準確性。
  • 業界 TensorFlow基準:圖像分類模型在各大平臺的測試研究
    因此本文通過將一系列的圖像分類模型放在多個平臺上測試,希望得出一些重要結果並為 TensorFlow 社區提供可信的參考。不僅如此,同時在本文最後一節中還將給出測試進行的細節和所使用腳本的連結。圖像分類模型的測試結果InceptionV3、ResNet-50、ResNet-152、VGG16 和 AlexNet 模型都在 ImageNet 數據集中進行測試。
  • 圖像分類任務中,Tensorflow 與 Keras 到底哪個更厲害?
    讓我們看看這個問題在圖像分類的實際應用中的答案。在此之前,先介紹Keras和Tensorflow這兩個術語,幫助你在10分鐘內構建強大的圖像分類器。TensorflowTensorflow是開發深度學習模型最常用的庫。它是有史以來最好的庫,在日常實驗中被許多極客選擇。
  • 數據分析之道 | TF入門實踐: 利用卷積神經網絡實現圖像分類
    辨別手寫數字與辨別衣服種類的邏輯一樣,神經網絡模型甚至連參數不改也都可以同樣訓練,唯一的區別在於:辨別衣服種類的圖像輸入為衣服而已,在 tensorflow_datasets 中集合該數據集,比如 fasion_mnist。
  • 【最新TensorFlow1.4.0教程03】利用Eager Execution構建和訓練卷積神經網絡(CNN)
    每個神經元都得到一些輸入數據,進行內積運算後再進行激活函數運算。那麼有哪些地方變化了呢?卷積神經網絡的結構基於一個假設,即輸入數據是二維的圖像,基於該假設,我們就向結構中添加了一些特有的性質。這些特有屬性使得前向傳播函數實現起來更高效,並且大幅度降低了網絡中參數的數量。
  • 谷歌開源圖像分類工具TF-Slim,定義TensorFlow複雜模型
    Guadarrama,谷歌研究員譯者:聞菲【新智元導讀】谷歌今天宣布開源 TensorFlow 高級軟體包 TF-Slim,能使用戶快速準確地定義複雜模型,尤其是圖像分類任務。自發布以來,TF-Slim 已經得到長足發展,無論是網絡層、代價函數,還是評估標準,都增加了很多類型,訓練和評估模型也有了很多便利的常規操作手段。這些手段使你在並行讀取數據或者在多臺機器上部署模型等大規模運行時,不必為細節操心。此外,我們還製作了 TF-Slim 圖像模型庫,為很多廣泛使用的圖像分類模型提供了定義以及訓練腳本,這些都是使用標準的資料庫寫就的。
  • 【他山之石】Tensorflow模型保存方式大匯總
    為此,我們特別搜集整理了一些實用的代碼連結,數據集,軟體,編程技巧等,開闢「他山之石」專欄,助你乘風破浪,一路奮勇向前,敬請關注。地址:https://www.zhihu.com/people/kumonoueGraphDef是Tensorflow中序列化的圖結構。在tensorflow中,計算圖被保存為Protobuf格式(pb)。
  • 盤點 | 對比圖像分類五大方法:KNN、SVM、BPNN、CNN和遷移學習
    傳統方式:特徵描述和檢測也許對一些樣本任務有好處,但實際情況要複雜得多。由於想要同時測試整個數據集和帶不同數量標籤的子數據集的精確度,我們構建了一個作為參數的數據集並解析進我們的程序。我們同樣構建了用於 k-NN 方法的鄰元素數作為解析參數。之後,我們開始提取數據集中的每一圖像特徵,並將其放入數組。我們使用 cv2.imread 讀取每一圖像,通過從圖像名稱中提取字符串來拆分標籤。在我們的數據集中,我們使用相同格式——類別標籤.
  • 【深度學習系列】用PaddlePaddle和Tensorflow進行圖像分類
    這篇主要跟大家講講如何用PaddlePaddle和Tensorflow做圖像分類。所有程序都在我的github裡(https://github.com/huxiaoman7/PaddlePaddle_code),可以自行下載訓練。在卷積神經網絡中,有五大經典模型,分別是:LeNet-5,AlexNet,GoogleNet,Vgg和ResNet。
  • 在TensorFlow中使用MobileNet,創建在手機上運行的快速圖像分類器
    當你想要識別一個圖像時,會把圖像發送到網上,在遠程伺服器上進行識別,然後把結果發回到你的手機上。這個情況現在正在快速發生變化。手機的計算能力正在快速增長,而計算機視覺需要的網絡複雜度正在縮小(感謝像SqueezeNet和MobileNet這樣的架構)。不需要連接網際網路的AI有很多優點,尤其適合一些對響應速度要求很高的場景。
  • 使用PaddleFluid和TensorFlow實現圖像分類網絡SE_ResNeXt | 文末超大福利
    python SE_ResNeXt_fluid.py在命令行運行下面的命令便可以使用 TensorFlow 進行模型的訓練,訓練中模型驗證以及模型保存:python SE_ResNeXt_tensorflow.py註:本系列的最新代碼,可以在 github 上的 TF2Fluid
  • TensorFlow學習筆記2:構建CNN模型
    下面將介紹TensorFlow中模型的基本組成部分,同時將構建一個CNN模型來對MNIST數據集中的數字手寫體進行識別。基本設置在我們構建模型之前,我們首先加載MNIST數據集,然後開啟一個TensorFlow會話(session)。加載MNIST數據集TensorFlow中已經有相關腳本,來自動下載和加載MNIST數據集。
  • 基於Keras的多標籤圖像分類
    而multi-label是更加general的一種情況了,它說為什麼一個sample的標籤只能有1個呢。為什麼一張圖片不是貓就是狗呢?難道我不能訓練一個人工智慧,它能告訴我這張圖片既有貓又有狗呢?其實關於多標籤學習的研究,已經有很多成果了。 主要解法是 * 不擴展基礎分類器的本來算法,只通過轉換原始問題來解決多標籤問題。如BR, LP等。
  • 教程 | 用TensorFlow Estimator實現文本分類
    本文演示了如何使用自定義的 TensorFlow 評估器、嵌入技術及 tf.layers 模塊(https://www.tensorflow.org/api_docs/python/tf/layers)來處理文本分類任務。在這篇文章中,我們會學習 word2vec 詞嵌入和遷移學習技術,在有標籤數據稀缺時獲得更好的模型性能。我們將展示相關的代碼片段。
  • Tensorflow實戰系列:手把手教你使用CNN進行圖像分類(附完整代碼)
    本教程旨在手把手教大家使用Tensorflow構建卷積神經網絡(CNN)進行圖像分類。教程並沒有使用MNIST數據集,而是使用了真實的圖片文件,並且教程代碼包含了模型的保存、加載等功能,因此希望在日常項目中使用Tensorflow的朋友可以參考這篇教程。完整代碼可在專知成員Hujun的Github中下載。
  • CNN-RNN中文文本分類,基於TensorFlow 實現
    /2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/以及字符級CNN的論文:https://arxiv.org/abs/1509.01626本文是基於TensorFlow在中文數據集上的簡化實現,使用了字符級CNN和RNN對中文文本進行分類,達到了較好的效果。
  • 利用DeepLab在Tensorflow中進行語義圖像分割
    分配這些語義標籤需要標出對象的輪廓,因此,它對定位精度的要求比其他視覺實體識別任務(例如圖像級分類或邊界框級檢測)更加嚴格。我們高興地宣布將 Google 最新、性能最好的語義圖像分割模型 DeepLab-v3+ (在 Tensorflow 中實現)開源:https://github.com/tensorflow/models/tree/master/research/deeplab此次發布包括基於一個強大的卷積神經網絡 (CNN) 骨幹架構構建的 DeepLab-v3
  • 使用PixelLib來實現圖像分割
    圖像分割是在像素級對圖像進行分類的任務。機器能夠根據分配給圖像中每個像素值的類將圖像分割成不同的段,從而更有效地分析圖像。在圖像分割中採用的獨特技術使其適用於解決某些計算機視覺問題。這些問題需要有關圖像中出現的對象詳細信息,無法通過對整個圖像進行分類或為圖像中存在的對象提供邊界框來提供詳細信息。