Tensorflow(1)IT男識別玫瑰

這是一個關於IT男的故事

IT男開始學習如何使用Inception代碼庫識別玫瑰

背景知識

   在機器學習領域,卷積神經網絡是大多數最早進的計算機視覺解決方案的核心,適用於各類任務。其中Tensorflow的Inception代碼庫也是基於此網絡解決了圖像分類問題。Inception網絡實現了2015年發表的論文《從新思考計算機視覺的初始架構》(Rethinking the Inception Architecture for Computer Vision)。
   在論文中探索了經過適當的分解卷積和積極的正則化,儘量有效地利用增長的算力,而達到相比現有水平更好的實質性收益。 在論文中也描述了一些具備指導意義的網絡設計原則,儘管這些基於大規模試驗的設計原則的實用性是推測的,未來須要更多的實驗數據來評估其準確性和有效性,但經驗證如嚴重偏離這些原則會每每致使網絡質量的降低,而且按照原則執行修復誤差也會使總體架構獲得改善。git

原則一,網絡設計早期不該過分壓縮輸入輸出數據。在設計網絡的時候須要根據特徵圖的各個維度的數據粗略的提取其中的特徵,一般到達網絡層的特徵圖數據的大小從輸入到輸出逐漸減少,但若是早期就過分壓縮數據,就會致使信息的大量丟失。信息內容不只僅經過特徵圖的維度進行評估,也須要相關結構等重要因素。信息丟失將會影響網絡訓練的質量。
原則二,高緯度的特徵圖表示能夠在本地用網絡代替。在卷積神經網絡中逐步增長非線性激活響應能夠得到更多特徵,加快網絡訓練的速度。
原則三,在卷積網絡以前對多通道的低維特徵進行降維,不會下降特徵的信息。 例如,在執行(例如3×3)卷積以前,能夠在空間聚合以前減少輸入表示的維度但並不會產生嚴重的不利影響。基於假設其緣由是相鄰單元之間的強相關性致使在降維期間信息損失小得多。鑑於這些原理,應能夠進行數據的壓縮,尺寸的減少應該能夠促進更快的學習。
原則四,找到最佳的網絡結構,平衡網絡的寬度和深度,使網絡的性能達到最優。平衡每級的濾波器數量和網絡深度,能夠提升網絡的最佳性能。增長網絡的寬度和深度能夠提升網絡質量。若是二者並行增長,能夠達到恆定計算量的最佳優化結果。 所以,計算預算應以平衡的方式分佈在網絡的深度和寬度之間。github

   雖然這些原則可能有意義,但直接應用它們來提升網絡質量並不是易事。Inception網絡也只是在逐步的靠近這些設計原則,模模糊糊中使用它們。
   關於論文部分再也不細述,請參考該論文:Rethinking the Inception Architecture for Computer Vision
   ICLR 2017年的一篇分析論文 An analysis of deep neural network models for practical applications 對實際應用中的重要技術進行了全面分析:精度,內存佔用,參數,操做計數,推理時間和功耗。其中在精度上,Inception網絡得到了最佳表現,固然在其餘維度並無得到全部的最佳表現力。精度評測結果以下:算法

Inception代碼介紹

   Google在開源Tensorflow的同時開源了一個名爲 Models的代碼庫。該代碼庫包含了[TensorFlow](https://www.tensorflow.org)中實現的許多不一樣模型,結構以下:
   - official:使用TensorFlow的高級API的示例模型的集合。旨在經過最新最穩定的TensorFlow API進行開發,通過測試並保持代碼最新。官方推薦新的TensorFlow用戶從這裏開始學習。
   - research:是研究人員在TensorFlow中實施的大量模型集合。它們沒有獲得官方支持,是由個體研究人員來維護模型,但也是最活躍的代碼目錄。
   - samples:包含代碼片斷和較小的模型,用於演示TensorFlow的功能,包括各類博客文章中提供的代碼。
   - tutorials:是TensorFlow教程中描述的模型集合。
   其中,本文介紹的 Inception 代碼庫就是research的一部分,文件結構及說明以下:bash

├── README.md  #很是全面的inception代碼庫的描述
├── WORKSPACE #bazel編譯使用
├── g3doc
│   └── inception_v3_architecture.png #inception_v3網絡體系結構的說明圖示
└── inception
    ├── BUILD
    ├── data #訓練數據的標註和代碼目錄
    │   ├── build_image_data.py #使用protos將圖片數據轉換爲TFRecord文件格式
    │   ├── build_imagenet_data.py #使用protos將ImageNet圖片數據集轉換爲TFRecord文件格式
    │   ├── download_and_preprocess_flowers.sh #下載花朵數據集並將數據集轉化爲TFRecord文件格式
    │   ├── download_and_preprocess_flowers_mac.sh 
    │   ├── download_and_preprocess_imagenet.sh #下載2012ImageNet訓練和評估數據集並將數據集轉化爲TFRecord文件格式
    │   ├── download_imagenet.sh # 下載2012ImageNet訓練和評估數據集
    │   ├── imagenet_2012_validation_synset_labels.txt #訓練數據的標籤與preprocess_imagenet_validation_data.py一塊兒對數據進行處理
    │   ├── imagenet_lsvrc_2015_synsets.txt #訓練數據的標籤
    │   ├── imagenet_metadata.txt #訓練數據的標籤和對應的語義
    │   ├── preprocess_imagenet_validation_data.py #將2012 ImageNet圖片和標籤相關聯
    │   └── process_bounding_boxes.py #將圖片數據和標籤數據相關聯的腳本
    ├── dataset.py # 輕量級的管理訓練數據集合的庫
    ├── flowers_data.py # 使用DataSet管理的花朵訓練數據
    ├── flowers_eval.py # 對花朵分類訓練模型的評估腳本,對inception_eval.py的封裝
    ├── flowers_train.py # 對花朵分類的訓練腳本,對inception_train.py的封裝
    ├── image_processing.py #處理單張圖片的庫,支持多個線程並行和預處理圖片。
    ├── imagenet_data.py # 使用DataSet管理的ImageNet訓練數據
    ├── imagenet_distributed_train.py #支持分佈式系統進行ImageNet訓練的庫,對inception_distributed_train.py的封裝
    ├── imagenet_eval.py # 對ImageNet數據集訓練模型的評估腳本
    ├── imagenet_train.py #對ImageNet數據集的訓練腳本
    ├── inception_distributed_train.py # 支持分佈式系統進行inception的網絡的訓練
    ├── inception_eval.py # inception網絡訓練模型的評估驗證庫
    ├── inception_model.py # 構建inception v3網絡的模型在數據集上
    ├── inception_train.py # inception網絡訓練腳本庫
    └── slim  #Tensorflow中一個輕量級的包含設計,訓練和評估模型的代碼庫,本文不作討論。
複製代碼

本文僅對inception_train.py(此腳本的後續更新已經轉移到slim代碼庫中,參考注意事項)的核心代碼進行分析,其餘文件請參考源代碼。網絡

首先,對inception網絡訓練腳本使用的標誌參數進行說明。

標誌參數以下:
   train_dir: 用來寫入事件日誌和檢查點(checkpoint),即訓練產生的events.out.xxx和model.ckpt-xxxx的文件,默認值'/tmp/imagenet_train’。
   max_steps: 訓練最大的步數,默認值10000000。
   subset: 描述是訓練仍是驗證。默認值是'train' 。架構

   用於管理運行tensorflow使用的硬件
   num_gpus: 管理用於運行tensorflow的硬件,該參數規定使用的GPU數量,默認值爲1。
   log_device_placement: 設置是否記錄設備,默認值是False。app

   用於管理訓練的類型
   fine_tune: 管理訓練類型,若是設置將隨機初始化最後一層權重,以便在新任務上訓練網絡。默認值是False,便可以在預訓練模型上繼續訓練。
   pretrained_model_checkpoint_path: 在一個新的訓練任務開始時指定預訓練模型存放的路徑。curl

   下面是關於學習速率的調整參數,這些參數的調整在很大程度上依賴於硬件架構,批大小以及對模型體系結構規範的更改。選擇一個精細調整的學習率是須要一些實驗的經驗過程的。
   initial_learning_rate: 初始學習速率。默認值是0.1。
   num_epochs_per_decay: 學習速率衰減的調整週期。
   learning_rate_decay_factor: 學習速率調整的參數因子。機器學習

其次,針對腳本中定義的tower_loss方法作一些分析。

函數: _tower_loss
   用於計算訓練模型單個塔上的總損失。在訓練時程序會將批量圖片任務進行拆分,一個批量的圖片拆分到不一樣的塔上。即若是batch_size = 32,num_gpus = 2,那麼每一個塔就會處理16張圖像。
1,使用inception構建網絡推理圖。異步

with tf.variable_scope(tf.get_variable_scope(), reuse=reuse_variables):
    logits = inception.inference(images, num_classes, for_training=True,
                                 restore_logits=restore_logits,
                                 scope=scope)
複製代碼

2,構建推理圖中計算損失的部分。

split_batch_size = images.get_shape().as_list()[0]
inception.loss(logits, labels, batch_size=split_batch_size)
複製代碼

3,僅組裝當前塔中的全部損失。

losses = tf.get_collection(slim.losses.LOSSES_COLLECTION, scope)
複製代碼

其中slim來自inception中slim目錄中的losses.py文件。這個方法獲取網絡的全部損失值。其中,LOSSES_COLLECTION = '_losses'

4,計算當前塔的全部損失。

regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
total_loss = tf.add_n(losses + regularization_losses, name='total_loss')
複製代碼

在損失函數上加上正則項是防止過擬合的一個重要方法,經過獲取tf.GraphKeys.REGULARIZATION_LOSSES集合中的全部變量得到正則化的損失值。

5,調整參數,初始衰減速率爲0.9,計算全部損失的移動平均值和總損失。

loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg')
loss_averages_op = loss_averages.apply(losses + [total_loss])
複製代碼

經過tf.train.ExponentialMovingAverage函數建立移動平均而更新參數,控制模型的更新速度。將全部的loss存儲在一個全局變量(GraphKeys.MOVING_AVERAGE_VARIABLES)中,再經過apply對每個變量進行每一次的迭代移動平均計算。

最後,針對Inception的訓練函數進行一些分析。

函數:train 在數據集上進行訓練。

#建立一個變量global_step來計算train調用的數量。這等於處理的批次數* FLAGS.num_gpus。

global_step = tf.get_variable(
        'global_step', [],
        initializer=tf.constant_initializer(0), trainable=False)
複製代碼

#計算得到學習速率的調整方案。

num_batches_per_epoch = (dataset.num_examples_per_epoch() / FLAGS.batch_size)
decay_steps = int(num_batches_per_epoch * FLAGS.num_epochs_per_decay)
複製代碼

#根據步數以指數方式衰減學習速率。

lr = tf.train.exponential_decay(FLAGS.initial_learning_rate,
                                    global_step,
                                    decay_steps,
                                    FLAGS.learning_rate_decay_factor,
                                    staircase=True)
複製代碼

#使用RMSProp算法建立一個執行梯度降低的優化器。

opt = tf.train.RMSPropOptimizer(lr, RMSPROP_DECAY,
                                    momentum=RMSPROP_MOMENTUM,
                                    epsilon=RMSPROP_EPSILON)
複製代碼

#獲取ImageNet的圖像和標籤,並在GPU之間拆分批處理。

split_batch_size = int(FLAGS.batch_size / FLAGS.num_gpus)
複製代碼

#覆蓋預處理線程的數量,以解決塔數量增長的問題。

num_preprocess_threads = FLAGS.num_preprocess_threads * FLAGS.num_gpus
images, labels = image_processing.distorted_inputs(
        dataset,
        num_preprocess_threads=num_preprocess_threads)
複製代碼

#Dataset標籤集中的類數加1.標籤0保留給(未使用的)後臺類。

num_classes = dataset.num_classes() + 1
複製代碼

#拆分塔的圖像和標籤批次。

images_splits = tf.split(axis=0, num_or_size_splits=FLAGS.num_gpus, value=images)
labels_splits = tf.split(axis=0, num_or_size_splits=FLAGS.num_gpus, value=labels)
複製代碼

#計算每一個模型塔的梯度。
#強制全部變量駐留在CPU上,計算ImageNet模型的一個塔的損失,此函數構造整個ImageNet模型,但在全部塔中共享變量。

with slim.arg_scope([slim.variables.variable], device='/cpu:0'):
	loss = _tower_loss(images_splits[i], labels_splits[i], num_classes,
                           scope, reuse_variables)
複製代碼

#重用下一個塔的變量。

reuse_variables = True
複製代碼

#保留最終塔的摘要。

summaries = tf.get_collection(tf.GraphKeys.SUMMARIES, scope)
複製代碼

#僅保留最終塔的批量標準化更新操做。理想狀況下,咱們應該從全部塔中獲取更新,但這些統計數據累積得很是快,所以咱們能夠忽略其餘塔的統計數據,而不會形成重大損失。

batchnorm_updates = tf.get_collection(slim.ops.UPDATE_OPS_COLLECTION, scope)
複製代碼

#計算此塔上ImageNet批量數據的梯度。

grads = opt.compute_gradients(loss)
複製代碼

#跟蹤全部塔的梯度。

tower_grads.append(grads)
複製代碼

#計算每一個梯度的平均值。請注意,這是全部塔開始同步的地方。

grads = _average_gradients(tower_grads)
複製代碼

#添加摘要以跟蹤學習率。

summaries.append(tf.summary.scalar('learning_rate', lr))
複製代碼

#添加漸變的直方圖。

for grad, var in grads:
      if grad is not None:
        summaries.append(
            tf.summary.histogram(var.op.name + '/gradients', grad))
複製代碼

#應用漸變來調整共享變量。

apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
複製代碼

#爲可訓練變量添加直方圖。

for var in tf.trainable_variables():
      summaries.append(tf.summary.histogram(var.op.name, var))
複製代碼

#跟蹤全部可訓練變量的移動平均值。維護BatchNormalization全局統計信息的「雙倍平均值」。這比須要的更復雜,可是使用它與以前的模型向後兼容。

variable_averages = tf.train.ExponentialMovingAverage(
        inception.MOVING_AVERAGE_DECAY, global_step)
variables_to_average = (tf.trainable_variables() +  tf.moving_average_variables())
variables_averages_op = variable_averages.apply(variables_to_average)
複製代碼

#將全部更新分組到一個訓練中。

batchnorm_updates_op = tf.group(*batchnorm_updates)
train_op = tf.group(apply_gradient_op, variables_averages_op, batchnorm_updates_op)
複製代碼

#建立一個保存器。

saver = tf.train.Saver(tf.global_variables())
複製代碼

#從最後的塔摘要中構建摘要操做。

summary_op = tf.summary.merge(summaries)
複製代碼

#構建一個初始化操做以在下面運行。

init = tf.global_variables_initializer()
複製代碼

#開始在Graph上運行操做。必須將allow_soft_placement設置爲True才能在GPU上構建塔,由於某些操做系統沒有GPU實現。

sess = tf.Session(config=tf.ConfigProto(
        allow_soft_placement=True,
        log_device_placement=FLAGS.log_device_placement))
    sess.run(init)

    if FLAGS.pretrained_model_checkpoint_path:
      …
      variables_to_restore = tf.get_collection(slim.variables.VARIABLES_TO_RESTORE)
      restorer = tf.train.Saver(variables_to_restore)
      restorer.restore(sess, FLAGS.pretrained_model_checkpoint_path)
      …
複製代碼

#啓動隊列運行。

tf.train.start_queue_runners(sess=sess)

    # 建立寫入器
    summary_writer = tf.summary.FileWriter(FLAGS.train_dir, graph=sess.graph)
    for step in range(FLAGS.max_steps):
      …
      # 執行本步的訓練操做
      start_time = time.time()
      _, loss_value = sess.run([train_op, loss])

     …

      # 每100步更新一次摘要信息
      if step % 100 == 0:
        summary_str = sess.run(summary_op)
        summary_writer.add_summary(summary_str, step)

      # 週期的保存checkpoint文件,這裏是5000步執行一次
      if step % 5000 == 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)
複製代碼

理解train方法後便可對網絡進行微整。

實戰驗證

實戰參考Inception的 README 文檔,本文只介紹其中的4個部分: ###如何在新任務上對預訓練模型進行微調

一,入門

   在調用訓練方法前,必須對圖片和標籤數據進行預處理,即將一個新的數據集轉換爲分片的TFRecord格式,每一個條目都是一個序列化的tf.Example proto結構。代碼庫提供了一個腳本,演示如何爲5個標籤上分佈的幾千幅花卉圖像的小數據集作到這一點。

daisy, dandelion, roses, sunflowers, tulips

   代碼庫提供自動腳本(download_and_preprocess_flowers.sh)下載數據集並將其轉換爲TFRecord格式。與ImageNet數據集很是類似,TFRecord格式中的每條記錄都是序列化的tf.Example proto結構,其條目包括JPEG編碼的字符串和整數標籤。有關詳細信息,請參閱parse_example_proto。
   該腳本只需幾分鐘便可運行,具體取決於您的網絡鏈接速度如下載和處理圖像。您的硬盤須要200MB的免費存儲空間(這比完整的500GB+的2012 ImageNet數據集少太多了)。在這裏咱們選擇DATA_DIR = / tmp / flowers-data /做爲這樣一個位置,但隨意編輯。

# 設置flower數據存儲位置 
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 構建預處理腳本
cd tensorflow-models/inception
bazel  
build //inception:download_and_preprocess_flowers

# 運行腳本下載並處理數據 
bazel-bin/inception/download_and_preprocess_flowers "${FLOWERS_DATA_DIR}"
複製代碼

若是腳本成功運行,終端輸出的最後一行應以下所示:

2016-02-24 20:42:25.067551: Finished writing all 3170 images in data set.
複製代碼

   當腳本結束時,將在DATA_DIR中找到2個用於訓練和驗證文件的分片。這些文件相似train-?????-of-00002和validation-?????-of-00002,分別表明訓練數據集和驗證數據集。
注意:
   若是準備自定義圖像數據集,則須要在自定義數據集上調用build_image_data.py。

另外,能夠選擇下載代碼庫提供的預訓練模型

# 指定下載模型要存儲的路徑
INCEPTION_MODEL_DIR=$HOME/inception-v3-model
  
mkdir -p ${INCEPTION_MODEL_DIR}

cd ${INCEPTION_MODEL_DIR}

# 經過curl命令下載模型壓縮包
curl -O http://download.tensorflow.org/models/image/imagenet/inception-v3-2016-03-01.tar.gz
tar xzf inception-v3-2016-03-01.tar.gz

# 將會在目錄中建立一個名爲inception-v3的目錄,幷包含下面的文件
> ls inception-v3

README.txt

checkpoint

model.ckpt-157585
複製代碼

如今可使用花朵數據集對預先訓練好的Inception v3模型進行微調。

二,如何在花卉數據上從新訓練模型

準備在花朵數據集上微調預先訓練好的Inception-v3模型,須要修改訓練腳本的2個參數:
   - pretrained_model_checkpoint_path: 指向預先訓練的Inception-v3模型的路徑。若是指定了此標誌,它將在腳本開始訓練以前從檢查點加載整個模型。
   - fine_tune: 一個布爾值,指示最後一個分類層是應該隨機初始化仍是恢復。若是您但願從檢查點繼續訓練預先訓練好的模型,則能夠將此標誌設置爲false。若是將此標誌設置爲true,則能夠從頭開始培訓新的分類層。

綜合起來,可使用如下命令從新訓練花卉數據集上的預先訓練的Inception-v3模型。

# 經過bazel構建flowers_train網絡,該網絡在源碼上封裝了對inception_train的調用。
cd tensorflow-models/inception

bazel build //inception:flowers_train

# 設置下載好的預訓練的模型路徑.

MODEL_PATH="${INCEPTION_MODEL_DIR}/inception-v3/model.ckpt-157585"

# 設置數據保存的路徑,該數據已是TFRecord文件格式
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 設置保存訓練中輸出的事件日誌和檢查點數據
TRAIN_DIR=/tmp/flowers_train/

# 經過flowers_train網絡開始使用預訓練的模型從新訓練花朵數據,fine_tune設置爲True。
bazel-bin/inception/flowers_train --train_dir="${TRAIN_DIR}" 
--data_dir="${FLOWERS_DATA_DIR}" 
--pretrained_model_checkpoint_path="${MODEL_PATH}" 
--fine_tune=True 
--initial_learning_rate=0.001 
--input_queue_memory_factor=1
複製代碼

在培訓過程當中增長了一些額外選項。

  • 將模型微調爲單獨的數據集要求顯着下降初始學習速率。咱們將初始學習率設置爲0.001。
  • 鮮花數據集很是小,因此咱們縮小了示例的隊列的大小。有關更多詳細信息,請參閱調整內存需求。

訓練腳本只會報告損失。要評估微調模型的質量,您須要運行驗證腳本flowers_eval:

# 開始構建flowers_eval模型
cd tensorflow-models/inception

bazel build //inception:flowers_eval

# 設置訓練中輸出的事件日誌和檢查點的目錄
TRAIN_DIR=/tmp/flowers_train/

# 設置訓練數據集所在目錄,該數據集是TFRecord文件格式
FLOWERS_DATA_DIR=/tmp/flowers-data/

# 設定保存驗證結果日誌文件的目錄
EVAL_DIR=/tmp/flowers_eval/

# 經過flowers_eval開始驗證flowers_train訓練的結果
bazel-bin/inception/flowers_eval 
--eval_dir="${EVAL_DIR}" 
--data_dir="${FLOWERS_DATA_DIR}" 
--subset=validation 
--num_examples=500 
--checkpoint_dir="${TRAIN_DIR}" 
--input_queue_memory_factor=1 
--run_once
複製代碼

訓練中發如今模型運行2000步後,評估的精確度達到大約93.4%。

Successfully loaded model from /tmp/flowers/model.ckpt-1999 at step=1999.
2016-03-01 16:52:51.761219: starting evaluation on (validation).
2016-03-01 16:53:05.450419: [20 batches out of 20] (36.5 examples/sec; 0.684sec/batch)
2016-03-01 16:53:05.450471: precision @ 1 = 0.9340 recall @ 5 = 0.9960 [500 examples]
複製代碼

三,如何構建一個新的數據集進行再訓練

   使用該模型提供的現有腳原本構建用於訓練或微調的新數據集。主要腳本是build_image_data.py。 簡而言之,這個腳本須要一個結構化的圖像目錄,並將其轉換爲可由Inception模型讀取的分片TFRecord。 具體來講,您須要建立一個指定結構的訓練圖像目錄,這些圖像位於TRAIN_DIR和 VALIDATION_DIR中,其排列方式以下:

$TRAIN_DIR/dog/image0.jpeg

$TRAIN_DIR/dog/image1.jpg

$TRAIN_DIR/dog/image2.png

...

$TRAIN_DIR/cat/weird-image.jpeg

$TRAIN_DIR/cat/my-image.jpeg

$TRAIN_DIR/cat/my-image.JPG

...

$VALIDATION_DIR/dog/imageA.jpeg

$VALIDATION_DIR/dog/imageB.jpg

$VALIDATION_DIR/dog/imageC.png

...

$VALIDATION_DIR/cat/weird-image.PNG

$VALIDATION_DIR/cat/that-image.jpg

$VALIDATION_DIR/cat/cat.JPG
...
複製代碼

注意:該腳本將附加一個索引爲0的額外背景類,所以您的類標籤範圍從0到num_labels。使用上面的例子,從build_image_data.py生成的相應類標籤以下所示:

0
  
1 dog
 
2 cat
複製代碼

TRAIN_DIR和VALIDATION_DIR中的每一個子目錄對應於駐留在該子目錄內的圖像的惟一標籤,圖像多是JPEG或PNG圖像,目前不支持其餘圖像類型。 數據安排在這個目錄結構中,能夠在數據上運行build_image_data.py來生成分片的TFRecord數據集。 build_image_data.py的註釋中描述了tf.Example中包含的完整信息列表。 要運行build_image_data.py,能夠運行如下命令行:

# 設置生成TFRecord文件的目錄
OUTPUT_DIRECTORY=$HOME/my-custom-data/

# 構建腳本build_image_data
cd tensorflow-models/inception
bazel 
build //inception:build_image_data

# 運行腳本進行轉化
bazel-bin/inception/build_image_data 
--train_directory="${TRAIN_DIR}" 
--validation_directory="${VALIDATION_DIR}" 
--output_directory="${OUTPUT_DIRECTORY}" 
--labels_file="${LABELS_FILE}" 
--train_shards=128 
--validation_shards=24 
--num_threads=8
複製代碼

OUTPUT_DIRECTORY是分片TFRecords的位置。
LABELS_FILE將是一個由腳本讀取的文本文件,該文件提供了全部標籤的列表。例如,在鮮花數據集的狀況下, LABELS_FILE包含如下數據:
daisy

dandelion

roses

sunflowers

tulips
請注意,每一個標籤的每一行都與模型中最終分類器中的條目相對應。也就是說,雛菊對應於條目1的分類器;蒲公英是條目2等。咱們跳過標籤0做爲背景類。 運行此腳本後,將生成以下所示的文件:

$TRAIN_DIR/train-00000-of-00128

$TRAIN_DIR/train-00001-of-00128

...

$TRAIN_DIR/train-00127-of-00128
and
$VALIDATION_DIR/validation-00000-of-00024

$VALIDATION_DIR/validation-00001-of-00024

...

$VALIDATION_DIR/validation-00023-of-00024
複製代碼

其中128和24分別是爲每一個數據集指定的分片數。目標是選擇碎片的數量,使每一個碎片大約有1024個圖像。一旦創建了這個數據集,就能夠在這個數據集上訓練或微調一個Inception模型。 另外,若是您使用訓練腳本,請修改flowers_data.py中的num_classes()和num_examples_per_epoch()以與新建的數據對應。

四,訓練模型的實際考慮因素

   模型架構和訓練過程嚴重依賴於用來訓練模型的硬件。若是你想在你的機器上訓練或微調這個模型,你須要調整和經驗地肯定一套適合你的設置的訓練超參數。

1)尋找好的超參數

大約5-10個超參數控制網絡訓練的速度。除了--batch_size和–num_gpus以外,在inception_train.py中定義了幾個常量,它們規定了學習任務。

RMSPROP_DECAY = 0.9 # RMSProp算法的衰減項.

MOMENTUM = 0.9 # RMSProp算法的Momentum值.

RMSPROP_EPSILON = 1.0 # RMSProp算法的Epsilon項.

INITIAL_LEARNING_RATE = 0.1 # 學習速錄初始化時的值.

NUM_EPOCHS_PER_DECAY = 30.0 # 學習速率開始衰減的時期Epochs.

LEARNING_RATE_DECAY_FACTOR = 0.16 # 學習速率衰減因子.
複製代碼

在訓練中下面參數的調整對結果有較大的影響。

  • INITIAL_LEARNING_RATE:較高的學習率能夠加快訓練速度。但速率過高會致使不穩定,使模型參數發散到無窮大或NaN。
  • batch_size:較大的批量大小能夠提升梯度的質量估算,並可對較高學習率的模型進行訓練。
  • num_gpus:一般GPU內存是阻止採用更大批量的瓶頸,使用更多的GPU容許使用更大的批量。
2)調整內存需求

   訓練這個模型在CPU和GPU方面有很大的內存需求,與CPU內存相比,GPU內存相對較小。兩個項目決定了GPU內存使用量——模型架構和批量大小(batch_size)。假設您保持模型架構不變,訓練對GPU需求的惟一控制參數就是批量大小。

「一個很好的經驗法則是嘗試使用盡量大的批量大小以適應GPU。」

   若是用完GPU內存,請下降--batch_size或在工做機上使用更多GPU。該模型在GPU之間執行批量分割,所以N個GPU能夠處理N倍於1個GPU的批量。 該模型也須要大量的CPU內存。Inception調整了這個模型來使用大約20GB的CPU內存。所以,得到大約40GB的CPU內存將是理想的。
   若是這不可行,能夠經過下降——input_queue_memory_factor來調低模型的內存需求。相對於跨–num_preprocess_threads線程的主要訓練對圖像進行異步預處理。
   預處理的圖像存儲在隊列中,其中每一個GPU執行出隊操做以接收批量圖像。 爲了保證數據的良好序列,咱們維護一個1024 x input_queue_memory_factor圖像的大型隊列。對於當前的模型架構,這至關於大約4GB的CPU內存。 能夠經過下降input_queue_memory_factor以減小內存佔用量。但大幅下降此值可能會致使模型在從頭開始訓練時預測精度略低。
   有關更多詳細信息,請參閱image_processing.py中的註釋。

經過上面的學習和實戰驗證,IT男使用訓練好的模型終於能夠大機率的識別出什麼事玫瑰。

引用及注意事項

引用:
1.Inception
2.Rethinking the Inception Architecture for Computer Vision
3.An analysis of deep neural network models for practical applications
4.ImageNet 是機器學習中用於訓練圖像識別系統的經常使用學術數據集。
5.Inception的模型架構圖以下:

6.RMSProp算法是一種梯度降低法,全稱是Root Mean Square Prop。 7.tower: 這個概念在tensorflow中並無明確的定義,個人理解tower是tensorflow神經網絡模型的一部分,是在梯度漸變計算中抽象出來可獨立計算的函數。能夠在單GPU上進行計算,也支持在多GPUs上進行獨立計算。

注意:
   對於Research中開源的Inception代碼庫,谷歌的開發者們將大部分的後續改進工做轉移到了 slim 代碼庫中。便可以在 slim 中找到此代碼庫的最新版本,持續學習能夠參考。

PS. 本人做爲機器學習的新鳥一隻,在學習過程當中對不少概念和算法都不明覺厲,若有錯誤請批評指正。

掃描二維碼,關注公衆號。 得到最新的移動開發技術乾貨。

相關文章
相關標籤/搜索