1. 程式人生 > >計算機視覺基礎——TensorFlow實經典LeNet網路

計算機視覺基礎——TensorFlow實經典LeNet網路

1537250305768859.png

一、LeNet網路簡介

1.1 LeNet網路的背景

閃光點:定義了CNN的基本元件,是CNN的鼻祖。

LeNet是卷積神經網路的祖師爺LeCun在1998年提出,用於解決手寫數字識別的視覺任務。自那時起,CNN的最基本的架構就定下來了:卷積層、池化層、全連線層。如今各大深度學習框架中所使用的LeNet都是簡化改進過的LeNet-5(-5表示具有5個層),和原始的LeNet有些許不同,比如把啟用函式改為了現在很常用的ReLu。

但是具體沒一個網路層的引數設定會稍有不同。比如卷積層卷積核的大小,輸出特徵圖的數量這些都可以自定義的。

 

1.2 LeNet的網路結構

LeNet一共包含5個網路層,如果算上池化層,就是8個網路層。

輸入層:輸入層的影象大小為28x28x1

卷積層1:卷積核大小為3x3x1x32,相當於是32個3x3x1的卷積核,移動步幅長為1,故而得到的輸出為32個特徵圖,也可以說成一幅影象有32個通道,28x28x32.

池化層1:採用最大化池化層,為2x2,移動步幅為2,故而輸出為:14x14x32

卷積層2:卷積核大小為3x3x32x64,相當於是64個3x3x32的卷積核,移動步幅長為1,故而得到的輸出為64個特徵圖,也可以說成一幅影象有64個通道,14x14x64.

池化層2:採用最大化池化層,為2x2,移動步幅為2,故而輸出為:7x7x64

卷積層3:卷積核大小為3x3x64x128,相當於是128個3x3x64的卷積核,移動步幅長為1,故而得到的輸出為128個特徵圖,也可以說成一幅影象有128個通道,7x7x128.

池化層3:採用最大化池化層,為2x2,移動步幅為2,故而輸出為:4x4x128

全連線層:輸入為128x4x4,需要將其展開成一維的,輸出為625.

輸出層:輸入為625,輸出為10.

 

1.3 LeNet的結構圖

二、tensorflow實現LeNet

 

2.1 實現程式碼及註釋

  1import numpy as np
  2import tensorflow as tf
  3from tensorflow.examples.tutorials.mnist import input_data #匯入資料的模組
  4
  5batch_size=100  #表示每一批訓練100組資料,因為訓練集共有資料55000組,故而訓練一個週期需要經過550次迭代
  6test_size=256   #作為驗證資料,驗證集有10000組資料,但這裡只驗證256組,因為資料太多,運算太慢
  7img_size=28     #手寫字影象的大小
  8num_class=10    #影象的類別
  9
 10X=tf.placeholder(dtype=tf.float32,shape=[None,img_size,img_size,1],name='input')
 11Y=tf.placeholder(dtype=tf.float32,shape=[None,num_class])
 12
 13p_keep=tf.placeholder(tf.float32,name='p_keep_rate') #後面用到dropout層的保留的引數
 14
 15mnist=input_data.read_data_sets('mnist_data',one_hot=True) #匯入資料集
 16train_X,train_Y,test_X,test_Y=mnist.train.images,mnist.train.labels,mnist.test.images,mnist.test.labels
 17
 18train_X=train_X.reshape(-1,img_size,img_size,1)   #訓練資料和測試資料都需要重塑一下形狀,因為匯入的是724長度的
 19test_X=test_X.reshape(-1,img_size,img_size,1)
 20
 21#第一個卷積層
 22with tf.name_scope('cnn_layer_01') as cnn_01:     
 23    w1=tf.Variable(tf.random_normal(shape=[3,3,1,32],stddev=0.01))
 24    conv1=tf.nn.conv2d(X,w1,strides=[1,1,1,1],padding="SAME")
 25    conv_y1=tf.nn.relu(conv1)
 26
 27#第一個池化層
 28with tf.name_scope('pool_layer_01') as pool_01:
 29    pool_y2=tf.nn.max_pool(conv_y1,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
 30    pool_y2=tf.nn.dropout(pool_y2,p_keep)
 31
 32#第二個卷積層
 33with tf.name_scope('cnn_layer_02') as cnn_02:
 34    w2=tf.Variable(tf.random_normal(shape=[3,3,32,64],stddev=0.01))
 35    conv2=tf.nn.conv2d(pool_y2,w2,strides=[1,1,1,1],padding="SAME")
 36    conv_y3=tf.nn.relu(conv2)
 37
 38#第二個池化層
 39with tf.name_scope('pool_layer_02') as pool_02:
 40    pool_y4=tf.nn.max_pool(conv_y3,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
 41    pool_y4=tf.nn.dropout(pool_y4,p_keep)
 42
 43#第三個卷積層
 44with tf.name_scope('cnn_layer_03') as cnn_03:
 45    w3=tf.Variable(tf.random_normal(shape=[3,3,64,128],stddev=0.01))
 46    conv3=tf.nn.conv2d(pool_y4,w3,strides=[1,1,1,1],padding="SAME")
 47    conv_y5=tf.nn.relu(conv3)
 48
 49#第三個池化層
 50with tf.name_scope('pool_layer_03') as pool_03:
 51    pool_y6=tf.nn.max_pool(conv_y5,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
 52
 53#全連線層 
 54with tf.name_scope('full_layer_01') as full_01:
 55    w4=tf.Variable(tf.random_normal(shape=[128*4*4,625],stddev=0.01))
 56    FC_layer=tf.reshape(pool_y6,[-1,w4.get_shape().as_list()[0]])
 57    FC_layer=tf.nn.dropout(FC_layer,p_keep)
 58    FC_y7=tf.matmul(FC_layer,w4)
 59    FC_y7=tf.nn.relu(FC_y7)
 60    FC_y7=tf.nn.dropout(FC_y7,p_keep)
 61
 62#輸出層,model_Y則為神經網路的預測輸出
 63with tf.name_scope('output_layer') as output_layer:
 64    w5=tf.Variable(tf.random_normal(shape=[625,num_class]))
 65    model_Y=tf.matmul(FC_y7,w5,name='output')
 66
 67#損失函式
 68Y_=tf.nn.softmax_cross_entropy_with_logits(logits=model_Y,labels=Y)
 69cost=tf.reduce_mean(Y_)
 70
 71#準確率
 72correct_prediction=tf.equal(tf.argmax(model_Y,axis=1),tf.argmax(Y,axis=1))
 73accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
 74
 75#優化方式
 76optimizer=tf.train.RMSPropOptimizer(0.001,0.9).minimize(cost)
 77
 78#將相關的引數寫入tensorboard
 79#-----------------------------------------------------------------------
 80tf.summary.scalar('loss',cost)
 81tf.summary.scalar('accuracy',accuracy)
 82tf.summary.histogram('w1',w1)
 83tf.summary.histogram('w2',w2)
 84tf.summary.histogram('w3',w3)
 85tf.summary.histogram('w4',w4)
 86tf.summary.histogram('w5',w5)
 87merge=tf.summary.merge_all()
 88#--------------------------------------------------------------------------
 89#構建會話任務
 90with tf.Session() as sess:
 91    tf.global_variables_initializer().run()
 92    writer=tf.summary.FileWriter('mnist_cnn_summary_01',graph=sess.graph)
 93    #將索引重組一下,得到【(0,100),(100,200),(200,300)。。。。】的形式
 94    training_batch=zip(range(0,len(train_X),batch_size),range(batch_size,len(train_X)+1,batch_size))
 95
 96    run_metadata=tf.RunMetadata()
 97    #開始訓練,此處只訓練一個epoch,若想訓練多個epoch,可以再新增一個迴圈
 98    for start,end in training_batch:
 99        opti,summary,loss,acc=sess.run([optimizer,merge,cost,accuracy],\
100        feed_dict={X:train_X[start:end],Y:train_Y[start:end],p_keep:0.8},\
101        run_metadata=run_metadata) #這是最關鍵的一步,optimizer,summary,loss,accuracy均放在一起進行訓練
102
103        writer.add_run_metadata(run_metadata,tag='step{0}'.format(start),global_step=(start/batch_size)+1)
104        writer.add_summary(summary,global_step=(start/batch_size)+1)
105
106        print(f'第 {(start/batch_size)+1} 次迭代時,準確度為 {acc},誤差為 {loss}',end='\r',flush=True)
107
108    print('===================下面開始進行測試==============================')
109    #下面開始對測試集上的資料進行驗證
110    test_index=np.arange(len(test_X))
111    np.random.shuffle(test_index)      #將測試集上的10000組資料順序隨即大亂
112    test_index=test_index[0:test_size] #只選擇打亂順序之後的256組樣本資料進行測試
113    test_acc=sess.run(accuracy,feed_dict={X:test_X[test_index],Y:test_Y[test_index],p_keep:1})
114    print(f'測試集上面的準確率為 :{test_acc}')
115    print('===================下面是儲存模型================================')
116     #儲存模型
117    saver=tf.train.Saver()
118    path=saver.save(sess,'mnist_cnn_model/medel.ckpt')
119    print(f'模型歐儲存到 {path}')
120    print('訓練完畢!')

 

TensorFlow實現LeNet

2.2 程式執行結果分析

2.2.1 結果列印

1===================下面開始進行測試==============================857185366
2測試集上面的準確率為 :0.9765625
3===================下面是儲存模型================================
4模型歐儲存到 mnist_cnn_model/medel.ckpt
5訓練完畢!

 

從上面可以看出,在256組測試資料及上面的準確率為0.9765625.只進行了一個epoch的訓練能達到這樣的效果已經很不錯了。

2.2.1 誤差曲線及準確率

 

 

2.2.2 模型graph

graph1.png

 

三、模型的載入以及預測

3.1 預測結果

 

一個魔性訓練完成之後,需要將模型儲存,這樣就可以避免每次使用模型的時候都重新訓練,本文只講實現,具體關於模型如何儲存,如何載入以及相關儲存檔案的具體含義後面會繼續講到。

 

 1import random
 2import matplotlib.pyplot as plt
 3import tensorflow as tf
 4from tensorflow.examples.tutorials.mnist import input_data #匯入資料的模組
 5
 6mnist=input_data.read_data_sets('mnist_data',one_hot=True)
 7train_X,train_Y,test_X,test_Y=mnist.train.images,mnist.train.labels,mnist.test.images,mnist.test.labels
 8
 9
10test_image=mnist.test.images[101]  #選取第101張圖片
11img_size=28
12test_image=test_image.reshape(-1,img_size,img_size,1)
13
14with tf.Session() as sess:   #    
15    new_saver=tf.train.import_meta_graph('mnist_cnn_model/medel.ckpt.meta') #第二步:匯入模型的圖結構
16    new_saver.restore(sess,'mnist_cnn_model/medel.ckpt')  #第三步:將這個會話繫結到匯入的圖中
17    #new_saver.restore(sess,tf.train.latest_checkpoint('mymodel'))    #第三步也可以是這樣操作,因為會從mymodel資料夾中獲取checkpoint,而checkpoint中儲存了最新存檔的檔案路徑
18
19    print('=======================模型載入完成=============================')
20    X=sess.graph.get_tensor_by_name('input:0')                 #從模型中獲取輸入的那個節點
21    p_keep=sess.graph.get_tensor_by_name('p_keep_rate:0')
22    model_y=sess.graph.get_tensor_by_name('output_layer/output:0')
23    print('=======================輸入輸出載入完成=============================')
24    result=sess.run(model_y,feed_dict={X:test_image,p_keep:1})  #需要的就是模型預測值model_Y,這裡存為result
25    print('++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')
26    print(result)
27    print('++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++')
28    soft_result=tf.nn.softmax(result)
29    result1=sess.run(soft_result)
30    print(result1)
31    
34    plt.imshow(test_image.reshape([28,28]),cmap='Greys')
35    plt.show()

 

模型的載入預測

3.2 預測結果分析

 

本次只選擇了一張測試圖片,選擇的是第101張照片,程式的執行顯示為如下:

原始測試圖片如下:

Figure_1.png

 

執行結果為:

1=======================模型載入完成=============================
2=======================輸入輸出載入完成=============================
3++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4[[15.647467  -6.0671535 -0.9249869 -5.6294613 -3.727207   0.5262224
5   2.540439  -1.8248326 -1.2350063  3.0618703]]
6++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7[[9.9999416e-01 3.7107148e-10 6.3485118e-08 5.7483751e-10 3.8519756e-09
8  2.7097201e-07 2.0308953e-06 2.5815121e-08 4.6562104e-08 3.4209170e-06]]

 

從上面的執行結果可以看出,第一個數字為0.99999416,後面的其他數子基本上非常接近於0,說明該數字是0的概率為99.9999%。

全文總結

本文基於TensorFlow實現了經典的LeNet網路,準確率較高,如果您看過之後覺得有什麼問題和需要改進的地方,歡迎您留言。另外,後面我會陸續實現相關的經典網路,包括VGGNet,GoogleNet,ResNet,DenseNet等,如果想在深度學習方面一起學習的可以持續關注一下。

 

 

草樣年華.jpg

 

 

個人微訊號.jpg