tensorflow實現CNN卷積神經網路
來自專欄 機器學習每日一記
轉載請註明來源。
前言:
在tensorflow官方教程中有CNN卷積神經網路的example,並且利用cifar10數據集進行訓練和測試
地址如下:
Convolutional Neural Networks | TensorFlow當我們信心滿滿的跑通官方的例子並測試了該數據集訓練後的模型精度後,我們想要訓練自己的數據集,比如訓練只識別貓和狗的模型該怎麼辦呢?若是不按規則的直接將訓練數據輸入到模型中肯定會有各種問題出現,這點Google官方教程比較煩人,老是拿minist/cifar-10這類構造好的數據集,該如何構造類似的數據集官方並沒有給出說明,讀者想構造自己的數據集進行訓練時往往不知從何處下手.因此本篇由此而生.
首先,tensorflow提供了一個統一的文件格式對象介面,TFrecord,TFrecord文件的讀寫非常方便、快速和統一.我們可以將自己的訓練數據轉化為自定義的TFrecord文件,在訓練模型時訓練數據集從TFrecord文件讀取即可
接下來演示將圖片數據集轉化為TFrecod文件的例子:
首先我的數據集有如下目錄結構:
faces文件夾下有三個文件夾,分別是三個人的人臉圖片
note:圖片名字和格式任意,因為我的圖片是程序自動抓取攝像頭生成的,不要看到是 bmp格式以及名字按序命名就認為自己測試時也要如此,任意就好,只要是圖片就行。
接下來利用程序將faces整個文件夾里的圖片生成TFrecord文件並讀取:
tfrecord.py
#coding:utf-8# -*- coding: utf-8 -*-# @Time : 2018/4/11 10:08# @Author : jiaopan# @Email : jiaopaner@163.comimport tensorflow as tfimport os,sys,timefrom PIL import Imageimport utilsIMAGE_SIZE = int(utils.configUtil("global.conf","dataset", "resize_image_size")) # 裁剪大小IMAGE_MAT_SIZE = int(utils.configUtil("global.conf","dataset", "image_mat_size")) # reshape參數CHANNELS = int(utils.configUtil("global.conf","dataset","chnnels")) # 通道TRAIN_DATASET = utils.configUtil("global.conf","dataset", "train_data_dir") # 訓練原始數據EVAL_DATASET = utils.configUtil("global.conf","dataset", "eval_data_dir") # 驗證集原始數據BATCH_SIZE = int(utils.configUtil("global.conf","dataset","batch_size"))#以上是我在測試讀取的配置文件參數,#若你不想從配置文件中讀取,直接將方法里的參數值設為你需要的值即可def create(dataset_dir,tfrecord_path,tfrecord_name="train_tfrecord", width=IMAGE_SIZE,height=IMAGE_SIZE): """ #構建圖片TFrecord文件 param dataset_dir:原始圖片的根目錄,目錄下包含多個子目錄,每個子目錄下為同一類別的圖片 param tfrecord_name:存儲的TFreord文件名 param tfrecord_path:存儲的TFreord文件的目錄路徑 param width:圖片裁剪寬度 param height:圖片裁剪高度 param channels:通道 =1 灰度圖 =3 RGB 彩色圖 """ if not os.path.exists(dataset_dir): print(創建TFRECORD文件時出錯,文件目錄或文件不存在,請檢查路徑名..
) exit() if not os.path.exists(os.path.dirname(tfrecord_path)): os.makedirs(os.path.dirname(tfrecord_path)) #創建TF文件寫對象 writer = tf.python_io.TFRecordWriter(os.path.join( tfrecord_path,tfrecord_name)) #讀取根目錄 即faces目錄 faces下總共有三個子目錄,labels = [jp,wts,zcl] lables = os.listdir(dataset_dir) print(一共 %d 個類別
% len(lables)) #enumerate(lables) -> {0:jp,1:wts,2:zcl} #此時jp對應的類別為0 ,wts對應的類別為1,zcl對應的類別為2 for index,label in enumerate(lables): print(
正在處理類別為 %s 的數據集 %label) time0 = time.time() filepath = os.path.join(dataset_dir,label) filesNames = os.listdir(filepath) for i,file in enumerate(filesNames): imgPath = os.path.join(filepath,file) img = Image.open(imgPath) img = img.resize((width,height))#裁剪圖片 img = img.tobytes()#將圖片轉為二進位格式 #構造tfrecord example = tf.train.Example(features=tf.train.Features(feature={ "label": tf.train.Feature( int64_list=tf.train.Int64List(value=[index])), image: tf.train.Feature( bytes_list=tf.train.BytesList(value=[img])) })) writer.write(example.SerializeToString()) sys.stdout.write(
>> Converting image %d/%d , %g s % ( i+1, len(filesNames), time.time() - time0)) writer.close() print(
Finished writing data to tfrecord files.)def read(tfrecord_path,width,height,channels): """ 讀取tfrecord 解析圖片並預處理 param tfrecord_path:tfrecord 文件目錄(可能含有多個Tfrecord文件) Note:若讀取多個TFrecord文件則這些文件在生成時參數裁剪大小參數和通道數應一致 否則讀取時會出錯 param width,height:轉換矩陣維度 param channels:通道 return: float_image,label """ files = os.listdir(tfrecord_path) filenames = [os.path.join( tfrecord_path,tfrecord_name) for tfrecord_name in files] #構建文件隊列 shuffle=True表示讀取時打亂順序 filename_queue = tf.train.string_input_producer(filenames, num_epochs=None, shuffle=True) reader = tf.TFRecordReader() key,serialized_example = reader.read(filename_queue) #保持和生成設置的字典一致 features = tf.parse_single_example(serialized_example,features={ "label": tf.FixedLenFeature([],tf.int64), image: tf.FixedLenFeature([],tf.string) }) img = features[image] #二進位數據 img = tf.decode_raw(img,tf.uint8) img = tf.reshape(img,[channels,width,height]) # 轉置 tf.transpose #原因:tf.nn.conv2d()的input參數shape為 #[batch, in_height, in_width, in_channels] img = tf.transpose(img, [1, 2, 0]) label = tf.cast(features[label], tf.int32) return img,label#對讀取的圖片進行預處理def data_process(img): img = tf.cast(img, tf.float32) img = tf.image.random_flip_left_right(img) # 圖片隨機左右翻轉 img = tf.image.random_brightness(img, max_delta=63) # 變換圖像的亮度 img = tf.image.random_contrast(img, lower=0.2, upper=1.8) # 變換圖像的對比度 float_image = tf.image.per_image_standardization(img) # 圖像標準化 return float_image#訓練圖片數據集讀取封裝方法def train_data_read(tfrecord_path,width=IMAGE_MAT_SIZE,height=IMAGE_MAT_SIZE,channels=CHANNELS): if not os.path.exists(tfrecord_path): os.makedirs(tfrecord_path) create(dataset_dir=TRAIN_DATASET,tfrecord_path=tfrecord_path) img, label = read(tfrecord_path, width, height, channels) #圖片處理 float_image = data_process(img) return float_image,label#驗證集圖片數據集讀取的的封裝方法def eval_data_read(tfrecord_path,width=IMAGE_MAT_SIZE,height=IMAGE_MAT_SIZE,channels=CHANNELS): if not os.path.exists(tfrecord_path): os.makedirs(tfrecord_path) create(dataset_dir=EVAL_DATASET,tfrecord_path=tfrecord_path) img, label = read(tfrecord_path, width, height, channels) img = tf.cast(img, tf.float32) float_image = tf.image.per_image_standardization(img) return float_image,label#構建batch [batch的含義自行google]def create_batch(float_image,label,count_num,batch_size=50): batch < min_after_dequeue < capacity count_num:圖片總數 capacity = int(count_num * 0.6 + 3 * BATCH_SIZE) min_after_dequeue = int(count_num * 0.6) images,label_batch = tf.train.shuffle_batch([float_image,label],batch_size=batch_size, capacity=capacity,min_after_dequeue=min_after_dequeue,num_threads=5) tf.summary.image(images, images) # 圖像可視化 tensorboard return images,label_batch#note:#在create_batch中的tf.train.shuffle_batch()方法中,有人可能會有疑問:#為什麼明明傳入的是一張圖片卻返回了多個值?是不是只將第一張圖片複製了多次?#當然不是,其實以上所有操作都還沒有真正的數據傳入,#tensorflow在執行前會將所有操作記錄為計算流圖,好比流程圖一樣,記錄此處該做什麼操作而已#當所有計算流圖記錄完畢,也就是執行sess.run()後才會有數據傳入#比如此處傳入的float_image的來源會回溯到read()方法,而read()方法以隊列讀取,#隊列里有多個文件,reader.read(filename_queue)會執行多次一樣if __name__ == __main__: #####測試##### create(tfrecord_path=D:/learn/tensorflow/tfrecord/train, tfrecord_name=tfrecord_train, dataset_dir=D:/learn//tensorflow/faces) float_image,label = train_data_read(tfrecord_path=D:/learn/tensorflow/tfrecord/train) images,label_batch = create_batch(float_image,label,1000) with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) coord=tf.train.Coordinator() threads= tf.train.start_queue_runners(coord=coord) for i in range(1):#循環一個batch 每個batch 我設置為50張圖片 # 在會話中取出image和label example, l = sess.run([images,label_batch]) print(example, l)#列印值:圖像轉化為的數字矩陣 以及對應標籤 coord.request_stop() coord.join(threads)
測試後生成的tfrecord文件:
生成了TFrecord格式的數據集,就可以傳入到CNN網路進行訓練了啦,構造自己想要的模型.我這裡是訓練jp,wts,zlc這三個人的分類模型(你也可以訓練貓、狗等動物的分類)
訓練好後傳入其中一人的照片給出是誰的結果.
network.py [CNN網路的構建]
# -*- coding: utf-8 -*-# @Time : 2018/4/11 10:08# @Author : jiaopan# @Email : jiaopaner@163.comfrom __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionimport reimport tensorflow as tfimport utilsFLAGS = tf.app.flags.FLAGStf.app.flags.DEFINE_integer(batch_size, int(utils.configUtil("global.conf","dataset","batch_size")),"""每個batch樣本總數""")IMAGE_SIZE = int(utils.configUtil("global.conf","dataset","image_mat_size"))NUM_CLASSES = int(utils.configUtil("global.conf","dataset","num_class"))NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = int(utils.configUtil("global.conf","train","train_data_count"))NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = int(utils.configUtil("global.conf","eval","eval_data_count"))#以上是我在測試讀取的配置文件參數,#若你不想從配置文件中讀取,直接將方法里的參數值設為你需要的值即可# 超參數設置MOVING_AVERAGE_DECAY = 0.9999NUM_EPOCHS_PER_DECAY = 350.0LEARNING_RATE_DECAY_FACTOR = 0.1INITIAL_LEARNING_RATE = 0.1TOWER_NAME = towerdef activation_summary(x): """創建tensorboard摘要.""" tensor_name = re.sub(%s_[0-9]*/ % TOWER_NAME, , x.op.name) tf.summary.histogram(tensor_name + /activations, x) tf.summary.scalar(tensor_name + /sparsity, tf.nn.zero_fraction(x))def variable_on_cpu(name, shape, initializer): """針對CPU-train 初始化參數.""" with tf.device(/cpu:0): var = tf.get_variable(name, shape, initializer=initializer) return vardef variable_with_weight_decay(name, shape, stddev, wd): """初始化 Variable with weight decay""" var = variable_on_cpu(name, shape,tf.truncated_normal_initializer(stddev=stddev)) if wd: weight_decay = tf.multiply(tf.nn.l2_loss(var), wd, name=weight_loss) tf.add_to_collection(losses, weight_decay) return vardef inference(images): """構建模型. Args: images: Images returned from distorted_inputs() or inputs(). """ # tf.get_variable() 可參數共享 針對multiple GPU # tf.Variable() single GPU # # 卷積層1 with tf.variable_scope(conv1) as scope: #初始化卷積核 kernel = variable_with_weight_decay(weights, shape=[5, 5, 3, 64], stddev=1e-4, wd=0.0) #卷積操作 conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding=SAME) biases = variable_on_cpu(biases, [64], tf.constant_initializer(0.0)) bias = tf.nn.bias_add(conv, biases) conv1 = tf.nn.relu(bias, name=scope.name) activation_summary(conv1) # 池化層1 pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding=SAME, name=pool1) # 局部響應標準化 norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=norm1) # 卷積層2 with tf.variable_scope(conv2) as scope: kernel = variable_with_weight_decay(weights, shape=[5, 5, 64, 64], stddev=1e-4, wd=0.0) conv = tf.nn.conv2d(norm1, kernel, [1, 1, 1, 1], padding=SAME) biases = variable_on_cpu(biases, [64], tf.constant_initializer(0.1)) bias = tf.nn.bias_add(conv, biases) conv2 = tf.nn.relu(bias, name=scope.name) activation_summary(conv2) # 局部響應標準化 norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name=norm2) # 池化層2 pool2 = tf.nn.max_pool(norm2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding=SAME, name=pool2) ###############全連接層################ #local3 with tf.variable_scope(local3) as scope: dim = 1 for d in pool2.get_shape()[1:].as_list(): dim *= d reshape = tf.reshape(pool2, [FLAGS.batch_size, dim]) weights = variable_with_weight_decay(weights, shape=[dim, 384], stddev=0.04, wd=0.004) biases = variable_on_cpu(biases, [384], tf.constant_initializer(0.1)) local3 = tf.nn.relu(tf.matmul(reshape, weights) + biases, name=scope.name) activation_summary(local3) # local4 with tf.variable_scope(local4) as scope: weights = variable_with_weight_decay(weights, shape=[384, 192], stddev=0.04, wd=0.004) biases = variable_on_cpu(biases, [192], tf.constant_initializer(0.1)) local4 = tf.nn.relu(tf.matmul(local3, weights) + biases, name=scope.name) activation_summary(local4) # softmax, i.e. softmax(WX + b) with tf.variable_scope(softmax_linear) as scope: weights = variable_with_weight_decay(weights, [192, NUM_CLASSES], stddev=1/192.0, wd=0.0) biases = variable_on_cpu(biases, [NUM_CLASSES], tf.constant_initializer(0.0)) softmax_linear = tf.add(tf.matmul(local4, weights), biases, name=scope.name) activation_summary(softmax_linear) return softmax_lineardef loss(logits, labels): """L2正則的誤差計算.""" sparse_labels = tf.reshape(labels, [FLAGS.batch_size, 1]) indices = tf.reshape(tf.range(FLAGS.batch_size), [FLAGS.batch_size, 1]) concated = tf.concat([indices, sparse_labels], 1) dense_labels = tf.sparse_to_dense(concated, [FLAGS.batch_size, NUM_CLASSES],1.0, 0.0) cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits = logits, labels = dense_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)def add_loss_summaries(total_loss): """創建誤差tesorboard摘要""" loss_averages = tf.train.ExponentialMovingAverage(0.9, name=avg) losses = tf.get_collection(losses) loss_averages_op = loss_averages.apply(losses + [total_loss]) for l in losses + [total_loss]: tf.summary.scalar(l.op.name + (raw), l) tf.summary.scalar(l.op.name, loss_averages.average(l)) return loss_averages_opdef train(total_loss, global_step): """訓練模型.""" #每個epoch的batch數 num_batches_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN / FLAGS.batch_size decay_steps = int(num_batches_per_epoch * NUM_EPOCHS_PER_DECAY) # 學習速率的配置 lr = tf.train.exponential_decay(INITIAL_LEARNING_RATE,global_step,decay_steps, LEARNING_RATE_DECAY_FACTOR, staircase=True) tf.summary.scalar(learning_rate, lr) loss_averages_op = add_loss_summaries(total_loss) # 梯度下降 with tf.control_dependencies([loss_averages_op]): opt = tf.train.GradientDescentOptimizer(lr) grads = opt.compute_gradients(total_loss) apply_gradient_op = opt.apply_gradients(grads, global_step=global_step) for var in tf.trainable_variables(): tf.summary.histogram(var.op.name, var) for grad, var in grads: if grad is not None: tf.summary.histogram(var.op.name + /gradients, grad) 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
train.py [執行訓練的程序]
# -*- coding: utf-8 -*-# @Time : 2018/4/11 10:08# @Author : jiaopan# @Email : jiaopaner@163.com# 訓練模塊from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionfrom datetime import datetimeimport os.pathimport timeimport numpy as npfrom six.moves import xrangeimport tensorflow as tfimport networkimport tfrecordimport utilsFLAGS = tf.app.flags.FLAGStf.app.flags.DEFINE_string(train_dir, utils.configUtil("global.conf","model","model_dir"), """模型保存目錄""" """檢查點存儲目錄.(tensorboard查看)""")tf.app.flags.DEFINE_integer(max_steps, int(utils.configUtil("global.conf","train","max_steps")), """最大訓練/迭代次數.""")tf.app.flags.DEFINE_boolean(log_device_placement, False,"""""")tf.app.flags.DEFINE_string(train_data,utils.configUtil("global.conf","train","train_tfrecord_dir"), 訓練集目錄(tfrecord))tf.app.flags.DEFINE_integer(train_num,int(utils.configUtil("global.conf","train","train_data_count")), 訓練集樣本總數)#以上是我在測試讀取的配置文件參數,#若你不想從配置文件中讀取,直接將方法里的參數值設為你需要的值即可def train(): with tf.Graph().as_default(): global_step = tf.Variable(0, trainable=False) # 獲得圖片數據和對應的標籤batch float_image, label = tfrecord.train_data_read(tfrecord_path=FLAGS.train_data) images, labels = tfrecord.create_batch(float_image,label,count_num=FLAGS.train_num) logits = network.inference(images) # 誤差計算 loss = network.loss(logits, labels) # 模型訓練 train_op = network.train(loss, global_step) # 存儲模型 saver = tf.train.Saver(tf.global_variables()) # 存儲所有操作 summary_op = tf.summary.merge_all() # 初始化所有變數. init = tf.initialize_all_variables() # 開始計算流圖 sess = tf.Session(config=tf.ConfigProto( log_device_placement=FLAGS.log_device_placement)) sess.run(init) # 隊列開始 tf.train.start_queue_runners(sess=sess) summary_writer = tf.summary.FileWriter(FLAGS.train_dir, graph_def=sess.graph_def) for step in xrange(FLAGS.max_steps):#迭代訓練 start_time = time.time() _, loss_value = sess.run([train_op, loss]) duration = time.time() - start_time assert not np.isnan(loss_value), Model diverged with loss = NaN if step % 10 == 0:#每訓練10次列印一次訓練誤差 num_examples_per_step = FLAGS.batch_size examples_per_sec = num_examples_per_step / duration sec_per_batch = float(duration) format_str = (%s: step %d, loss = %.2f (%.1f examples/sec; %.3f sec/batch)) print (format_str % (datetime.now(), step, loss_value, examples_per_sec, sec_per_batch)) if step % 50 == 0:#每訓練50次保存參數 summary_str = sess.run(summary_op) summary_writer.add_summary(summary_str, step) # 開始時保存模型 然後每訓練1000次更新模型. if step % 1000 == 0 or (step + 1) == FLAGS.max_steps: checkpoint_path = os.path.join(FLAGS.train_dir, model.ckpt) saver.save(sess, checkpoint_path, global_step=step)def main(argv=None): #命令行 train()if __name__ == __main__: tf.app.run()
network_eval.py [模型驗證程序 評估模型訓練的精度]
#coding:utf-8# -*- coding: utf-8 -*-# @Time : 2018/4/11 10:08# @Author : jiaopan# @Email : jiaopaner@163.com# 模型驗證模塊from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionfrom datetime import datetimeimport mathimport timefrom tensorflow.python.platform import gfileimport numpy as npimport tensorflow as tfimport networkimport tfrecordimport utilsFLAGS = tf.app.flags.FLAGStf.app.flags.DEFINE_string(eval_dir, utils.configUtil("global.conf","eval","eval_log_dir"), """驗證日誌目錄.""")tf.app.flags.DEFINE_string(eval_data, utils.configUtil("global.conf","eval","eval_tfrecord_dir"), """驗證數據集目錄""")tf.app.flags.DEFINE_string(checkpoint_dir, utils.configUtil("global.conf","model","model_dir"), """保存的模型.""")tf.app.flags.DEFINE_integer(eval_interval_secs,60*3, """設置每隔多長時間做一次評估""")tf.app.flags.DEFINE_integer(num_examples, int(utils.configUtil("global.conf","eval","eval_data_count")), """驗證數據集樣本總數""")tf.app.flags.DEFINE_boolean(run_once, False, """僅驗證一次.""")def eval_once(saver, summary_writer, top_k_op, summary_op): with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir) if ckpt and ckpt.model_checkpoint_path: saver.restore(sess, ckpt.model_checkpoint_path)#載入訓練好的模型檢查點 global_step = ckpt.model_checkpoint_path.split(/)[-1].split(-)[-1] else: print(No checkpoint file found) return coord = tf.train.Coordinator() try: threads = [] for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS): threads.extend(qr.create_threads(sess, coord=coord, daemon=True,start=True)) num_iter = int(math.ceil(FLAGS.num_examples / FLAGS.batch_size))#迭代次數 true_count = 0 # 預測正確的次數 total_sample_count = num_iter * FLAGS.batch_size #驗證的樣本總數 step = 0 while step < num_iter and not coord.should_stop(): predictions = sess.run([top_k_op]) #e.g. return [true,false,true,false,false] true_count += np.sum(predictions) step += 1 #準確率計算 precision = true_count / total_sample_count print(%s: precision @ 1 = %.3f % (datetime.now(), precision)) summary = tf.Summary() summary.ParseFromString(sess.run(summary_op)) summary.value.add(tag=Precision @ 1, simple_value=precision) summary_writer.add_summary(summary, global_step) except Exception as e: coord.request_stop(e) coord.request_stop() coord.join(threads, stop_grace_period_secs=10)def evaluate(): """Eval CIFAR-10 for a number of steps.""" with tf.Graph().as_default(): float_image, label = tfrecord.eval_data_read(tfrecord_path=FLAGS.eval_data) images, labels = tfrecord.create_batch(float_image, label, count_num=FLAGS.num_examples) logits = network.inference(images) # tf.nn.in_top_k:計算預測的結果和實際結果的是否相等,返回bool類型的張量 top_k_op = tf.nn.in_top_k(logits, labels, 1) variable_averages = tf.train.ExponentialMovingAverage(network.MOVING_AVERAGE_DECAY) variables_to_restore = variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) summary_op = tf.summary.merge_all() graph_def = tf.get_default_graph().as_graph_def() summary_writer = tf.summary.FileWriter(FLAGS.eval_dir, graph_def=graph_def) while True: eval_once(saver, summary_writer, top_k_op, summary_op) if FLAGS.run_once: break time.sleep(FLAGS.eval_interval_secs)def main(argv=None): if gfile.Exists(FLAGS.eval_dir): gfile.DeleteRecursively(FLAGS.eval_dir) gfile.MakeDirs(FLAGS.eval_dir) evaluate()if __name__ == __main__: tf.app.run()
整個模型建立流程如下:
- 執行tfrecord.py生成tfrecord訓練集和驗證集文件,訓練集合驗證集生成時參數設置應一致
- 執行train.py開始訓練模型 每訓練1000次後保存或更新模型
- 執行train.py的同時執行network_eval.py它會在設定的時間間隔內,載入保存的模型,利用驗證數據集去評估模型的準確率
我測試時訓練的迭代次數為一萬次,其實在4000次左右時模型的誤差就保持在很低的水平了,接近0
同時驗證的程序執行時,模型的準確率逐步提高,最後到達了97%左右
(當然了,因為我的類別只有三個,所以較簡單的CNN網路訓練10000次能到達97%當然是可以的)
訓練好模型後,當然是傳入新的圖片(三人之一),看看模型能不能知道傳入的圖片是誰了
classify.py# -*- coding: utf-8 -*-# @Time : 2018/4/15 2:14# @Author : jiaopan# @Email : jiaopaner@163.comfrom PIL import Imageimport tensorflow as tfimport networkimport utilsFLAGS = tf.app.flags.FLAGStf.app.flags.DEFINE_string(checkpoint_dir, utils.configUtil("global.conf","model","model_dir"), """保存的模型.""")def inputs(input,count=1,batch_size=1): network.FLAGS.batch_size = batch_size img = Image.open(input) img = img.resize((32, 32)) img = img.tobytes() img = tf.decode_raw(img, tf.uint8) img = tf.reshape(img, [3, 32, 32]) img = tf.transpose(img, [1, 2, 0]) img = tf.cast(img, tf.float32) float_image = tf.image.per_image_standardization(img) capacity = int(count * 0.4 + 3 * batch_size) min_after_dequeue = int(batch_size * 0.4) images, label_batch = tf.train.shuffle_batch([float_image, ?], batch_size=batch_size, capacity=capacity, min_after_dequeue=min_after_dequeue, num_threads=5) return imagesdef predict(imgPath): with tf.Graph().as_default(): float_image = inputs(imgPath) logits = network.inference(float_image) #top_k_op = tf.nn.in_top_k(logits, [0], 1) variable_averages = tf.train.ExponentialMovingAverage(network.MOVING_AVERAGE_DECAY) variables_to_restore = variable_averages.variables_to_restore() saver = tf.train.Saver(variables_to_restore) summary_op = tf.summary.merge_all() graph_def = tf.get_default_graph().as_graph_def() summary_writer = tf.summary.FileWriter(/tmp/jiaopan/pred, graph_def=graph_def) with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir) if ckpt and ckpt.model_checkpoint_path: print(ckpt.model_checkpoint_path) saver.restore(sess, ckpt.model_checkpoint_path) global_step = ckpt.model_checkpoint_path.split(/)[-1].split(-)[-1] else: print(No checkpoint file found) return coord = tf.train.Coordinator() try: threads = [] for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS): threads.extend(qr.create_threads(sess, coord=coord, daemon=True, start=True)) predictions = sess.run([logits]) print(predictions) summary = tf.Summary() summary.ParseFromString(sess.run(summary_op)) summary.value.add(tag=Precision @ 1, simple_value=1) summary_writer.add_summary(summary, global_step) except Exception as e: coord.request_stop(e) coord.request_stop() coord.join(threads, stop_grace_period_secs=10)def main(argv=None): predict("D:/learn/machine_learning/deep-learning/tensorflow/test/jp/33.bmp")if __name__ == __main__: tf.app.run()
結果:
我這裡是將logits列印出來了,你可以再寫一步程序將數組最大值的索引提出來,其索引值就是類別值,再和類別字典對應就能列印出名字了.如這裡我傳入jp的一張圖片進行測試,列印的結果可以看出第一個值最大,最大值的索引為0,所以分類正確.
{0:jp,1:wts,2:zcl} (tfrecord中設置類別字典時,以文件夾的讀取順序而設置)
global.cnf文件
[dataset]train_data_dir = D:/learn/machine_learning/deep-learning/tensorflow/traineval_data_dir = D:/learn/machine_learning/deep-learning/tensorflow/evalnum_class = 3resize_image_size = 32image_mat_size = 32chnnels = 3batch_size = 50[train]train_tfrecord_dir = D:/learn/machine_learning/deep-learning/tensorflow/tfrecord/traintrain_data_count = 850max_steps = 5000[eval]eval_log_dir = /tmp/jiaopan/evaleval_tfrecord_dir = D:/learn/machine_learning/deep-learning/tensorflow/tfrecord/evaleval_data_count = 48[model]model_dir = /tmp/jiaopan/model
讀取配置文件的tool:
# -*- coding: utf-8 -*-# @Time : 2018/4/14 17:57# @Author : jiaopan# @Email : jiaopaner@163.comimport configparserdef configUtil(confir_file,name, key): """ 讀取配置文件 param confir_file:配置文件 param name:配置項名 param key:配置鍵名 """ conf = configparser.ConfigParser() try:conf.read(confir_file) except:print(confir_file+"不存在或"+name+"/"+"key未配置") return conf.get(name, key)
我將代碼放到了github,有需要的請自行下載.
https://github.com/JiaoPaner/image_classify推薦閱讀:
TAG:TensorFlow | Python | 深度學習DeepLearning |