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)。影子變數的初始值就是這個變數的初始值:
decay 控制著模型更新的速度,越大越趨於穩定。實際運用中,decay 一般會設定為十分接近 1 的常數(0.99或0.999)。為了使得模型在訓練的初始階段更新得更快,ExponentialMovingAverage 還提供了 num_updates 引數來動態設定 decay 的大小
就此,我們就完成了整個卷積神經網路在CIFAR資料集上的分類預測。