聖誕節玩的有點嗨,差點忘記更新。祝大家昨天聖誕節快樂,再過幾天元旦節快樂。
來繼續學習,在/home/your_name/TensorFlow/cifar10/ 下新建文件夾cifar10_train,用來保存訓練時的日志logs,繼續在/home/your_name/TensorFlow/cifar10/ cifar10.py中輸入如下代碼:
def train(): # global_step global_step = tf.Variable(0, name = 'global_step', trainable=False) # cifar10 數據文件夾 data_dir = '/home/your_name/TensorFlow/cifar10/data/cifar-10-batches-bin/' # 訓練時的日志logs文件,沒有這個目錄要先建一個 train_dir = '/home/your_name/TensorFlow/cifar10/cifar10_train/' # 加載 images,labels images, labels = my_cifar10_input.inputs(data_dir, BATCH_SIZE) # 求 loss loss = losses(inference(images), labels) # 設置優化算法,這里用 SGD 隨機梯度下降法,恆定學習率 optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE) # global_step 用來設置初始化 train_op = optimizer.minimize(loss, global_step = global_step) # 保存操作 saver = tf.train.Saver(tf.all_variables()) # 匯總操作 summary_op = tf.merge_all_summaries() # 初始化方式是初始化所有變量 init = tf.initialize_all_variables() os.environ['CUDA_VISIBLE_DEVICES'] = str(0) config = tf.ConfigProto() # 占用 GPU 的 20% 資源 config.gpu_options.per_process_gpu_memory_fraction = 0.2 # 設置會話模式,用 InteractiveSession 可交互的會話,逼格高 sess = tf.InteractiveSession(config=config) # 運行初始化 sess.run(init) # 設置多線程協調器 coord = tf.train.Coordinator() # 開始 Queue Runners (隊列運行器) threads = tf.train.start_queue_runners(sess = sess, coord = coord) # 把匯總寫進 train_dir,注意此處還沒有運行 summary_writer = tf.train.SummaryWriter(train_dir, sess.graph) # 開始訓練過程 try: for step in xrange(MAX_STEP): if coord.should_stop(): break start_time = time.time() # 在會話中運行 loss _, 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 % 30 == 0: # 本小節代碼設置一些花哨的打印格式,可以不用管 num_examples_per_step = 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 % 100 == 0: # 運行匯總操作, 寫入匯總 summary_str = sess.run(summary_op) summary_writer.add_summary(summary_str, step) if step % 1000 == 0 or (step + 1) == MAX_STEP: # 保存當前的模型和權重到 train_dir,global_step 為當前的迭代次數 checkpoint_path = os.path.join(train_dir, 'model.ckpt') saver.save(sess, checkpoint_path, global_step=step) except Exception, e: coord.request_stop(e) finally: coord.request_stop() coord.join(threads) sess.close() def evaluate(): data_dir = '/home/your_name/TensorFlow/cifar10/data/cifar-10-batches-bin/' train_dir = '/home/your_name/TensorFlow/cifar10/cifar10_train/' images, labels = my_cifar10_input.inputs(data_dir, BATCH_SIZE, train = False) logits = inference(images) saver = tf.train.Saver(tf.all_variables()) os.environ['CUDA_VISIBLE_DEVICES'] = str(0) config = tf.ConfigProto() config.gpu_options.per_process_gpu_memory_fraction = 0.2 sess = tf.InteractiveSession(config=config) coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess = sess, coord = coord) # 加載模型參數 print("Reading checkpoints...") ckpt = tf.train.get_checkpoint_state(train_dir) if ckpt and ckpt.model_checkpoint_path: ckpt_name = os.path.basename(ckpt.model_checkpoint_path) global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1] saver.restore(sess, os.path.join(train_dir, ckpt_name)) print('Loading success, global_step is %s' % global_step) try: # 對比分類結果,至於為什么用這個函數,后面詳談 top_k_op = tf.nn.in_top_k(logits, labels, 1) true_count = 0 step = 0 while step < 157: if coord.should_stop(): break predictions = sess.run(top_k_op) true_count += np.sum(predictions) step += 1 precision = true_count / 10000 print('%s: precision @ 1 = %.3f' % (datetime.now(), precision)) except tf.errors.OutOfRangeError: coord.request_stop() finally: coord.request_stop() coord.join(threads) sess.close() if __name__ == '__main__': if TRAIN: train () else: evaluate()
現在說明一下 in_top_k 這個函數的作用,官方文檔介紹中: tf.nn.in_top_k(predictions, targets, k, name=None)
這個函數返回一個 batch_size 大小的布爾矩陣 array,predictions 是一個 batch_size*classes 大小的矩陣,targets 是一個 batch_size 大小的類別 index 矩陣,這個函數的作用是,如果 targets[i] 是 predictions[i][:] 的前 k 個最大值,則返回的 array[i] = True, 否則,返回的 array[i] = False。可以看到,在上述評估程序 evaluate 中,這個函數沒有用 softmax 的結果進行計算,而是用 inference 最后的輸出結果(一個全連接層)進行計算。
寫完之后,點擊運行,可以看到,訓練的 loss 值,從剛開始的 2.31 左右,下降到最終的 0.00 左右,在訓練的過程中,/home/your_name/TensorFlow/cifar10/cifar10_train/ 文件夾下會出現12個文件,其中有 5 個 model.ckpt-0000 文件,這個是訓練過程中保存的模型,后面的數字表示迭代次數,5 個 model.ckpt-0000.meta 文件,這個是訓練過程中保存的元數據(暫時不清楚功能),TensorFlow 默認只保存近期的幾個模型和幾個元數據,刪除前面沒用的模型和元數據。還有個 checkpoint 的文本文檔,和一個 out.tfevents 形式的文件,是summary 的日志文件。如果不想用 tensorboard 看網絡結構和訓練過程中的權重分布,損失情況等等,在程序中可以不寫 summary 語句。
訓練完成之后,我們用 tensorboard 進行可視化(事實上在訓練的過程中,隨時可以可視化)。在任意位置打開命令行終端,輸入:
tensorboard --logdir=/home/your_name/TensorFlow/cifar10/cifar10_train/
會出現如下指示:
根據指示,打開瀏覽器,輸入 http://127.0.1.1:6006(有的瀏覽器可能不支持,建議多換幾個瀏覽器試試)會看到可視化的界面,有六個選項卡:
EVENTS 對話框里面有兩個圖,一個是訓練過程中的 loss 圖,一個是隊列 queue 的圖;由於沒有 image_summary() 和 audio_summary() 語句,所以,IMAGES 和 AUDIO 選項卡都沒有內容;GRAPHS 選項卡包含了整個模型的流程圖,如下圖,可以展開和移動選定的 namespace;DISTRBUTIONS 和 HISTOGRAMS 包含了訓練時的各種匯總的分布和柱狀圖。
訓練完之后,設置 TRAIN = False,進行測試,得到如下結果:
可以看到,測試的精度只有 76%,測試結果不夠高的原因可能是,測試的時候沒有經過 softmax 層,直接用全連接層的權重(存疑?),另外官方的代碼也給出了官方的運行結果,如下:
可以看到,經過 10 萬次迭代,官方給出的正確率達到 83%,我們只進行了 5 萬次,達到 76% 的正確率,相對來說,還算可以,效果沒有官方好的原因可能是:
1. 官方使用了非固定的學習率;
2. 官方迭代比本代碼迭代次數多一倍;
參考文獻:
1. https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10