1. 程式人生 > >用cifar10訓練一個卷積神經網路

用cifar10訓練一個卷積神經網路

今天按照教程搭建了一個神經網路,這裡總結一下。搭建神經網路的結構如下所示:

我們搭建自己的網路時,一般先確定自己的網路架構,然後計算個層引數,做好這些預備工作之後就可以開始寫程式碼了。

#匯入所需要的包
import cifar10,cifar10_input
import tensorflow as tf
import numpy as np
import time
import math


max_step=3000#迭代3000次
batch_size=128#每次迭代使用128張圖片
#下載cifar10的預設路徑
data_dir='/tmp/cifar10_data/cifar-10-batches-bin'

#定義權重函式
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把weight loss統一存到一個collection,這個collection名為"losses",它會在後面計算神經網路總體loss時被用上
        tf.add_to_collection("losses", weight_loss)

    return var

# 下載cifar10類的資料集,並解壓,展開到其預設位置
cifar10.maybe_download_and_extract()
#按每一批次來讀取資料
images_train,labels_train=cifar10_input.distorted_inputs(
    data_dir=data_dir,
    batch_size=batch_size)
images_test,labels_test=cifar10_input.inputs(eval_data=True,
                                             data_dir=data_dir,
                                             batch_size=batch_size)
# 因為batch_size在之後定義網路結構時被用到了,所以資料尺寸中的第一個值即樣本條數需要被預先設定,而不能像以前那樣設定為None
# 而資料尺寸中的圖片尺寸為24*24即是剪裁後的大小,顏色通道數則設為3
# 這裡寫batch_size而不是None 因為後面程式碼中get_shape會拿到這裡面的batch_size
#訓練集多少行,就有多少個Label
image_holder=tf.placeholder(tf.float32,[batch_size,24,24,3])
labels_holder=tf.placeholder(tf.int32,[batch_size])

#第一個卷積層,64個卷積核,卷積核大小是5*5,3通道
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.constant(0.0,shape=[64]))#初始化引數
conv1=tf.nn.relu(tf.nn.bias_add(kernel1,bias1))#使用啟用函式啟用
# 使用尺寸3*3步長2*2的最大池化層處理資料,這裡最大池化的尺寸和步長不一樣,可以增加資料的豐富性
pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
# 使用LRN對結果進行處理
norm1=tf.nn.lrn(pool1,4,bias=0.1,alpha=0.001/9.0,beta=0.75)


#第二個卷積層
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))#使用啟用函式啟用
# 使用LRN對結果進行處理
norm2=tf.nn.lrn(conv2,4,bias=0.1,alpha=0.001/9.0,beta=0.75)
# 使用尺寸3*3步長2*2的最大池化層處理資料,這裡最大池化的尺寸和步長不一樣,可以增加資料的豐富性
pool2=tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')

#全連線層
#使用tf.reshape函式將每個樣本都變成一維向量,使用get_shape函式獲取資料扁平化之後的長度
reshape=tf.reshape(pool2,[batch_size,-1])
dim=reshape.get_shape()[1].value
# 接著初始化權值,隱含節點384個,正太分佈的標準差設為0.04,bias的值也初始化為0.1
# 注意這裡我們希望這個全連線層不要過擬合,因此設了一個非零的weight loss值0.04,讓這一層具有L2正則所約束。
weight3=variable_with_weight_loss(shape=[dim,384],stddev=0.04,w1=0.004)
bias3=tf.Variable(tf.constant(0.1,shape=[384]))#寫0.1是為了Relu小於0時全為0,所以給0.1不至於成為死亡神經元
# 最後我們依然使用ReLU啟用函式進行非線性化
local3=tf.nn.relu(tf.matmul(reshape,weight3)+bias3)

#第二個全連線層
weight4=variable_with_weight_loss(shape=[384,192],stddev=1/192.0,w1=0.0)
bias4=tf.Variable(tf.constant(0.0,shape=[192]))
local4=tf.nn.relu(tf.matmul(local3,weight4)+bias4)

#最後一層(輸出層)
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)

#定義loss函式
def loss(logits,labels):
    labels=tf.cast(labels,tf.int64)
    #把softmax的計算和cross_entropy的計算合在了一起
    cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(
        logits=logits,labels=labels,name='cross_entropy_per_example')
    #對 cross entropy計算均值
    cross_entropy_mean=tf.reduce_mean(cross_entropy,name='cross_entropy')
    #使用tf.add_n將整體losses的collection集合中的全部loss求和,得到最終的loss
    tf.add_to_collection('losses',cross_entropy_mean)

    return tf.add_n(tf.get_collection('losses'),name='total_loss')


loss=loss(logits,labels_holder)#logits輸出的結果
train_op=tf.train.AdamOptimizer(1e-3).minimize(loss)
# 使用 tf.nn.in_top_k()函式求輸出結果中 top k的準確率,預設使用top 1,也就是輸出分數最高的那一類的準確率
top_k_op=tf.nn.in_top_k(logits,labels_holder,1)

sess=tf.InteractiveSession()
tf.global_variables_initializer().run()
# 啟動圖片資料增強的執行緒佇列,這裡一共使用了16個執行緒來進行加速,如果不啟動執行緒,那麼後續inference以及訓練的操作都是無法開始的
tf.train.start_queue_runners()

#訓練
for step in range(max_step):
    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,labels_holder:label_batch})
    duration=time.time()-start_time

    if step %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))

#評測模型在測試集上的準確率
num_examples=10000

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,labels_holder:label_batch})#有多少個相同的結果預測出的和真實的比較
    
    true_count+=np.sum(predictions)
    step+=1

precision=true_count/total_sample_count#預測對的和總的樣本數
print('precision @ 1=%.3f'%precision)