一.百度網盤Cifar獲取地址:
鏈接:https://pan.baidu.com/s/132yQGedau02Bw47fz75bYQ
提取碼:bnvd
二.Tensorflow代碼實現:
該程序部分分為兩個文件,分別是:Cifar10_data.py和CNN_Cifar-10.py文件。其中Cifar10_data.py文件的作用是采用文件隊列的方式讀取目標文件並對讀取完畢的圖像文件進行圖像增強預處理,CNN_Cifar-10.py文件的作用是構造循環神經網絡的整體結構,並進行訓練和測試(評估)過程。
下面的代碼是Cifar10_data.py程序文件:
1 #該文件負責讀取Cifar-10數據並對其進行數據增強預處理 2 import os 3 import tensorflow as tf 4 num_classes=10 5 6 #設定用於訓練和評估的樣本總數 7 num_examples_pre_epoch_for_train=50000 8 num_examples_pre_epoch_for_eval=10000 9 10 #定義一個空類,用於返回讀取的Cifar-10的數據 11 class CIFAR10Record(object): 12 pass 13 14 15 #定義一個讀取Cifar-10的函數read_cifar10(),這個函數的目的就是讀取目標文件里面的內容 16 def read_cifar10(file_queue): 17 result=CIFAR10Record() 18 19 label_bytes=1 #如果是Cifar-100數據集,則此處為2 20 result.height=32 21 result.width=32 22 result.depth=3 #因為是RGB三通道,所以深度是3 23 24 image_bytes=result.height * result.width * result.depth #圖片樣本總元素數量 25 record_bytes=label_bytes + image_bytes #因為每一個樣本包含圖片和標簽,所以最終的元素數量還需要圖片樣本數量加上一個標簽值 26 27 reader=tf.FixedLengthRecordReader(record_bytes=record_bytes) #使用tf.FixedLengthRecordReader()創建一個文件讀取類。該類的目的就是讀取文件 28 result.key,value=reader.read(file_queue) #使用該類的read()函數從文件隊列里面讀取文件 29 30 record_bytes=tf.decode_raw(value,tf.uint8) #讀取到文件以后,將讀取到的文件內容從字符串形式解析為圖相對應的像素數組 31 32 result.label=tf.cast(tf.strided_slice(record_bytes,[0],[label_bytes]),tf.int32) #因為該數組第一個元素是標簽,所以我們使用strided_slice()函數將標簽提取出來,並且使用tf.cast()函數將這一個標簽轉換成int32的數值形式 33 34 depth_major=tf.reshape(tf.strided_slice(record_bytes,[label_bytes],[label_bytes + image_bytes]), 35 [result.depth,result.height,result.width]) #剩下的元素再分割出來,這些就是圖片數據,因為這些數據在數據及立面存儲的形式是depth * height * width,我們要把這種格式轉換成[depth,height,width] 36 37 38 result.uint8image=tf.transpose(depth_major,[1,2,0]) #我們要將之前分割好的圖片數據使用tf.transpose()函數轉換成為高度信息、寬度信息、深度信息這樣的順序 39 40 return result #返回值是已經把目標文件里面的信息都讀取出來 41 42 def inputs(data_dir,batch_size,distorted): #這個文件是讀取數據並對數據進行預處理,這個函數就是對數據進行預處理---對圖像數據是否進行增強進行判斷,並作出相應的操作 43 filenames=[os.path.join(data_dir,"data_batch_%d.bin"%i)for i in range(1,6)] #拼接地址 44 45 file_queue=tf.train.string_input_producer(filenames) #根據已經有的文件地址創建一個文件隊列 46 read_input=read_cifar10(file_queue) #根據已經有的文件隊列使用已經定義好的文件讀取函數read_cifar10()讀取隊列中的文件 47 48 reshaped_image=tf.cast(read_input.uint8image,tf.float32) #將已經轉換好的圖片數據再次轉換為float32的形式 49 50 num_examples_per_epoch=num_examples_pre_epoch_for_train 51 52 53 if distorted != None: #如果預處理函數中的distorted參數不為空值,就代表要進行圖片增強處理 54 cropped_image=tf.random_crop(reshaped_image,[24,24,3]) #首先將預處理好的圖片進行剪切,使用tf.random_crop()函數 55 56 flipped_image=tf.image.random_flip_left_right(cropped_image) #將剪切好的圖片進行左右翻轉,使用tf.image.random_flip_left_right()函數 57 58 adjusted_brightness=tf.image.random_brightness(flipped_image,max_delta=0.8) #將左右翻轉好的圖片進行隨機亮度調整,使用tf.image.random_brightness()函數 59 60 adjusted_contrast=tf.image.random_contrast(adjusted_brightness,lower=0.2,upper=1.8) #將亮度調整好的圖片進行隨機對比度調整,使用tf.image.random_contrast()函數 61 62 float_image=tf.image.per_image_standardization(adjusted_contrast) #進行標准化圖片操作,tf.image.per_image_standardization()函數是對每一個像素減去平均值並除以像素方差 63 64 float_image.set_shape([24,24,3]) #設置圖片數據及標簽的形狀 65 read_input.label.set_shape([1]) 66 67 min_queue_examples=int(num_examples_pre_epoch_for_eval * 0.4) 68 print("Filling queue with %d CIFAR images before starting to train. This will take a few minutes." 69 %min_queue_examples) 70 71 images_train,labels_train=tf.train.shuffle_batch([float_image,read_input.label],batch_size=batch_size, 72 num_threads=16, 73 capacity=min_queue_examples + 3 * batch_size, 74 min_after_dequeue=min_queue_examples, 75 ) 76 #使用tf.train.shuffle_batch()函數隨機產生一個batch的image和label 77 78 return images_train,tf.reshape(labels_train,[batch_size]) 79 80 else: #不對圖像數據進行數據增強處理 81 resized_image=tf.image.resize_image_with_crop_or_pad(reshaped_image,24,24) #在這種情況下,使用函數tf.image.resize_image_with_crop_or_pad()對圖片數據進行剪切 82 83 float_image=tf.image.per_image_standardization(resized_image) #剪切完成以后,直接進行圖片標准化操作 84 85 float_image.set_shape([24,24,3]) 86 read_input.label.set_shape([1]) 87 88 min_queue_examples=int(num_examples_per_epoch * 0.4) 89 90 images_test,labels_test=tf.train.batch([float_image,read_input.label], 91 batch_size=batch_size,num_threads=16, 92 capacity=min_queue_examples + 3 * batch_size) 93 #這里使用batch()函數代替tf.train.shuffle_batch()函數 94 return images_test,tf.reshape(labels_test,[batch_size])
下面的代碼是CNN_Cifar-10.py程序文件:
1 #該文件的目的是構造循環神經網絡的整體結構,並進行訓練和測試(評估)過程 2 import tensorflow as tf 3 import numpy as np 4 import time 5 import math 6 import Cifar10_data 7 8 max_steps=4000 9 batch_size=100 10 num_examples_for_eval=10000 11 data_dir="C:/Users/muzi/Desktop/Cifar_data/cifar-10-batches-bin" 12 13 #創建一個variable_with_weight_loss()函數,該函數的作用是: 14 # 1.使用參數w1控制L2 loss的大小 15 # 2.使用函數tf.nn.l2_loss()計算權重L2 loss 16 # 3.使用函數tf.multiply()計算權重L2 loss與w1的乘積,並賦值給weights_loss 17 # 4.使用函數tf.add_to_collection()將最終的結果放在名為losses的集合里面,方便后面計算神經網絡的總體loss, 18 def variable_with_weight_loss(shape,stddev,w1): 19 var=tf.Variable(tf.truncated_normal(shape,stddev=stddev)) 20 if w1 is not None: 21 weights_loss=tf.multiply(tf.nn.l2_loss(var),w1,name="weights_loss") 22 tf.add_to_collection("losses",weights_loss) 23 return var 24 25 #使用上一個文件里面已經定義好的文件序列讀取函數讀取訓練數據文件和測試數據從文件,其中訓練數據文件進行數據增強處理,測試數據文件不進行數據增強處理 26 images_train,labels_train=Cifar10_data.inputs(data_dir=data_dir,batch_size=batch_size,distorted=True) 27 images_test,labels_test=Cifar10_data.inputs(data_dir=data_dir,batch_size=batch_size,distorted=None) 28 29 #創建x和y_兩個placeholder,用於在訓練或評估時提供輸入的數據和對應的標簽值。要注意的是,由於以后定義全連接網絡的時候用到了batch_size,所以x中,第一個參數不應該是None,而應該是batch_size 30 x=tf.placeholder(tf.float32,[batch_size,24,24,3]) 31 y_=tf.placeholder(tf.int32,[batch_size]) 32 33 #創建第一個卷積層 34 kernel1=variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,w1=0.0) 35 conv1=tf.nn.conv2d(x,kernel1,[1,1,1,1],padding="SAME") 36 bias1=tf.Variable(tf.constant(0.0,shape=[64])) 37 relu1=tf.nn.relu(tf.nn.bias_add(conv1,bias1)) 38 pool1=tf.nn.max_pool(relu1,ksize=[1,3,3,1],strides=[1,2,2,1],padding="SAME") 39 40 #創建第二個卷積層 41 kernel2=variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,w1=0.0) 42 conv2=tf.nn.conv2d(pool1,kernel2,[1,1,1,1],padding="SAME") 43 bias2=tf.Variable(tf.constant(0.1,shape=[64])) 44 relu2=tf.nn.relu(tf.nn.bias_add(conv2,bias2)) 45 pool2=tf.nn.max_pool(relu2,ksize=[1,3,3,1],strides=[1,2,2,1],padding="SAME") 46 47 #因為要進行全連接層的操作,所以這里使用tf.reshape()函數將pool2輸出變成一維向量,並使用get_shape()函數獲取扁平化之后的長度 48 reshape=tf.reshape(pool2,[batch_size,-1]) #這里面的-1代表將pool2的三維結構拉直為一維結構 49 dim=reshape.get_shape()[1].value #get_shape()[1].value表示獲取reshape之后的第二個維度的值 50 51 #建立第一個全連接層 52 weight1=variable_with_weight_loss(shape=[dim,384],stddev=0.04,w1=0.004) 53 fc_bias1=tf.Variable(tf.constant(0.1,shape=[384])) 54 fc_1=tf.nn.relu(tf.matmul(reshape,weight1)+fc_bias1) 55 56 #建立第二個全連接層 57 weight2=variable_with_weight_loss(shape=[384,192],stddev=0.04,w1=0.004) 58 fc_bias2=tf.Variable(tf.constant(0.1,shape=[192])) 59 local4=tf.nn.relu(tf.matmul(fc_1,weight2)+fc_bias2) 60 61 #建立第三個全連接層 62 weight3=variable_with_weight_loss(shape=[192,10],stddev=1 / 192.0,w1=0.0) 63 fc_bias3=tf.Variable(tf.constant(0.1,shape=[10])) 64 result=tf.add(tf.matmul(local4,weight3),fc_bias3) 65 66 #計算損失,包括全中參數的正則化損失和交叉熵損失 67 cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=result,labels=tf.cast(y_,tf.int64)) 68 69 weights_with_l2_loss=tf.add_n(tf.get_collection("losses")) 70 loss=tf.reduce_mean(cross_entropy)+weights_with_l2_loss 71 72 train_op=tf.train.AdamOptimizer(1e-3).minimize(loss) 73 74 #函數tf.nn.in_top_k()用來計算輸出結果中top k的准確率,函數默認的k值是1,即top 1的准確率,也就是輸出分類准確率最高時的數值 75 top_k_op=tf.nn.in_top_k(result,y_,1) 76 77 init_op=tf.global_variables_initializer() 78 with tf.Session() as sess: 79 sess.run(init_op) 80 tf.train.start_queue_runners() #啟動線程操作,這是因為之前數據增強的時候使用train.shuffle_batch()函數的時候通過參數num_threads()配置了16個線程用於組織batch的操作 81 82 #每隔100step會計算並展示當前的loss、每秒鍾能訓練的樣本數量、以及訓練一個batch數據所花費的時間 83 for step in range (max_steps): 84 start_time=time.time() 85 image_batch,label_batch=sess.run([images_train,labels_train]) 86 _,loss_value=sess.run([train_op,loss],feed_dict={x:image_batch,y_:label_batch}) 87 duration=time.time() - start_time 88 89 if step % 100 == 0: 90 examples_per_sec=batch_size / duration 91 sec_per_batch=float(duration) 92 print("step %d,loss=%.2f(%.1f examples/sec;%.3f sec/batch)"%(step,loss_value,examples_per_sec,sec_per_batch)) 93 94 #計算最終的正確率 95 num_batch=int(math.ceil(num_examples_for_eval/batch_size)) #math.ceil()函數用於求整 96 true_count=0 97 total_sample_count=num_batch * batch_size 98 99 #在一個for循環里面統計所有預測正確的樣例個數 100 for j in range(num_batch): 101 image_batch,label_batch=sess.run([images_test,labels_test]) 102 predictions=sess.run([top_k_op],feed_dict={x:image_batch,y_:label_batch}) 103 true_count += np.sum(predictions) 104 105 #打印正確率信息 106 print("accuracy = %.3f%%"%((true_count/total_sample_count) * 100))
最終執行完成以后,執行的結果如下(使用CPU進行訓練):
可以看到,最后的正確率在72.190%