Tensorflow框架(四)
阿新 • • 發佈:2018-12-13
《TensorFlow 實戰Google深度學習框架》文中對這一章的描述個人感覺過於簡單,尤其是針對一些經典的卷積網路。所以本章重點介紹如何搭建這些經典的網路結構,對於模型的細節部分,本章不允以過多介紹,有興趣的可以查閱其他資料文獻
一、卷積層
卷積層就是對過濾器的定義
- 前兩個維度分別表示了過濾器的尺寸(也就是長了寬)
- 第三個維度表示了當前層的深度(其實過濾器的深度等於當前層的深度)
- 第四個維度表示了過濾器的個數(書上說是過濾器深度,不過個人覺得過濾器個數更直觀)
注意過濾器與過濾器之間引數不共享,過濾器在當前圖層滑動時權重共享
# 定義過濾器權重與偏置 filter_weight = tf.get_variable( 'weights', [5, 5, 3, 16], initializer = tf.truncated_normal_initializer(stddev = 0.1)) biases = tf.get_variable('biases', [16], initializer = tf.constant_initializer(0.1)) # 定義過濾器 # input是四個維度張量,以平面圖為例,第一個維度可以表示第幾張圖片,後三個維度代表該圖 # strides = [1,1,1,1]的第一個維度和第四個維度一定是1,步長只對矩陣的長和寬有效 # SAME表示邊緣填充空白,經過卷積變換後圖像與未變換前尺寸一樣,如果是VALID表示不新增 conv = tf.nn.conv2d(input, filter_weight, strides = [1, 1, 1, 1], padding = 'SAME') # 為每一個過濾器卷積得到的圖層加上偏執 bias = tf.nn.bias_add(conv, biases) # Relu函式啟用 actived_conv = tf.nn.relu(bias)
二、池化層
常用的有最大池化層和平均池化層
# 最大池化層 # ksize維度裡第一個和第四個必須為1,第二個和第三個維度表示過濾器尺寸 pool = tf.nn.max_pool(actived_conv, ksize = [1,3,3,1], strides = [1,2,2,1], padding = 'SAME') # 平均池化層 pool = tf.nn.avg_pool(actived_conv, ksize = [1,3,3,1], strides = [1,2,2,1], padding = 'SAME')
三、LeNet-5網路
下圖給的是論文中的LeNet-5網路模型,在下述程式碼中我們並不重建這個模型,而是用一種類似的網路結構。需要指出的是,書中的程式碼個人感覺有點生澀難懂,而且由於使用的是梯度下降法,會導致模型收斂速度很慢。因此修改使用Adam優化演算法。
下述中的程式碼不儲存模型引數,實施列印預測測試集的效果。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# 載入資料集
mnist = input_data.read_data_sets("C:/Users/14981/Desktop/Deep Learning/", one_hot = True)
# 載入引數
times = 20
batch_size = 128
regularization = 0.0001
moving_average_decay = 0.99
learning_rate_base = 0.8
learning_rate_decay = 0.99
batch_num = mnist.train.num_examples // batch_size
# 通用函式
def weight_variable(name, shape):
initial = tf.get_variable(name, shape,
initializer = tf.truncated_normal_initializer(stddev=0.1))
return initial
def bias_variable(name, shape):
initial = tf.get_variable(name, shape,
initializer = tf.constant_initializer(0.1))
return initial
def inference(input_tensor, regularizer, keep_prob):
images = tf.reshape(input_tensor, [-1,28,28,1])
with tf.variable_scope('layer1-conv1'):
conv1_weights = weight_variable('weight', [5,5,1,32])
conv1_biases = bias_variable('bias', [32])
conv1 = tf.nn.conv2d(images, conv1_weights, strides = [1,1,1,1], padding = 'SAME')
relu1 = tf.nn.relu(conv1 + conv1_biases)
with tf.name_scope('layer2-pool1'):
pool1 = tf.nn.max_pool(relu1, ksize = [1,2,2,1], strides = [1,2,2,1], padding = 'SAME')
with tf.variable_scope('layer3-conv2'):
conv2_weights = weight_variable('weight', [5,5,32,64])
conv2_biases = bias_variable('bias', [64])
conv2 = tf.nn.conv2d(pool1, conv2_weights, strides = [1,1,1,1], padding = 'SAME')
relu2 = tf.nn.relu(conv2 + conv2_biases)
with tf.name_scope('layer4-pool2'):
pool1 = tf.nn.max_pool(relu2, ksize = [1,2,2,1], strides = [1,2,2,1], padding = 'SAME')
# 注意此時圖片的維度被壓縮成了7*7*64
pool_shape = tf.reshape(pool1, (-1,7*7*64))
with tf.variable_scope('layer5-fc1'):
fc1_weights = weight_variable('weight', [7*7*64,512])
if regularizer != None:
tf.add_to_collection('losses', regularizer(fc1_weights))
fc1_biases = bias_variable('bias', [512])
fc1 = tf.nn.relu(tf.matmul(pool_shape, fc1_weights) + fc1_biases)
# dropout優化演算法
fc1 = tf.nn.dropout(fc1, keep_prob)
with tf.variable_scope('layer6-fc2'):
fc2_weights = weight_variable('weight', [512, 10])
if regularizer != None:
tf.add_to_collection('losses', regularizer(fc2_weights))
fc2_biases = bias_variable('bias',[10])
logit = tf.nn.softmax(tf.matmul(fc1, fc2_weights) + fc2_biases)
return logit
def train(mnist):
x = tf.placeholder(tf.float32, [None,784], name = 'x-input')
y = tf.placeholder(tf.float32, [None,10], name = 'y-input')
keep_prob = tf.placeholder(tf.float32)
regularizer = tf.contrib.layers.l2_regularizer(regularization)
logit = inference(x, regularizer, keep_prob)
# 定義滑動平均模型
global_step = tf.Variable(0, trainable = False)
variable_averages = tf.train.ExponentialMovingAverage(moving_average_decay)
variable_averages_op = variable_averages.apply(tf.trainable_variables())
# 定義損失函式
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
logits = logit, labels = tf.argmax(y, 1))
cross_entropy_mean = tf.reduce_mean(cross_entropy)
loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
# 定義學習率衰減
learning_rate = tf.train.exponential_decay(
learning_rate_base,
global_step,
mnist.train.num_examples, # 總玩所有資料需要的迭代次數
learning_rate_decay
)
train_step = tf.train.AdamOptimizer(1e-4).\
minimize(loss, global_step = global_step)
# 定義反向傳播滑動平均模型
with tf.control_dependencies([train_step, variable_averages_op]):
train_op = tf.no_op(name = 'train')
# 準確率
correction_prediction = tf.equal(tf.argmax(logit, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correction_prediction, tf.float32))
# 引數初始化
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
# 總共的批次共迭代times次
for epoch in range(times):
for batch in range(batch_num):
xs, ys = mnist.train.next_batch(batch_size)
_, loss_value, step = sess.run([train_op, loss, global_step],
feed_dict = {x:xs,y:ys,keep_prob:0.7})
acc = sess.run(accuracy,
feed_dict = {x:mnist.test.images, y:mnist.test.labels,keep_prob:1.0})
print("After %d, Testing Accuracy = %g" %(epoch, acc))
# 訓練
train(mnist)
四、經典網路模型
後續會單獨整理一篇由經典網路模型的文章
五、遷移學習
本段程式碼摘自書上,經個人實際執行後結果正確,同時做了更詳細的程式碼註釋,並對書中冗餘的程式碼進行了優化。
首先是處理資料集,並最終將資料集的資訊儲存在.npy檔案中
import numpy as np
import os.path
import glob
from scipy.misc import imread, imresize
# 輸入檔案位置
input_data = 'C:\\Users\\guesthost\\Desktop\\深度學習資料集\\flower_photos\\flower_photos'
# 輸出檔案位置
output_data = 'C:\\Users\\guesthost\\Desktop\\深度學習資料集\\flower_processed_data.npy'
# 測試資料與驗證資料的比例
validation_percentage = 10
test_percentage = 10
def create_image_lists(testing_percentage, validation_percentage):
# 在目錄樹中游走以便讀取目錄下的資料夾名稱
sub_dirs = [x[0] for x in os.walk(input_data)]
is_root_dir = True
training_images = []
training_labels = []
testing_images = []
testing_labels = []
validation_images = []
validation_labels = []
current_label = 0
for sub_dir in sub_dirs:
ret = 1
# 忽略根目錄
if is_root_dir:
is_root_dir = False
continue
extensions = ['jpg', 'jpeg']
file_list = []
dir_name = os.path.join(sub_dir)
for extension in extensions:
# 讀取當前目錄下所有以extension為字尾的檔案
file_glob = os.path.join(input_data, dir_name, '*.' + extension)
file_list.extend(glob.glob(file_glob))
if not file_list:
continue
# 對file_list列表下所有圖片進行處理
for file_name in file_list:
# 對圖片進行解碼
image = imread(file_name)
image_value = imresize(image, [299, 299])
# 隨機劃分資料集
# 根據訓練集:驗證集:測試集 = 8:1:1比例來劃分資料
chance = np.random.randint(100)
if chance < validation_percentage:
validation_images.append(image_value)
validation_labels.append(current_label)
elif chance < (test_percentage + validation_percentage):
testing_images.append(image_value)
testing_labels.append(current_label)
else:
training_images.append(image_value)
training_labels.append(current_label)
print("%d picture is completed" % ret)
ret += 1
print("%d dir is completed!" % current_label)
current_label += 1
# 獲取隨機狀態
state = np.random.get_state()
np.random.shuffle(training_images)
# 以打亂訓練集影象矩陣的狀態同樣打亂訓練集影象標籤
np.random.set_state(state)
np.random.shuffle(training_labels)
return np.asarray([training_images, training_labels,
validation_images, validation_labels,
testing_images, testing_labels])
def main():
processed_data = create_image_lists(test_percentage, validation_percentage)
np.save(output_data, processed_data)
if __name__ == '__main__':
main()
使用Google訓練好的Inception-v3網路模型做遷移學習
import tensorflow as tf
import tensorflow.contrib.slim.python.slim.nets.inception_v3 as inception_v3
import tensorflow.contrib.slim as slim
import load_dataset as load
import numpy as np
# 輸入資料路徑
Input_data = load.output_data
# 預先訓練好的模型路徑
ckpt_file = 'C:/Users/guesthost/Desktop/機器學習/深度學習/深度學習預訓練模型/inception_v3_2016_08_28/inception_v3.ckpt'
# 訓練好的模型路徑
train_file = 'C:/Users/guesthost/Desktop/機器學習/深度學習/深度學習預訓練模型/my_inception_model/my_inception_v3_model'
input_data = load.output_data
learning_rate = 1e-4
steps = 300
batch = 32
n_classes = 5
checkpoint_exclude_scopes = 'InceptionV3/Logits,InceptionV3/AuxLogits'
trainable_scopes = 'InceptionV3/Logits, InceptionV3/AuxLogits'
# 獲取所有需要從訓練好的模型中載入的引數
def get_tuned_variables():
exclusions = [scope.strip() for scope in checkpoint_exclude_scopes.split(',')]
variables_to_restore = []
# 獲取模型所有變數的列表
# 之後篩選出除了op名稱的開頭為exclusion的以外的op作為需要訓練的引數返回
for var in slim.get_model_variables():
excluded = False
for exclusion in exclusions:
if var.op.name.startswith(exclusion):
excluded = True
break
if not excluded:
variables_to_restore.append(var)
return variables_to_restore
# 獲取所有需要訓練的變數列表
def get_trainable_variables():
scopes = [scope.strip() for scope in trainable_scopes.split(',')]
variables_to_train = []
for scope in scopes:
# 獲取tf.GraphKeys圖物件中所有可訓練的變數
variables = tf.get_collection(
tf.GraphKeys.TRAINABLE_VARIABLES, scope)
variables_to_train.extend(variables)
return variables_to_train
def main():
processed_data = np.load(input_data)
training_images = processed_data[0]
n_training_example = len(training_images)
training_labels = processed_data[1]
validation_images = processed_data[2]
validation_labels = processed_data[3]
testing_images = processed_data[4]
testing_labels = processed_data[5]
print("%d trianing examples, %d validation examples and %d testing examples."\
%(n_training_example, len(validation_images), len(testing_images)))
images = tf.placeholder(tf.float32, shape = [None, 299, 299, 3], name = 'x-input')
labels = tf.placeholder(tf.int64, shape = [None], name = 'labels')
# 載入模型的預設變數
with slim.arg_scope(inception_v3.inception_v3_arg_scope()):
logits, _ = inception_v3.inception_v3(images, num_classes = n_classes)
# 交叉熵損失
tf.losses.softmax_cross_entropy(tf.one_hot(labels, n_classes), logits = logits, weights = 1.0)
# 定義訓練過程
train_step = tf.train.RMSPropOptimizer(learning_rate).minimize(tf.losses.get_total_loss())
# 計算正確率
with tf.name_scope('evaluation'):
correct_prediction = tf.equal(tf.argmax(logits, 1), labels)
evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 定義從ckpt檔案中返回指定的變數的函式
# 這裡的get_tuned_variables() 表示返回需要訓練的變數
# ignore_missing_vars = True 表示若沒有變數時,返回None
load_fn = slim.assign_from_checkpoint_fn(ckpt_file, get_tuned_variables(), ignore_missing_vars = True)
# 定義儲存新的訓練好得模型
saver = tf.train.Saver()
with tf.Session() as sess:
# 初始化需要在模型載入之前,否則初始化過程會將已經載入好的變數衝重新賦值
init = tf.global_variables_initializer()
sess.run(init)
print("Loading tuned variables from %s" % ckpt_file)
load_fn(sess)
start = 0
end = batch
for i in range(steps):
start = (i * batch) % n_training_example
end = min(start + batch, n_training_example)
sess.run(train_step, feed_dict = {images:training_images[start:end],labels:training_labels[start:end]})
# 列印驗證集準確率
if i % 30 == 0 or i + 1 == steps:
saver.save(sess, train_file, global_step = i)
validation_accuracy = sess.run(evaluation_step, feed_dict = {images:validation_images, labels:validation_labels})
print("Step %d Validation accuracy = %.1f%%" %(i, validation_accuracy * 100))
# 列印測試集準確率
test_accuracy = sess.run(evaluation_step, feed_dict = {images:testing_images, labels:testing_labels})
print('Final test accuracy = %.1f%%' %(test_accuracy * 100))
main()