天天看點

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

一、CNN的引入

本文轉部落格:http://blog.csdn.net/lyc_yongcai/article/details/73237090

在人工的全連接配接神經網絡中,每相鄰兩層之間的每個神經元之間都是有邊相連的。當輸入層的特征次元變得很高時,這時全連接配接網絡需要訓練的參數就會增大很多,計算速度就會變得很慢,例如一張黑白的 28×28 的手寫數字圖檔,輸入層的神經元就有784個,如下圖所示: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

若在中間隻使用一層隐藏層,參數 w 就有 784×15=11760 多個;若輸入的是28×28帶有顔色的RGB格式的手寫數字圖檔,輸入神經元就有28×28×3=2352 個…… 。這很容易看出使用全連接配接神經網絡處理圖像中的需要訓練參數過多的問題。

而在卷積神經網絡(Convolutional Neural Network,CNN)中,卷積層的神經元隻與前一層的部分神經元節點相連,即它的神經元間的連接配接是非全連接配接的,且同一層中某些神經元之間的連接配接的權重 w 和偏移 b 是共享的(即相同的),這樣大量地減少了需要訓練參數的數量。

卷積神經網絡CNN的結構一般包含這幾個層:

  • 輸入層:用于資料的輸入
  • 卷積層:使用卷積核進行特征提取和特征映射
  • 激勵層:由于卷積也是一種線性運算,是以需要增加非線性映射
  • 池化層:進行下采樣,對特征圖稀疏處理,減少資料運算量。
  • 全連接配接層:通常在CNN的尾部進行重新拟合,減少特征資訊的損失
  • 輸出層:用于輸出結果

當然中間還可以使用一些其他的功能層:

  • 歸一化層(Batch Normalization):在CNN中對特征的歸一化
  • 切分層:對某些(圖檔)資料的進行分區域的單獨學習
  • 融合層:對獨立進行特征學習的分支進行融合

二、CNN的層次結構

輸入層:

在CNN的輸入層中,(圖檔)資料輸入的格式 與 全連接配接神經網絡的輸入格式(一維向量)不太一樣。CNN的輸入層的輸入格式保留了圖檔本身的結構。

對于黑白的 28×28 的圖檔,CNN的輸入是一個 28×28 的的二維神經元,如下圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

而對于RGB格式的28×28圖檔,CNN的輸入則是一個 3×28×28 的三維神經元(RGB中的每一個顔色通道都有一個 28×28 的矩陣),如下圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

卷積層:

在卷積層中有幾個重要的概念:

  • local receptive fields(感受視野)
  • shared weights(共享權值)

假設輸入的是一個 28×28 的的二維神經元,我們定義5×5 的 一個 local receptive fields(感受視野),即 隐藏層的神經元與輸入層的5×5個神經元相連,這個5*5的區域就稱之為Local Receptive Fields,如下圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

可類似看作:隐藏層中的神經元 具有一個固定大小的感受視野去感受上一層的部分特征。在全連接配接神經網絡中,隐藏層中的神經元的感受視野足夠大乃至可以看到上一層的所有特征。

而在卷積神經網絡中,隐藏層中的神經元的感受視野比較小,隻能看到上一次的部分特征,上一層的其他特征可以通過平移感受視野來得到同一層的其他神經元,由同一層其他神經元來看:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

設移動的步長為1:從左到右掃描,每次移動 1 格,掃描完之後,再向下移動一格,再次從左到右掃描。

具體過程如動圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹
深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

可看出 卷積層的神經元是隻與前一層的部分神經元節點相連,每一條相連的線對應一個權重 w 。

一個感受視野帶有一個卷積核,我們将 感受視野 中的權重 w 矩陣稱為 卷積核 ;将感受視野對輸入的掃描間隔稱為步長(stride);當步長比較大時(stride>1),為了掃描到邊緣的一些特征,感受視野可能會“出界”,這時需要對邊界擴充(pad),邊界擴充可以設為 0 或 其他值。步長 和 邊界擴充值的大小由使用者來定義。

卷積核的大小由使用者來定義,即定義的感受視野的大小;卷積核的權重矩陣的值,便是卷積神經網絡的參數,為了有一個偏移項 ,卷積核可附帶一個偏移項 b ,它們的初值可以随機來生成,可通過訓練進行變化。

是以 感受視野 掃描時可以計算出下一層神經元的值為:

b+∑i=04∑j=04wijxij

對下一層的所有神經元來說,它們從不同的位置去探測了上一層神經元的特征。

我們将通過 一個帶有卷積核的感受視野 掃描生成的下一層神經元矩陣 稱為 一個feature map (特征映射圖),如下圖的右邊便是一個 feature map:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

是以在同一個 feature map 上的神經元使用的卷積核是相同的,是以這些神經元 shared weights,共享卷積核中的權值和附帶的偏移。一個 feature map 對應 一個卷積核,若我們使用 3 個不同的卷積核,可以輸出3個feature map:(感受視野:5×5,布長stride:1)

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

是以在CNN的卷積層,我們需要訓練的參數大大地減少到了 (5×5+1)×3=78個。

假設輸入的是 28×28 的RGB圖檔,即輸入的是一個 3×28×28 的的二維神經元,這時卷積核的大小不隻用長和寬來表示,還有深度,感受視野也對應的有了深度,如下圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

由圖可知:感受視野: 3×2×2 ; 卷積核: 3×2×2 ,深度為3;下一層的神經元的值為:b+∑2d=0∑1i=0∑1j=0wdijxdij . 卷積核的深度和感受視野的深度相同,都由輸入資料來決定,長寬可由自己來設定,數目也可以由自己來設定,一個卷積核依然對應一個 feature map。

注:“stride=1”表示在長和寬上的移動間隔都為1,即 stridewidth=1 且 strideheight=1

激勵層:

激勵層主要對卷積層的輸出進行一個非線性映射,因為卷積層的計算還是一種線性計算。使用的激勵函數一般為ReLu函數:

f(x)=max(x,0)

卷積層和激勵層通常合并在一起稱為“卷積層”。

池化層:

當輸入經過卷積層時,若感受視野比較小,布長stride比較小,得到的feature map (特征圖)還是比較大,可以通過池化層來對每一個 feature map 進行降維操作,輸出的深度還是不變的,依然為 feature map 的個數。

池化層也有一個“池化視野(filter)”來對feature map矩陣進行掃描,對“池化視野”中的矩陣值進行計算,一般有兩種計算方式:

  • Max pooling:取“池化視野”矩陣中的最大值
  • Average pooling:取“池化視野”矩陣中的平均值

掃描的過程中同樣地會涉及的掃描布長stride,掃描方式同卷積層一樣,先從左到右掃描,結束則向下移動布長大小,再從左到右。如下圖示例所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

其中“池化視野”filter: 2×2;布長stride:2。(注:“ 池化視野”為個人叫法)

最後可将 3 個 24×24 的 feature map 下采樣得到 3 個 24×24 的特征矩陣:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

歸一化層:

1. Batch Normalization

Batch Normalization(批量歸一化)實作了在神經網絡層的中間進行預處理的操作,即在上一層的輸入歸一化處理後再進入網絡的下一層,這樣可有效地防止“梯度彌散”,加速網絡訓練。

Batch Normalization具體的算法如下圖所示: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

每次訓練時,取 batch_size 大小的樣本進行訓練,在BN層中,将一個神經元看作一個特征,batch_size 個樣本在某個特征次元會有 batch_size 個值,然後在每個神經元 xi 次元上的進行這些樣本的均值和方差,通過公式得到 xi∧,再通過參數 γ 和 β 進行線性映射得到每個神經元對應的輸出 yi 。在BN層中,可以看出每一個神經元次元上,都會有一個參數 γ 和 β ,它們同權重w一樣可以通過訓練進行優化。

在卷積神經網絡中進行批量歸一化時,一般對 未進行ReLu激活的 feature map進行批量歸一化,輸出後再作為激勵層的輸入,可達到調整激勵函數偏導的作用。

一種做法是将 feature map 中的神經元作為特征次元,參數 γ 和 β 的數量和則等于 2×fmapwidth×fmaplength×fmapnum,這樣做的話參數的數量會變得很多;

另一種做法是把 一個 feature map 看做一個特征次元,一個 feature map 上的神經元共享這個 feature map的 參數 γ 和 β ,參數 γ 和 β 的數量和則等于 2×fmapnum,計算均值和方差則在batch_size個訓練樣本在每一個feature map次元上的均值和方差。

注:fmapnum指的是一個樣本的feature map數量,feature map 跟神經元一樣也有一定的排列順序。

Batch Normalization 算法的訓練過程和測試過程的差別:

在訓練過程中,我們每次都會将 batch_size 數目大小的訓練樣本 放入到CNN網絡中進行訓練,在BN層中自然可以得到計算輸出所需要的 均值 和 方差 ;

而在測試過程中,我們往往隻會向CNN網絡中輸入一個測試樣本,這是在BN層計算的均值和方差會均為 0,因為隻有一個樣本輸入,是以BN層的輸入也會出現很大的問題,進而導緻CNN網絡輸出的錯誤。是以在測試過程中,我們需要借助訓練集中所有樣本在BN層歸一化時每個次元上的均值和方差,當然為了計算友善,我們可以在 batch_num 次訓練過程中,将每一次在BN層歸一化時每個次元上的均值和方差進行相加,最後再進行求一次均值即可。

2. Local Response Normalization

近鄰歸一化(Local Response Normalization)的歸一化方法主要發生在不同的相鄰的卷積核(經過ReLu之後)的輸出之間,即輸入是發生在不同的經過ReLu之後的 feature map 中。

LRN的公式如下:

b(i,x,y)=a(i,x,y)(k+α∑min(N−1,i+n/2)j=max(0,i−n/2)a(j,x,y)2) β

其中: 

a(i,x,y) 表示第i個卷積核的輸出(經過ReLu層)的feature map上的 (x,y) 位置上的值。 

b(i,x,y) 表示 a(i,x,y) 經LRN後的輸出。 

N 表示卷積核的數量,即輸入的 feature map的個數。 

n 表示近鄰的卷積核(或feature map)個數,由自己來決定。 

k,α,β是超參數,由使用者自己調整或決定。

與BN的差別:BN依據mini batch的資料,近鄰歸一僅需要自己來決定,BN訓練中有學習參數;BN歸一化主要發生在不同的樣本之間,LRN歸一化主要發生在不同的卷積核的輸出之間。

切分層:

在一些應用中,需要對圖檔進行切割,獨立地對某一部分區域進行單獨學習。這樣可以對特定部分進行通過調整 感受視野 進行力度更大的學習。

融合層:

融合層可以對切分層進行融合,也可以對不同大小的卷積核學習到的特征進行融合。

例如在GoogleLeNet 中,使用多種分辨率的卷積核對目标特征進行學習,通過 padding 使得每一個 feature map 的長寬都一緻,之後再将多個 feature map 在深度上拼接在一起: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

融合的方法有幾種,一種是特征矩陣之間的拼接級聯,另一種是在特征矩陣進行運算 (+,−,x,max,conv)。

全連接配接層和輸出層

全連接配接層主要對特征進行重新拟合,減少特征資訊的丢失;輸出層主要準備做好最後目标結果的輸出。例如VGG的結構圖,如下圖所示: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

典型的卷積神經網絡

LeNet-5模型

第一個成功應用于數字數字識别的卷積神經網絡模型(卷積層自帶激勵函數,下同):

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

卷積層的卷積核邊長都是5,步長都為1;池化層的視窗邊長都為2,步長都為2。

AlexNet 模型

具體結構圖:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

從AlexNet的結構可發現:經典的卷積神經網絡結構通常為:

輸入層 → (卷積層+→池化層?)+→全連接配接層+→輸出層

AlexNet卷積層的卷積核邊長為5或3,池化層的視窗邊長為3。具體參數如圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

VGGNet 模型

VGGNet 模型 和 AlexNet模型 在結構上沒多大變化,在卷積層部位增加了多個卷積層。AlexNet(上) 和 VGGNet (下)的對比如下圖所示:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

具體參數如圖所示:其中CONV3-64:表示卷積核的長和寬為3,個數有64個;POOL2:表示池化視窗的長和寬都為2,其他類似。 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

GoogleNet 模型

使用了多個不同分辨率的卷積核,最後再對它們得到的feature map 按深度融合在一起,結構如圖:

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

其中,有一些主要的子產品稱為 Inception module,例如: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

在 Inception module 中使用到了很多 1×1 的卷積核,使用 1×1 的卷積核,步長為1時,輸入的feature map和輸出的feature map長寬不會發生改變,但可以通過改變 1×1 的卷積核的數目,來達到減小feature map的厚度的效果,進而做到一些訓練參數的減少。

GoogleNet還有一個特點就是它是全卷積結構(FCN)的,網絡的最後沒有使用全連接配接層,一方面這樣可以減少參數的數目,不容易過拟合,一方面也帶來了一些空間資訊的丢失。代替全連接配接層的是全局平均池化(Global Average Pooling,GAP)的方法,思想是:為每一個類别輸出一個feature map ,再取每一個 feature map上的平均值,作為最後的softmax層的輸入。

ResNet模型

在前面的CNN模型中,都是将輸入一層一層地傳遞下去(圖左),當層次比較深時,模型不是很好訓練。在ResNet模型中,它将低層學習到的特征和高層的學習到的特征進行一個融合(加法運算,圖右),這樣反向傳遞時,導數傳遞得更快,減少梯度彌散的現象。

注意:F(X)的shape需要等于 X 的shape ,這樣才可以進行相加。

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹

四、Tensorflow代碼

主要的函數說明:

卷積層: 

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

參數說明:
  • data_format:表示輸入的格式,有兩種分别為:“NHWC”和“NCHW”,預設為“NHWC”
  • input:輸入是一個4維格式的(圖像)資料,資料的 shape 由 data_format 決定:當 data_format 為“NHWC”輸入資料的shape表示為[batch, in_height, in_width, in_channels],分别表示訓練時一個batch的圖檔數量、圖檔高度、 圖檔寬度、 圖像通道數。當 data_format 為“NHWC”輸入資料的shape表示為[batch, in_channels, in_height, in_width]
  • filter:卷積核是一個4維格式的資料:shape表示為:[height,width,in_channels, out_channels],分别表示卷積核的高、寬、深度(與輸入的in_channels應相同)、輸出 feature map的個數(即卷積核的個數)。
  • strides:表示步長:一個長度為4的一維清單,每個元素跟data_format互相對應,表示在data_format每一維上的移動步長。當輸入的預設格式為:“NHWC”,則 strides = [batch , in_height , in_width, in_channels]。其中 batch 和 in_channels 要求一定為1,即隻能在一個樣本的一個通道上的特征圖上進行移動,in_height , in_width表示卷積核在特征圖的高度和寬度上移動的布長,即 strideheight 和 stridewidth 。
  • padding:表示填充方式:“SAME”表示采用填充的方式,簡單地了解為以0填充邊緣,但還有一個要求,左邊(上邊)補0的個數和右邊(下邊)補0的個數一樣或少一個,“VALID”表示采用不填充的方式,多餘地進行丢棄。具體公式:

    “SAME”: output_spatial_shape[i]=⌈(input_spatial_shape[i] / strides[i])⌉

    “VALID”: output_spatial_shape[i]=⌈((input_spatial_shape[i]−(spatial_filter_shape[i]−1)/strides[i])⌉

池化層: 

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

或者 

tf.nn.avg_pool(…)

參數說明:
  • value:表示池化的輸入:一個4維格式的資料,資料的 shape 由 data_format 決定,預設情況下shape 為[batch, height, width, channels]
  • 其他參數與 tf.nn.cov2d 類型
  • ksize:表示池化視窗的大小:一個長度為4的一維清單,一般為[1, height, width, 1],因不想在batch和channels上做池化,則将其值設為1。

Batch Nomalization層: 

batch_normalization( x,mean,variance,offset,scale, variance_epsilon,name=None)

  • mean 和 variance 通過 tf.nn.moments 來進行計算: 

    batch_mean, batch_var = tf.nn.moments(x, axes = [0, 1, 2], keep_dims=True),注意axes的輸入。對于以feature map 為次元的全局歸一化,若feature map 的shape 為[batch, height, width, depth],則将axes指派為[0, 1, 2]

  • x 為輸入的feature map 四維資料,offset、scale為一維Tensor資料,shape 等于 feature map 的深度depth。

代碼示例:

通過搭建卷積神經網絡來實作sklearn庫中的手寫數字識别,搭建的卷積神經網絡結構如下圖所示: 

深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹(轉載) 深度學習之卷積神經網絡CNN及tensorflow代碼實作示例詳細介紹
import tensorflow as tf
           
from sklearn.datasets import load_digits
import numpy as np
           
digits = load_digits()
X_data = digits.data.astype(np.float32)
Y_data = digits.target.astype(np.float32).reshape(-,)
print X_data.shape
print Y_data.shape                
(1797, 64)
(1797, 1)
           
from sklearn.preprocessing import MinMaxScaler
           
scaler = MinMaxScaler()
           
X_data = scaler.fit_transform(X_data)
           
from sklearn.preprocessing import OneHotEncoder
           
matrix([[ 1.,  0.,  0., ...,  0.,  0.,  0.],
        [ 0.,  1.,  0., ...,  0.,  0.,  0.],
        [ 0.,  0.,  1., ...,  0.,  0.,  0.],
        ..., 
        [ 0.,  0.,  0., ...,  0.,  1.,  0.],
        [ 0.,  0.,  0., ...,  0.,  0.,  1.],
        [ 0.,  0.,  0., ...,  0.,  1.,  0.]])
           
# 轉換為圖檔的格式 (batch,height,width,channels)
X = X_data.reshape(-,,,)
           
def generatebatch(X,Y,n_examples, batch_size):
    for batch_i in range(n_examples // batch_size):
        start = batch_i*batch_size
        end = start + batch_size
        batch_xs = X[start:end]
        batch_ys = Y[start:end]
        yield batch_xs, batch_ys # 生成每一個batch
           
tf.reset_default_graph()
# 輸入層
tf_X = tf.placeholder(tf.float32,[None,,,])
tf_Y = tf.placeholder(tf.float32,[None,])
           
# 卷積層+激活層
conv_filter_w1 = tf.Variable(tf.random_normal([, , , ]))
conv_filter_b1 =  tf.Variable(tf.random_normal([]))
relu_feature_maps1 = tf.nn.relu(\
                tf.nn.conv2d(tf_X, conv_filter_w1,strides=[, , , ], padding='SAME') + conv_filter_b1)
           
# 池化層
max_pool1 = tf.nn.max_pool(relu_feature_maps1,ksize=[,,,],strides=[,,,],padding='SAME')
           
print max_pool1
           
Tensor("MaxPool:0", shape=(?, 4, 4, 10), dtype=float32)
           
# 卷積層
conv_filter_w2 = tf.Variable(tf.random_normal([, , , ]))
conv_filter_b2 =  tf.Variable(tf.random_normal([]))
conv_out2 = tf.nn.conv2d(relu_feature_maps1, conv_filter_w2,strides=[, , , ], padding='SAME') + conv_filter_b2
print conv_out2
           
Tensor("add_4:0", shape=(?, 4, 4, 5), dtype=float32)
           
# BN歸一化層+激活層 
batch_mean, batch_var = tf.nn.moments(conv_out2, [, , ], keep_dims=True)
shift = tf.Variable(tf.zeros([]))
scale = tf.Variable(tf.ones([]))
epsilon = 
BN_out = tf.nn.batch_normalization(conv_out2, batch_mean, batch_var, shift, scale, epsilon)
print BN_out
relu_BN_maps2 = tf.nn.relu(BN_out)
           
Tensor("batchnorm/add_1:0", shape=(?, 4, 4, 5), dtype=float32)
           
# 池化層
max_pool2 = tf.nn.max_pool(relu_BN_maps2,ksize=[,,,],strides=[,,,],padding='SAME')
           
print max_pool2
           
Tensor("MaxPool_1:0", shape=(?, 2, 2, 5), dtype=float32)
           
# 将特征圖進行展開
max_pool2_flat = tf.reshape(max_pool2, [-, **])
           
# 全連接配接層
fc_w1 = tf.Variable(tf.random_normal([**,]))
fc_b1 =  tf.Variable(tf.random_normal([]))
fc_out1 = tf.nn.relu(tf.matmul(max_pool2_flat, fc_w1) + fc_b1)
           
# 輸出層
out_w1 = tf.Variable(tf.random_normal([,]))
out_b1 = tf.Variable(tf.random_normal([]))
pred = tf.nn.softmax(tf.matmul(fc_out1,out_w1)+out_b1)
           
loss = -tf.reduce_mean(tf_Y*tf.log(tf.clip_by_value(pred,,)))
           
train_step = tf.train.AdamOptimizer().minimize(loss)
           
y_pred = tf.arg_max(pred,)
bool_pred = tf.equal(tf.arg_max(tf_Y,),y_pred)
           
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(): # 疊代1000個周期
        for batch_xs,batch_ys in generatebatch(X,Y,Y.shape[],batch_size): # 每個周期進行MBGD算法
            sess.run(train_step,feed_dict={tf_X:batch_xs,tf_Y:batch_ys})
        if(epoch%==):
            res = sess.run(accuracy,feed_dict={tf_X:X,tf_Y:Y})
            print (epoch,res)
    res_ypred = y_pred.eval(feed_dict={tf_X:X,tf_Y:Y}).flatten() # 隻能預測一批樣本,不能預測一個樣本
    print res_ypred
           
(0, 0.36338341)
(100, 0.96828049)
(200, 0.99666113)
(300, 0.99554813)
(400, 0.99888706)
(500, 0.99777406)
(600, 0.9961046)
(700, 0.99666113)
(800, 0.99499166)
(900, 0.99888706)
[0 1 2 ..., 8 9 8]
           
在第100次個batch size 疊代時,準确率就快速接近收斂了,這得歸功于Batch Normalization 的作用!需要注意的是,這個模型還不能用來預測單個樣本,因為在進行BN層計算時,單個樣本的均值和方差都為0,會得到相反的預測效果,解決方法詳見歸一化層。
from sklearn.metrics import  accuracy_score
           
print accuracy_score(Y_data,res_ypred.reshape(-,))
           
0.998887033945
           

繼續閱讀