1. 程式人生 > >tensorflow卷積神經網路例子學習筆記

tensorflow卷積神經網路例子學習筆記

tensorflow卷積神經網路例子

本文是對tensorflow教程中的cifar資料集卷積神經網路例子進行學習後的筆記,主要記錄了一些相關方法的使用。

模型輸入

模型的輸入包括input()、distorted_inputs等一些操作,分別用於讀取CIFAR影象並進行預處理。
檔案處理流程:

  • 統一裁剪到24 * 24畫素大小,裁剪中央區域
  • 近似白化處理,使得模型對動態範圍變化不敏感
distorted_image = tf.random_crop(reshaped_image, [height, width,3])

float_image = tf.image.per_image_standardization(distorted_image)

對於訓練集,可以採取一系列的隨機變換方法來人為增加資料集的大小:

  • 對影象進行左右翻轉
  • 隨機變換影象的亮度
  • 隨機變換突襲那個的對比度
distorted_image = tf.image.random_flip_left_right(distorted_image)

distorted_image = tf.image.random_brightness(distorted_image,                                      max_delta=63)

distorted_image = tf.image.random_contrast(distorted_image,                                        lower=0.2
, upper=1.8)

檔案讀取機制

  在tensorflow中有一種檔案讀取是通過裡那個佇列的完成,一個是記憶體佇列,一個是檔名佇列。使用tf.string_input_producer(num_pochs, shuffle=False)來產生檔名佇列,在tensorflow中記憶體佇列不需要我們自己建立,我們只需要使用reader物件從檔名佇列中讀取資料就可以。需要注意的是,在我們使用tf.string_input_producer(num_pochs, shuffle=False)建立檔名佇列的時候,整個系統還是處於停滯的狀態,也就是說,我們的檔名還未真正加入到佇列中,我們需要使用tf.train.start_queue_runners()之後才真正啟動填充佇列的執行緒。

可以參考以下一段簡單的程式碼:

# --*- coding:utf-8 -*--
import os
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
train_dir = 'your path'

def get_files(file_dir):
    cats = []
    label_cats = []
    dogs = []
    label_dogs = []
    for file in os.listdir(file_dir + '/cat'):
        cats.append(file_dir + 'cat' + '/' + file)
        label_cats.append(0)

    for file in os.listdir(file_dir + '/dog'):
        dogs.append(file_dir + 'dog' + '/' + file)
        label_dogs.append(1)



    #把cat和dog合起來組成一個list(img和lab)
    image_list = np.hstack((cats, dogs))
    label_list = np.hstack((label_cats, label_dogs))

    #利用shuffle打亂順序
    temp = np.array([image_list, label_list])
    temp = temp.transpose()
    np.random.shuffle(temp)

    #從打亂的temp中再取出list(img和lab)
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(i) for i in label_list]

    return image_list, label_list

BATCH_SIZE = 2
CAPACITY = 256
IMG_W = 208
IMG_H = 208

def get_batch(image, label, image_W, image_H, batch_size, capacity):
    image = tf.cast(image, tf.string)
    label = tf.cast(label, tf.int32)

    #產生一個輸入佇列queue,因為img和lab是分開的,所以使用tf.train.slice_input_producer(),然後用tf.read_file()從佇列中讀取影象
    input_queue = tf.train.slice_input_producer([image, label])
    label = input_queue[1]
    image_contents = tf.read_file(input_queue[0])  # read img from a queue
    image = tf.image.decode_jpeg(image_contents, channels=3)
    image = tf.image.resize_image_with_crop_or_pad(image, image_W, image_H)
    #image = tf.image.per_image_standardization(image)
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_contrast(image,
                                               lower=0.2, upper=1.8)
    image_batch, label_batch = tf.train.batch([image, label],
                                              batch_size=batch_size,
                                              num_threads=32,
                                              capacity=capacity)
    # 重新排列label,行數為[batch_size]
    label_batch = tf.reshape(label_batch, [batch_size])
    #image_batch = tf.cast(image_batch, tf.float32)

    return image_batch, label_batch

image_list, label_list = get_files(train_dir)
image_batch, label_batch = get_batch(image_list, label_list,IMG_W, IMG_H, BATCH_SIZE, CAPACITY)

with tf.Session() as sess:
    i = 0
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    try:
        while not coord.should_stop() and i < 20:
            img, label = sess.run([image_batch, label_batch])

            for j in np.arange(BATCH_SIZE):

                print('label: %d' %label[j])
                plt.imshow(img[j,:,:,:])
                plt.show()
                i += 1
    except tf.errors.OutOfRangeError:
        print('Done')

    finally:
        coord.request_stop()
    coord.join(threads)

訓練模型

模型的訓練包括loss()和train()等一些操作,用於計算損失,計算梯度、進行變數更新以及呈現最終的結果。

logits = cifar10.inference(images)

    # Calculate loss.
loss = cifar10.loss(logits=logits, labels=labels)

    # Build a Graph that trains the model with one batch of examples and
    # updates the model parameters.
train_op = cifar10.train(loss, global_step)

    # Create a saver.
saver = tf.train.Saver(tf.all_variables())
  • inference()
    這部分主要是網路的設定,包括兩個卷積層,三個區域性連線層,用於構造分類模型。這部分程式碼全部採用的是tf.get_variable(),和tf.Variable()的主要區別在於tf.get_variable()可用於共享機制,若某變數名已存在,則返回該值,而後者不管是否存在都會返回新的變數。
import tensorflow as tf

with tf.variable_scope("scope1"):
    w1 = tf.get_variable("w1", shape=[])
    w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
    w1_p = tf.get_variable("w1", shape=[])
    w2_p = tf.Variable(1.0, name="w2")

print(w1 is w1_p, w2 is w2_p)
  • loss()
    此處定義的loss是交叉熵損失加上所有w的的L2正則。
tf.add_n(tf.get_collection('losses'), name='total_loss')

在tensorflow中,tensorflow的collection提供一個全域性的儲存機制,不會受到變數名生存空間的影響。一處儲存,到處可取。也就是說,一個名稱下,可以儲存多個值。

  • train()
# Compute gradients.
  with tf.control_dependencies([loss_averages_op]):
    opt = tf.train.GradientDescentOptimizer(lr)
    grads = opt.compute_gradients(total_loss)

  # Apply gradients.
  apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)

  # Add histograms for trainable variables.
  for var in tf.trainable_variables():
    tf.summary.histogram(var.op.name, var)

  # Add histograms for gradients.
  for grad, var in grads:
    if grad is not None:
      tf.summary.histogram(var.op.name + '/gradients', grad)

  # Track the moving averages of all trainable variables.
  variable_averages = tf.train.ExponentialMovingAverage(
      MOVING_AVERAGE_DECAY, global_step)
  variables_averages_op = variable_averages.apply(tf.trainable_variables())

  with tf.control_dependencies([apply_gradient_op, variables_averages_op]):
    train_op = tf.no_op(name='train')

  return train_op

tf.control_dependencies()設計是用來控制計算流圖的,給圖中的某些計算指定順序。tf.no_op()表示什麼也不做。比如模型訓練的時候要執行a,b操作,可使用以下程式碼:

with tf.control_dependencies([a, b]):
    c= tf.no_op(name='train')#tf.no_op;什麼也不做
sess.run(c)

評估

訓練指令碼會為所有學習變數計算其移動均值,評估指令碼則直接將所有學習到的模型引數替換成對應的移動均值。這一替代方式可以在評估過程中提升模型的效能。

# Restore the moving average version of the learned variables for eval.
    variable_averages = tf.train.ExponentialMovingAverage(
        cifar10.MOVING_AVERAGE_DECAY)
    variables_to_restore = variable_averages.variables_to_restore()
    saver = tf.train.Saver(variables_to_restore)

ExponentialMovingAverage 對每一個(待更新訓練學習的)變數(variable)都會維護一個影子變數(shadow variable)。影子變數的初始值就是這個變數的初始值:
shadow_variable=decayshadow_variable+(1decay)variable
decay 控制著模型更新的速度,越大越趨於穩定。實際運用中,decay 一般會設定為十分接近 1 的常數(0.99或0.999)。為了使得模型在訓練的初始階段更新得更快,ExponentialMovingAverage 還提供了 num_updates 引數來動態設定 decay 的大小
decay=min{decay,1+num_updates10+num_updates}

就此,我們就完成了整個卷積神經網路在CIFAR資料集上的分類預測。