學習筆記TF029:實現進階卷積網絡


經典數據集CIFAR-10,60000張32x32彩色圖像,訓練集50000張,測試集10000張。標注10類,每類圖片6000張。airplance、automobile、bird、cat、deer、dog、frog、horse、ship、truck。沒有任何重疊。CIFAR-100,100類標注。深度學習之父 Geoffrey Hinton和學生Alex Krizhevsky、Vinod Nair收集。圖片源於80 million tiny images數據集。State-of-the-art 3.5%錯誤率,GPU訓練十幾小時。詳細Benchmark和排名在 http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results.html 。LeCun,現有卷積神經網絡已經解決CIFAR-10數據集問題。

根據Alex cuda-convnet模型修改,3000個batch,每個batch 128個樣本,達到73%正確率。GTX1080單顯卡幾十秒模型訓練時間。CPU慢很多。如用100k batch 結合學習速度decay(每隔一段時間下降學習速率一個比率),正確率可到86%。模型訓練參數100萬個,預測四則運算總量2000萬次。對weights進行L2正則化。圖片翻轉、隨機剪切等數據增強,制造更多樣本。每個卷積-最大池化層后用LRN層,增強模型泛化能力。

下載TensorFlow Models庫,使用其中提供CIFAR-10數據類。git clone https://github.com/tensorflow/models.git。models/tutorials/image/cifar10。

載入常用庫,NumPy、time,TensorFlow Models自動下載、讀取CIFAR-10數據類。

定義batch_size,訓練輪數max_steps,下載CIFAR-10數據默認路徑。

定義初始化weight函數,tf.truncated_normal截斷正態分布初始化權重。Weight加L2 loss ,做L2 正則化。減少特征或懲罰不重要特征權重,緩解特征過多導致過擬合。正則化幫助找到該懲罰的特征權重。為使用某個特征,需付出loss代價。L1正則制造稀疏特征,大部分無用特征權重被置0。L2正則讓特征權重不過大,特征權重較平均。wl控制L2 loss大小,tf.nn.l2_loss函數計算weight L2 loss,tf.multiply L2 loss 乘以wl,得最后 weight loss。tf.add_to_collection weight loss統一存在collection losses,計算神經網絡總體loss使用。

用cifar10類下載數據集,解壓、展開到默認位置。

用cifar10_input類 distorted_inputs函數產生訓練數據,包括特征、label,返回封裝tensor,每次執行生成一個batch_size數量樣本。Data Augmentation(數據增強),cifar10_input.distorted_inputs函數,隨機水平翻轉(tf.image.random_flip_left_right)、隨機剪切一塊24x24圖片(tf.random_crop)、設置隨機亮度對比度(tf.image.random_brightness、tf.image.random_contrast),數據標准化(tf.image.per_image_whitening,數據減均值,除方差,保證數據零均值,方差1)。獲得更多樣本,帶噪聲,一張圖片樣本變多張圖片,擴大樣本量,提高准確率。數據增強操作耗費大量CPU時間,distored_inputs用16個獨立線程加速任務,函數內部產生線程池,通過TensorFlow queue調度。

用cifar10_input.inputs函數生成測試數據,裁剪圖片正中間24x24大小區塊,數據標准化。

創建輸入數據placeholderx,特征、label。設定placeholder數據尺寸,batch_size定義網絡結構要用,數據尺寸第一個值樣本條數需要預先設定,不能設None。數據尺寸的圖片尺寸為24x24,裁剪后大小,顏色通道數3,彩色RGB三通道。

第一個卷積層,variable_with_weight_loss 函數創建卷積核參數初始化。卷積核大小5x5,3個顏色通道,64個卷積核,設置weight初始化函數標准差0.05。wl(weight loss)設0。tf.nn.conv2d函數對輸入數據image_holder卷積操作,步長stride設1,padding模式SAME,bias初始化0,卷積結果加bias,用ReLU激活函數非線化。用尺寸3x3,步長2x2最大池化層處理數據,尺寸、步長不一致,增加數據豐富性。tf.nn.lrn函數,LRN,處理結果。

LRN起於Alex用CNN參加ImageNet比賽論文。LRN模仿生物神經系統側抑制機制,對局部神經元活動創建競爭環境,響應較大值變得相對更大,抑制其他反饋較小神經元,增強模型泛化能力。用LRN后CNN Top1錯誤率降低1.4%。LRN對無上限邊界激活函數ReLU有用,從附近多個卷積核響應(Response)挑選較大反饋,不適合固定邊界能抑制過大值激活函數Sigmoid。

第二個卷積層,卷積核尺寸第三維度輸入通道數64,bias值全初始化0.1。先進行LRN層處理,再用最大池化層。

全連接層,把前面兩個卷積層輸出結果全部flatten,tf.reshape函數把每個樣本變成一維向量。get_shape函數獲取數據扁平化長度。variable_with_weight_loss函數初始化全連接層weight,隱含節點384,正態分布標准差0.04,bias初始化0.1。設非零weight loss值0.04,所有參數被L2正則約束,避免過擬合。ReLU激活函數非線性化。

第二個全連接層,隱含節點192。

最后一層,先創建weight,正態分布標准差設上一隱含層節點數倒數,不計入L2正則。Softmax操作放在計算loss部分,不需要對inference輸出softmax處理,就可以獲得最終分類,直接比較inference輸出各類數值大小。

整個卷積神經網絡從輸入到輸出流程。設計CNN,安排卷積層、池化層、全連接層分布和順序,超參數設置、Trick使用。卷積神經網絡結構:
conv1:卷積層和ReLU激活函數
pool1:最大池化
norm1:LRN
conv2:卷積層和ReLU激活函數
norm2:LRN
pool2:最大池化
local3:全連接層和ReLU激活函數
local4:全連接層和ReLU激活函數
logits:模型Inference輸出結果

計算CNN loss。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。Logits節點、label_placeholder傳入loss小孩子數,獲得最終loss。

優化器選擇Adam Optimizer,學習速率1e-3。

tf.nn.in_top_k函數求輸出結果top k准確率,默認top 1,輸出分類最高類准確率。

tf.InteractiveSession創建默認session ,初始化全部模型參數。

啟動圖片數據增強線程隊列,16個線程加速。

訓練。每個step訓練過程,session run方法執行images_train、 labels_train計算,獲得batch訓練數據,傳入train_op和loss計算。記錄每個step時間,每隔10個step計算展示當前loss、每秒鍾訓練樣本數量、訓練batch數據時間,監控整個訓練過程。GTX 1080,每秒訓練1800個樣本,batch_size 128,每個batch 0.066s。損失loss,開始4.6,3000步訓練下降到1.0。

評測模型測試集准確率。測試集10000個樣本,使用固定batch_size,逐個batch輸入測試數據。計算全部樣本評測完batch數量。每個step用session run方法獲取images_test、labels_test的batch,執行top_k_op計算模型 batch top 1預測正確樣本數。匯總所有預測正確結果,求全部測試樣本預測正確數量。

打印准確率評測結果計算。

73%准確率。持續增加max_steps,期望准確率逐漸增加。max_steps較大,用學習速率衰減(decay)的SGD訓練,接近86%。L2正則,LRN層提升模型准確率,提升框泛化性。

數據增強(Data Augmentation),給單幅圖增加多個副本,提高圖片利用率,防止圖片結構學習過擬合。利用圖片本身性質,圖片冗余信息量較大,制造不同噪聲,依可識別。神經網絡克服噪聲准確識別,泛化性更好。深度學習只要提供足夠多樣本,准確率可以持續提升。 規模越大越復雜神經網絡模型,可以達到准確率水平越高,需要更多數據訓練。Alex cuda-convnet測試結果,CIFAR-10,不數據增強,錯誤最低下降到17%,數據增強,錯誤率下降到11%。

    import cifar10,cifar10_input
    import tensorflow as tf
    import numpy as np
    import time
    max_steps = 3000
    batch_size = 128
    data_dir = '/tmp/cifar10_data/cifar-10-batches-bin'
    def variable_with_weight_loss(shape, stddev, wl):
        var = tf.Variable(tf.truncated_normal(shape, stddev=stddev))
        if wl is not None:
            weight_loss = tf.multiply(tf.nn.l2_loss(var), wl, name='weight_loss')
            tf.add_to_collection('losses', weight_loss)
        return var
    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')
  
    ###
    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)                                                  
    #images_train, labels_train = cifar10.distorted_inputs()
    #images_test, labels_test = cifar10.inputs(eval_data=True)
    image_holder = tf.placeholder(tf.float32, [batch_size, 24, 24, 3])
    label_holder = tf.placeholder(tf.int32, [batch_size])
    #logits = inference(image_holder)
    weight1 = variable_with_weight_loss(shape=[5, 5, 3, 64], stddev=5e-2, wl=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))
    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)
    weight2 = variable_with_weight_loss(shape=[5, 5, 64, 64], stddev=5e-2, wl=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')
    reshape = tf.reshape(pool2, [batch_size, -1])
    dim = reshape.get_shape()[1].value
    weight3 = variable_with_weight_loss(shape=[dim, 384], stddev=0.04, wl=0.004)
    bias3 = tf.Variable(tf.constant(0.1, shape=[384]))
    local3 = tf.nn.relu(tf.matmul(reshape, weight3) + bias3)
    weight4 = variable_with_weight_loss(shape=[384, 192], stddev=0.04, wl=0.004)
    bias4 = tf.Variable(tf.constant(0.1, shape=[192]))                                      
    local4 = tf.nn.relu(tf.matmul(local3, weight4) + bias4)
    weight5 = variable_with_weight_loss(shape=[192, 10], stddev=1/192.0, wl=0.0)
    bias5 = tf.Variable(tf.constant(0.0, shape=[10]))
    logits = tf.add(tf.matmul(local4, weight5), bias5)
    loss = loss(logits, label_holder)
    train_op = tf.train.AdamOptimizer(1e-3).minimize(loss) #0.72
    top_k_op = tf.nn.in_top_k(logits, label_holder, 1)
    sess = tf.InteractiveSession()
    tf.global_variables_initializer().run()
    tf.train.start_queue_runners()
    ###
    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 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
    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
    precision = true_count / total_sample_count
    print('precision @ 1 = %.3f' % precision)

 

參考資料:
《TensorFlow實戰》

歡迎付費咨詢(150元每小時),我的微信:qingxingfengzi


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM