卷積神經(jīng)網(wǎng)絡(Convolutional Neural Network,CNN),一般卷積神經(jīng)網(wǎng)路由多個卷積層構(gòu)成,每個卷積層中通常會進行如下幾個操作:
(1)圖像通過多個不同的卷積核的濾波,并加偏置(bias),提取出局部特征,每一個卷積核會映射出一個新的2D圖像。
(2)將前面卷積核的濾波輸出結(jié)果,進行非線性的激活函數(shù)處理,目前最常見的是ReLu函數(shù),而以前Sigmoid函數(shù)用的比較多。
(3)對激活函數(shù)的結(jié)果再進行池化操作(即降采樣6,比如2x2的圖片降維1x1的圖片),目前一般是使用最大池化,保留最顯著的特征,并提升模型的畸變?nèi)萑棠芰Α?/p>
一個卷積層中可以有多個不同的卷積核,而每一個卷積核都對應一個濾波后映射出的新圖像,同一個新圖像中每一個像素都來自完全相同的卷積核,這就是卷積核的權(quán)值共享。卷積核的大小,一般為3X3,5X5,7X7,1x1。卷積操作是局部連接方式,比如整個圖像是1000x1000像素,卷積核是10x10,那圖像的維度就是100,一個卷積核對應一個隱藏節(jié)點,隱藏層節(jié)點就是1W個。如果只有一個卷積核,就只能提取一種卷積核濾波的結(jié)果,即只能提出一種圖片特征。我么可以增加卷積核的數(shù)量多提取一些特征。每一個卷積核濾波得到的圖像就是一類特征的映射,即一個Feature Map.
卷積的好處是,不管圖片尺寸如何,我們需要訓練的權(quán)值數(shù)量只跟卷積核大小、卷積核數(shù)量有關(guān),我們可以使用非常少的參數(shù)量處理任意大小的圖片。隱藏節(jié)點的數(shù)量只跟卷積的步長有關(guān),如果步長為1,那么隱藏節(jié)點的數(shù)量和輸入的圖像的像素數(shù)量一致;如果步長為5,那么每5X5的像素才需要一個隱藏節(jié)點,我們隱藏節(jié)點的數(shù)量就是輸入像素數(shù)量的1/25.
總結(jié)一下,卷積神經(jīng)網(wǎng)絡的要點就是局部連接、權(quán)值共享和池化層中的降采樣。其中局部連接和權(quán)值共享降低了參數(shù)量,使訓練復雜度大大下降,并減輕了過擬合。同時,權(quán)值共享還賦予了卷積網(wǎng)絡對平移的容忍性,而池化曾降采樣則進一步降低了輸出參數(shù)量,并賦予模型對輕度形變的容忍性,提高了模型的泛化能力。
======================================================================================
Tensorflow實現(xiàn)簡單的卷積神經(jīng)網(wǎng)絡
這個簡單的卷積神經(jīng)網(wǎng)絡使用兩個卷積層加一個全連接層構(gòu)建一個簡單但是非常有代表性的卷積神經(jīng)網(wǎng)絡。
首先載入MNIST數(shù)據(jù)集,并創(chuàng)建默認的interactive Session
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist=input_data.read_data_sets('/tmp/data',one_hot=True)
sess=tf.InteractiveSession()
接下來是實現(xiàn)這個卷積神經(jīng)網(wǎng)絡會有很多權(quán)重和偏置需要創(chuàng)建,因此我們先定義好初始化函數(shù)以便重復使用。我們需要給權(quán)重制造一些隨機的噪聲來打破完全對稱,比如截斷的正太分布噪聲,標準差為0.1.同時因為我們使用ReLu函數(shù),也給偏置增加一些小的正值(0.1)用來避免死亡節(jié)點。
def weight_variable(shape):
? initial=tf.truncated_normal(shape,stddev=0.1)
? return tf.Variable(initial)
def bias_variable(shape):
? initial=tf.constant(0.1,shape=shape)
? return tf.Variable(initial)
卷積層、池化層也是接下來重復使用的,也為他們分別定義創(chuàng)建函數(shù)。這里的tf.nn.conv2d是tensorflow中的2維卷積函數(shù),參數(shù)中x是輸入,
w是卷積參數(shù),比如[5,5,1,32]:前面兩個數(shù)字代表卷積核的尺寸;第三個數(shù)字代表有多少個channel。因為我們只有灰度單色,所以是1,如果是彩色的RGB圖片,這里應該是3;最后一個數(shù)字代表卷積核的數(shù)量,也就是這個卷積層會提取多少類的特征(多少個不同的卷積核)。
strides代表卷積模板移動的步長,都是1代表會不遺漏地劃過圖片的每一個點。strides[0]和strides[3]的兩個1是默認值,中間兩個1代表padding時在x方向運動一步,y方向運動一步。
Padding代表邊界的處理方式,這里SAME代表邊界加上Padding讓卷積的輸出和輸入保持同樣的尺寸。
tf.nn.max_pool是Tensorflow中最大池化函數(shù),這里使用2x2的最大池化,即講一個2X2的像素塊降維1x1的像素。最大池化會保留原始像素塊中灰度值最高的哪一個像素,即保留最顯著的特征。池化的核函數(shù)大小為2X2.
因為希望整體上縮小圖片尺寸,因此池化層的strides也設(shè)為橫豎兩個方向以2為步長。
def conv2d(x,w):
return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding='SAME')
def max_pool_2X2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
在正式設(shè)計卷積神經(jīng)網(wǎng)絡結(jié)構(gòu)之前,先定義輸入的placeholder,x是特征,y_是真實的label。因為卷積神經(jīng)網(wǎng)絡利用到空間結(jié)構(gòu)信息,因襲需要將1維的輸入向量轉(zhuǎn)為2維的圖片結(jié)構(gòu),即從1X784->28X28,同時因為只有一個顏色通道,故最終尺寸為[-1,28,28,1],前面的-1代表樣本數(shù)量不固定,最后的1代表顏色通道數(shù)量。這里使用的tensor變形函數(shù)是tf.reshape
x=tf.placeholder(tf.float32,[None,784])
y_=tf.placeholder(tf.float32,[None,10])
x_image=tf.reshape(x,[-1,28,28,1])
接下來定義我們的第一個卷積層。我們先使用前面寫好的函數(shù)進行參數(shù)初始化,包括weights和bias。這里的[5,5,1,32],代表卷積核尺寸為5X5,1個顏色通道,32個不同的卷積核。然后使用conv2d函數(shù)進行卷積操作,并加上偏置,接著再使用ReLu激活函數(shù)進行非線性處理。最后,使用最大池化函數(shù)max_pool_2x2對卷積的輸出結(jié)果進行池化操作。
w_conv1=weight_variable([5,5,1,32])
b_conv1=bias_variable([32])
h_conv1=tf.nn.relu(conv2d(x_image,w_conv1)+b_conv1)
h_pool1=max_pool_2X2(h_conv1)
現(xiàn)在定義第二個卷積層,這個卷積層基本和第一個卷積層一樣,唯一的不同是卷積核的數(shù)量編程了64,也就是說這一層的卷積會提取64中 特征。上一層的卷積核數(shù)量為32(即輸出32個通道),所以本卷積和尺寸的第三個維度即輸入的通道數(shù)也需要調(diào)整為32
w_conv2=weight_variable([5,5,32,64])
b_conv2=bias_variable([64])
h_conv2=tf.relu(conv2d(h_pool1,w_conv2)+b_conv2)
h_pool2=max_pool_2X2(h_conv2)
因為前面經(jīng)歷了兩次步長為2x2的最大池化,所以邊長已經(jīng)只有1/4了,圖片的尺寸由28x28變成了7x7.而第二個卷積層的卷積核數(shù)量為64,其輸出的tensor尺寸即為7x7x64。我們使用tf.reshape函數(shù)對第二個卷積層的輸出tensor進行變形,將其轉(zhuǎn)成1維的向量,然后連接一個全連接層,隱層節(jié)點數(shù)為1024,并使用ReLu函數(shù)。
w_fc1=weight_variable([7*7*64,1024])
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,w_fc1)+b_fc1)
為了減輕過擬合,下面使用一個Dropout層,Dropout,通過一個placeholder傳入keep_prob比率來控制。在訓練的時候,我們隨機丟棄一部分節(jié)點的數(shù)據(jù)來減輕過擬合,預測時則保留全部數(shù)據(jù)來追求最好的預測性能。
keep_prob=tf.placeholder(tf.float32)
h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)
最后我們將Dropout層的輸出連接一個softmax層,得到最后的概率輸出。
w_fc2=weight_variable([1024,10])
b_fc2=bias_variable([10])
y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop,w_fc2)+b_fc2)
在來定義損失函數(shù)為cross_entropy,優(yōu)化器為adam,并給一個比較小的學習速率1e-4
cross_entropy=tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y_conv),reduction_indices=[1]))
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
再繼續(xù)定義評測準確率的操作
correct_prediction=tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
下面開始訓練過程。首先依然是初始化所有參數(shù),設(shè)置訓練時dropout的keep_prob比率為0.5,然后使用大小為50的mini-batch,共進行20000次迭代,參與訓練的樣本數(shù)量總共為100W,其中每100次訓練,我們會對準確率進行一次評測(評測時keep_prob設(shè)為1),用以實時監(jiān)測模型的性能。
tf.global_variables_initializer().run()
for i in range(20000):
batch=mnist.train.next_batch(50)
if i%100==0:
train_accuracy=accuracy.eval(feed_dict={x:batch[0],y_:batch[1],keep_prob:1.0})
print 'step %d,training accuracy %g'%(i,train_accuracy)
train_step.run(feed_dict={x:batch[0],y_:batch[1],keep_prob:0.5})
print 'test accuracy %g'% accuracy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels,keep_prob:1.0})
全部訓練完成后,我們再最終的測試集上進行全面測試,得到整體的分類準確率。========99.16%
=====================================================================================
Tensorflow實現(xiàn)進階的卷積神經(jīng)網(wǎng)絡
使用的數(shù)據(jù)集是CIFAR-10
先下載tensorflow models庫,以便使用其中提供的CIFAR-10的數(shù)據(jù)類
git clone https://github.com/tensorflow/models.git
cd models/tutorials/image/cifar10
然后我們載入一些常用庫,并載入Tensorflow models中自動下載。讀取CIFAR-10數(shù)據(jù)的類。
import cifar10,cifar10_input
import tensorflow as tf
import numpy as np
import time
接著定義batch_size、訓練輪數(shù)max_steps,以及下載CIFAR-10數(shù)據(jù)的默認路徑。
max_steps=3000
batch_size=128
data_dir='/tmp/cifar10_data/cifar-10-batches-bin'
定義初始化的權(quán)重函數(shù),和之前一樣使用tf.truncated_normal階段的整他分布來初始化權(quán)重。但是這里我們給weight加一個L2的loss,相當于一個L2的正則化處理。
在機器學習中,因特征過多而導致過擬合,一般可以通過減少特征或者懲罰不重要特征的權(quán)重來緩解這個問題。但是通常我們并不知道該懲罰哪些特征的權(quán)重,而正則化就是版主我們懲罰特征權(quán)重的,即特征的權(quán)重也會成為模型損失函數(shù)的一部分??梢岳斫鉃?,為了使用某個特征,我們需要付出loss的代價,除非這個特征非常有效,否則就會被loss上的增加覆蓋效果。這樣我們就可以篩選出最有效的特征,減少特征權(quán)重防止過擬合。
一般來說L1正則會制造稀疏的特征,大部分無用特征的權(quán)重會被置為0,而L2正則會讓特征的權(quán)重不過大,使得特征的權(quán)重比較平均。
我們使用w1控制L2 loss的大小,使tf.nn.l2_loss函數(shù)計算weight的L2 loss,在使用tf.multiply 讓L2 loss乘以w1,得到最后的weight loss。接著我們使用tf.add_to_collection 把weight loss統(tǒng)一存到一個collection,讓這個'collection'名為‘losses’,它會在后面計算神經(jīng)網(wǎng)絡的總體loss時被用上。
def variable_with_weight_loss(shape,stddev,w1):
var=tf.Variable(tf.truncated_normal(shape,stddev=stddev))
if w1 is not None:
weight_loss=tf.multiply(tf.nn.l2_loss(var),w1,name='weight_loss')
tf.add_to_collection('losses',weight_loss)
return var
下面使用cifar10類下載數(shù)據(jù)集,并解壓,展開到其默認位置。
cifar10.maybe_download_and_extract()
再使用cifar10_inputs類中的distorted_inputs函數(shù)產(chǎn)生訓練需要使用的數(shù)據(jù),包括特征及其對應的label,這里返回的是已經(jīng)封裝好的tensor,每次執(zhí)行都會生成一個batch_size的數(shù)量的樣本。
需要注意的是我們隊數(shù)據(jù)進行了data augmentation(數(shù)據(jù)增強)。具體細節(jié)可查看cifar10_input.distorted_inputs函數(shù),其中數(shù)據(jù)增強操作包括隨機的水平翻轉(zhuǎn)(tf.image.random_flip_left_right)、隨機剪切一塊24x24代銷的圖片(tf.random_crop)、設(shè)置隨機的亮度和對比度(tf.image.random_brightness,tf.image.random_contrast),以及對數(shù)據(jù)進行標準化tf.image.per_image_whitening(對數(shù)據(jù)減去均值,除以方差,保證數(shù)據(jù)0均值,方差為1)。通過這些操作,我們可以獲得更多的樣本(帶噪聲的),原來的一張圖片樣本可以變?yōu)槎鄰垐D片,相當于擴大樣本量,對提高準確率非常有幫助。需要注意的是,我們對圖像進行數(shù)據(jù)增強的操作需要耗費大量的CPU時間,因此distorted_inputs使用了16個獨立的縣城來加速任務,函數(shù)內(nèi)部會產(chǎn)生線程池,在需要使用時會通過tensorflow queue進行調(diào)度。
images_train.labels_train=cifar10_input.distorted_inputs(data_dir=data_dir,batch_size=batch_size)
我們再使用cifar10_inputs.inputs函數(shù)生成測試數(shù)據(jù),這里不需要進行太多處理,不需要對圖片進行翻轉(zhuǎn)或修改亮度、對比度,不過需要裁剪圖片正中間的24x24大小的區(qū)塊,并進行數(shù)據(jù)標準化操作。
images_test,labels_test=cifar10_input.inputs(eval_data=True,data_dir=data_dir,batch-size=batch_size)
接下來創(chuàng)建輸入數(shù)據(jù)的placeholder,包括特征和label。在設(shè)定placeholder的數(shù)據(jù)尺寸時需要注意,因為batch_size在之后定義網(wǎng)路結(jié)構(gòu)時被用到了,所以數(shù)據(jù)尺寸中的第一個值即為樣本條數(shù)需要被預先設(shè)定,而不能像以前一樣可以設(shè)為None.而數(shù)據(jù)尺寸中的圖片尺寸為24x24,即是裁剪后的大小,而顏色通過數(shù)設(shè)為3,代表圖片是彩色有RGB三條通道。
image_holder=tf.placeholder(tf.float32,[batch_size,24,24,3])
label_holder=tf.placeholder(tf.int32,[batch_size])
準備工作做好,開始創(chuàng)建第一個卷積層。使用之前創(chuàng)建好的variable_with_weight_loss函數(shù)創(chuàng)建卷積核的參數(shù)并進行初始化。第一個卷積層使用5x5的卷積核大小,3個顏色通道,64個卷積核,同時設(shè)置weight初始化函數(shù)的標準差為0.05。我們部隊第一個卷積層的weight進行L2的正則,因此w1(weight loss)這一項設(shè)為0,下面使用tf.nn.conv2d函數(shù)對輸入數(shù)據(jù)image_holder進行卷積操作,這里的步長stride設(shè)為1,padding 模式為SAME。把這層的bias全部初始化為0,再將卷積的結(jié)果加上bias,最后使用一個ReLu激活函數(shù)進行非線性化。在relu后,我們使用一個尺寸為3x3,且步長為2x2的最大池化層處理數(shù)據(jù),注意這里最大池化的尺寸和步長不一致,這樣可以增加數(shù)據(jù)的豐富性。再之后,我們使用tf.nn.lrn函數(shù),即LRN對結(jié)果進行處理。(LRN模仿了生物神經(jīng)系統(tǒng)的‘側(cè)抑制’機制,對局部神經(jīng)元的活動創(chuàng)建競爭環(huán)境,是的其中響應比較大的值變得相對更大,并抑制其他反饋較小的神經(jīng)元,增強了模型的泛化能力。)
LRN對relu這種沒有上限邊界的激活函數(shù)會比較有用,因為它會從附近的多個卷積核的響應中挑選比價打的反饋,但不適合sigmoid這種有固定邊界并且能抑制過大值的激活函數(shù)。
weight1=variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,w1=0.0)
kernel1=tf.nn.conv2d(image_holder,weight1,[1,1,1,1],padding='SAME')
bias1=tf.Variable(tf.constent(0.0,shape=[64]))
conv1=tf.nn.relu(tf.nn.bias_add(kernel1,bias1))
pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
norm1=tf.nn.lrn(pool1,4,bias=1.0,alpha=0.001/9.0,beta=0.75)
現(xiàn)在來創(chuàng)建第二個卷積層,這里的步驟和第一步很像,區(qū)別如下:上一層的卷積核數(shù)量為64(即輸出64個通道),所以本卷積和尺寸的第三個維度即輸入的通道數(shù)也需要調(diào)整為64。還有一個需要注意的地方是這里的bias值全部出初始化為0.1,而不是0,最后我們調(diào)換了最大池化層和LRN層的順序,先進性LRN層處理,在使用最大池化層。
weight2=variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,w1=0.0)
kernel2=tf.nn.conv2d(norm1,weight2,[1,1,1,1],padding='SAME')
bias2=tf.Variable(tf.constant(0.1,shape=[64]))
conv2=tf.nn.relu(tf.nn.bias_add(kernel2,bias2))
norm2=tf.nn.lrn(conv2,4,bias=1.0,alpha=0.001/9.0,beta=0.75)
pool2=tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
在兩個卷積層之后,將使用一個全連接層,這里先要把第二個卷積層的輸出結(jié)果flattern,使用tf.reshape函數(shù)將每個樣本都變成一維向量。我們使用get_shape函數(shù),獲取數(shù)據(jù)扁平化之后的長度。接著使用variable_with_weight_loss函數(shù)對全連接層的weight進行初始化,這里隱含節(jié)點數(shù)為384,正太分布的標準差設(shè)為0.04,bias的值也初始化為0.1。需要注意的是我們希望這個全連接層不要過擬合,因此設(shè)了一個非零的weight loss值為0.04,讓這一層的所有參數(shù)都被L2正則所約束。最后我們依然使用relu激活函數(shù)進行非線性化。
reshape=tf.reshape(pool2,[batch_size,-1])
dim=reshape.get_shape()[1].value
weight3=variable_with_weight_loss(shape=[dim,384],stddev=0.04,w1=0.04)
bias3=tf.Variable(tf.constant(0.1,shape=[384]))
local3=tf.nn.relu(tf.matmul(reshape,weight3)+bias3)
接下來這個全連接層和前一層很像,只不過其隱含節(jié)點數(shù)下降了一半,只有192個,其他的超參數(shù)保持不變。
weight4=variable_with_weight_loss(shape=[384,192],stddev=0.004,w1=0.004)
bias4=tf.Variable(tf.constant(0.1,shape=[192]))
local4=tf.nn.relu(tf.matmul(local3,weight4)+bias4)
下面是最后一層,依然先床架這一層的weight,其正太分布標準差設(shè)為上一個隱含層的節(jié)點數(shù)的倒數(shù),并且不計入L2的正則。需要注意的是,這里不像之前那樣使用softmax輸出最后的結(jié)果,這是因為我們把softmax的操作放在了計算loss部分。我們不需要對inference的輸出進行softmax處理就可以獲得最終分類結(jié)果(直接比較inference輸出的各類的數(shù)值大小即可),計算softmax主要是為了計算Loss,因此softmax操作整合到后面是比較合適的。
weight5=variable_with_weight_loss(shape=[192,10],stddev=1/192.0,w1=0.0)
bias5=tf.Variable(tf.constant(0.0,shape=[10]))
logits=tf.add(tf.matmul(local4,weight5),bias5)
卷積神經(jīng)網(wǎng)絡結(jié)構(gòu)表
layer名稱 描述
conv1 卷積層和Relu激活函數(shù)
pool1 最大池化
norm1 LRN
conv2 卷積層和relu激活函數(shù)
norm2 LRN
pool2 最大池化
local3 全連接層和relu激活函數(shù)
local4 全連接層和relu函數(shù)
logits 模型inference的輸出結(jié)果
可以觀察到,其實設(shè)計CNN主要就是安排卷積層、池化層、全連接層的分布和順序,以及其中超參數(shù)的設(shè)置、trick的使用等。設(shè)計性能良好的CNN是有一定規(guī)律可尋的,但是想要針對某個問題設(shè)計最合適的網(wǎng)絡結(jié)構(gòu),是需要大量時間摸索的。
完成了模型inference部分的構(gòu)建,接下來計算cnn的loss。這里依然使用cross entropy,需要注意的是我們把softmax的計算和cross-entropy loss 計算何在一起了,即tf.nn.sparse_softmax_cross_entropy_with_logits。這里使用tf.reduce_mean,對cross entropy 計算均值,再使用tf.add_to_collection把cross entropy 的loss添加到整體losses的collection中。最后,使用tf.add_n將整體的losses的collection中的loss全部求和,得到最終的Loss,其中包括cross entropy loss ,還有兩個全連接層中的weight 的L2 loss.
def loss(logits,labels):
labels=tf.cast(labels,tf.int64)
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,labels=labels,name='cross_entropy_per_example')
cross_entropy_mean=tf.reduce_mean(cross_entropy,name='cross_entropy')
tf.add_to_collection('losses',cross_entropy_mean)
return tf.add_n(tf.get_collection('losses'),name='total_loss')
接著將logits 節(jié)點和label_holder 傳入loss函數(shù)獲得最終的loss。
loss=loss(logits,label_holder)
優(yōu)化器選擇Adan optimizer,學習速率設(shè)為1e-3
train_op=tf.train.AdamOptimizer(1e-3).minimize(loss)
使用tf.nn.in_top_k函數(shù)求輸出結(jié)果中top k 的準確率,默認使用top1,也就是輸出分數(shù)最高的哪一類的準確率。
top_k_op=tf.nn.in_top_k(logits,label_holder,1)
使用tf.InteractiveSession創(chuàng)建默認的session,接著初始化全部模型參數(shù)
sess=tf.InteractiveSession()
tf.global_variables_initializer().run()
這一步是啟動前面提到的圖片數(shù)據(jù)增強的線程隊列,這里一共使用了16個縣城來進行加速。注意,如果這里不啟動縣城,那么后續(xù)的inference及訓練的操作都是無法開始的
tf.train.start_queue_runners()
現(xiàn)在正是開始訓練。在每一個step的訓練過程中,我們需要先使用session的run方法執(zhí)行images_train,labels_train的計算,獲得一個batch的訓練數(shù)據(jù),再將這個batch的數(shù)據(jù)傳入train_op和loss計算。我們記錄每一個step花費的時間,每隔10個step會計算并展示當前的loss、每秒能訓練的樣本數(shù)量,以及訓練一個batch數(shù)據(jù)所花費的時間,這樣就可以比較方便地監(jiān)控整個訓練過程。
for step in range(max_steps):
start_time=time.time()
image_batch,label_batch=sess.run([images_train,labels_train])
_,loss_value=sess.run([train_op,loss],feed_dict={image_holder:image_batch,label_holder:label_batch})
duration=time.time()-start_time
if stap%10==0:
examples_per_sec=batch_size/duration
sec_per_batch=float(duration)
format_str=('step %d,loss=%.2f (%.1f examples/sec;%.3f sec/batch)')
print format_str % (step,loss_value,examples_per_sec,sec_per_batch)
接下來評測模型在測試集上的準確率。需要注意的是,我們依然要像訓練時那樣使用固定的batch_size,然后一個batch一個batch地輸入測試數(shù)據(jù)。我們先計算一共要多少個batch才能將全部樣本評測完。同時,在每一個step中使用session的run方法獲取images_test,labels_test的batch,再執(zhí)行top_k_op計算模型在這個batch的top 1上預測正確地樣本數(shù),最后匯總所有預測正確地結(jié)果,求得全部測試樣本中預測正確的數(shù)量。
num_examples=10000
import math
num_iter=int(math.ceil(num_examples/batch_size))
true_count=0
total_sample_count=num_iter*batch_size
step=0
while step<num_iter:
image_batch,label_batch=sess.run([images_test,labels_test])
predictions=sess.run([top_k_op],feed_dict={image_holder:image_batch,label_holder:label_batch})
true_count+=np.sum(predictions)
step+=1
最后將準確率的評測結(jié)果計算并打印出來
precision=true_count/total_sample_count
print 'precision @1=%.3f' % precision
最終,在cifar-10數(shù)據(jù)集上,通過一個算時間小迭代次數(shù)的訓練,可以達到大致73%準確率。持續(xù)增加max_steps,可以期望準確率逐漸增加。如果max_steps比較大,則推薦使用學習速率衰減(decay)的SGD進行訓練,這樣訓練過程中能達到的準確率峰值會比較高,大致接近86%,而其中L2正則以及LRN層的使用都對模型準確率有所提升。