TensorFlow r1.4 で画像認識の転移学習

TensorFlowが1.4にアップデートされていたので、花の転移学習チュートリアルやり直してみた。
チュートリアル:[How to Retrain Inception's Final Layer for New Categories](https://www.tensorflow.org/tutorials/image_retraining)

#1.インストール
必要なものをインストールします。

- virtualenv (仮想環境が必要であれば)
    - `pip install --upgrade virtualenv`
    - `virtualenv --system-site-packages -p python3 仮想環境名`
    - 仮想環境に入るvirtualenvのコマンド `source 仮想環境名/bin/activate`
- python 3.6.2
    - `pip3 install --upgrade tensorflow`
    - バージョン確認 `python --version`
- tensorflow 1.4 
    - `pip3 install --upgrade tensorflow`
- matplotlib
    - `pip3 install matplotlib`
- [github - tensorflow/tensorflow](https://github.com/tensorflow/tensorflow)
    - `git clone https://github.com/tensorflow/tensorflow.git`


#2.label_image.py を追加する
\#1でcloneしたgithubのディレクトリから、さらにimage_retrainingというディレクトリに移動する。

```:ターミナル
$ cd tensorflow/tensorflow/examples/image_retraining
```
ここで、見当たらないlabe_image.pyを追加する。

```label_image.py

"""Simple image classification with Inception.

Run image classification with your model.

This script is usually used with retrain.py found in this same
directory.

This program creates a graph from a saved GraphDef protocol buffer,
and runs inference on an input JPEG image. You are required
to pass in the graph file and the txt file.

It outputs human readable strings of the top 5 predictions along with
their probabilities.

Change the --image_file argument to any jpg image to compute a
classification of that image.

Example usage:
python label_image.py --graph=retrained_graph.pb
  --labels=retrained_labels.txt
  --image=flower_photos/daisy/54377391_15648e8d18.jpg

NOTE: To learn to use this file and retrain.py, please see:

https://codelabs.developers.google.com/codelabs/tensorflow-for-poets
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

import tensorflow as tf

parser = argparse.ArgumentParser()
parser.add_argument(
    '--image', required=True, type=str, help='Absolute path to image file.')
parser.add_argument(
    '--num_top_predictions',
    type=int,
    default=5,
    help='Display this many predictions.')
parser.add_argument(
    '--graph',
    required=True,
    type=str,
    help='Absolute path to graph file (.pb)')
parser.add_argument(
    '--labels',
    required=True,
    type=str,
    help='Absolute path to labels file (.txt)')
parser.add_argument(
    '--output_layer',
    type=str,
    default='final_result:0',
    help='Name of the result operation')
parser.add_argument(
    '--input_layer',
    type=str,
    default='DecodeJpeg/contents:0',
    help='Name of the input operation')


def load_image(filename):
  """Read in the image_data to be classified."""
  return tf.gfile.FastGFile(filename, 'rb').read()


def load_labels(filename):
  """Read in labels, one label per line."""
  return [line.rstrip() for line in tf.gfile.GFile(filename)]


def load_graph(filename):
  """Unpersists graph from file as default graph."""
  with tf.gfile.FastGFile(filename, 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    tf.import_graph_def(graph_def, name='')


def run_graph(image_data, labels, input_layer_name, output_layer_name,
              num_top_predictions):
  with tf.Session() as sess:
    # Feed the image_data as input to the graph.
    #   predictions will contain a two-dimensional array, where one
    #   dimension represents the input image count, and the other has
    #   predictions per class
    softmax_tensor = sess.graph.get_tensor_by_name(output_layer_name)
    predictions, = sess.run(softmax_tensor, {input_layer_name: image_data})

    # Sort to show labels in order of confidence
    top_k = predictions.argsort()[-num_top_predictions:][::-1]
    for node_id in top_k:
      human_string = labels[node_id]
      score = predictions[node_id]
      print('%s (score = %.5f)' % (human_string, score))

    return 0


def main(argv):
  """Runs inference on an image."""
  if argv[1:]:
    raise ValueError('Unused Command Line Args: %s' % argv[1:])

  if not tf.gfile.Exists(FLAGS.image):
    tf.logging.fatal('image file does not exist %s', FLAGS.image)

  if not tf.gfile.Exists(FLAGS.labels):
    tf.logging.fatal('labels file does not exist %s', FLAGS.labels)

  if not tf.gfile.Exists(FLAGS.graph):
    tf.logging.fatal('graph file does not exist %s', FLAGS.graph)

  # load image
  image_data = load_image(FLAGS.image)

  # load labels
  labels = load_labels(FLAGS.labels)

  # load graph, which is stored in the default session
  load_graph(FLAGS.graph)

  run_graph(image_data, labels, FLAGS.input_layer, FLAGS.output_layer,
            FLAGS.num_top_predictions)


if __name__ == '__main__':
  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=sys.argv[:1]+unparsed)

```
label_image.pyという名前で保存し、image_retraining直下に置く。


#3.花のサンプルをDLする

画像群をDLする。
`$ curl -O http://download.tensorflow.org/example_images/flower_photos.tgz`


#4.再学習モデルを作る

再学習にはretrain.pyを用いる。
ターミナルに以下の内容を打つ。

```:再学習
python retrain.py \
  --bottleneck_dir=bottlenecks \
  --how_many_training_steps=500 \
  --model_dir=inception \
  --summaries_dir=training_summaries/basic \
  --output_graph=retrained_graph.pb \
  --output_labels=retrained_labels.txt \
  --image_dir=flower_photos
```

なお、
  --how_many_training_steps=(回数変更OK） \
  --output_graph=(任意名称OK).pb \　
  --output_labels=(任意名称OK).txt \
  --image_dir=(#3でDLした画像群)


#5.モデルを実行する
\#4で作成したモデルを用いて、label_image.pyを実行すると、
新たに学習したデータでの画像認識を確認できる。

新たに認識させたい画像を、label_image.pyがある階層に入れて置く。
ここではimgtest.jpg という画像を置いた。

```:ターミナル
$ python label_image.py --image imgtest.jpg --graph retrained_graph.pb --labels retrained_labels.txt 
```

なお、
--graph (#4で指定した名称).pb
--labels (#4で指定した名称).txt
にすること。


#6.Error: No module と出る時
対処法はこちら。
[TensorFlow r1.4 で Error: No module named 'tensorflow.contrib.quantize' となる時の対処法](https://qiita.com/ume1126/items/b46c3632f3437e40fd13)


#7.virtualenvを削除
テストを終えて仮想環境を削除したい時は
`deactivate`で無効化してから、ごっそり削除でOK。
参考：[virtualenv 基本的なコマンド使い方メモ](https://qiita.com/th1209/items/84f21a4499548b34ec91#%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96%E5%89%8A%E9%99%A4)