画像特徴空間の可視化 [TensorFlowでDeep Learning 19]

([目次はこちら](http://qiita.com/kumonkumon/items/6fd05963df92e9eec8c0))

# はじめに

Deep Learningそのものではないですが、特徴空間とか埋め込み表現とかEmbeddingとか言われるものを、TensorBoardで可視化します。
何かの資料などに使うと画像認識やってる感が出ます。

本家のこちらの実現方法とは異なり、checkpointも出力しません。
[TensorBoard: Embedding Visualization](https://www.tensorflow.org/versions/r1.1/get_started/embedding_viz)

# 作るもの
動画用意したんで見てみてください。

[![youtube.png](https://qiita-image-store.s3.amazonaws.com/0/127038/76bf5f05-1309-7ffe-0504-73ab3856a69c.png)](https://www.youtube.com/watch?v=d3qnu1n3wHs)

# 必要なもの

- 画像
- スプライト画像
- 画像特徴抽出器 / 画像特徴ベクトル
- 設定ファイル
- TensorFlow/TensorBoard
    - tensorflow==1.8.0, tensorflow-hub==0.1.0 を使っています
    - 普通のPCで大丈夫 (特徴抽出にちょっと時間かかるが)

## 画像
Google画像検索で動物の画像を2500枚集めました。
画像は、`images/img_0001.jpg 〜 images/img_2500.jpg` の2500枚とします。

## スプライト画像

ImageMagick使うと一撃です。

```sh
$ montage images/img_*.jpg -tile 50x50 -geometry 50x50! sprite.jpg
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/127038/190af16b-0c66-4c45-34ec-915ec2946e0e.jpeg" width=70%>


## 画像特徴抽出器 / 画像特徴ベクトル


```python:feture_extraction.py
import csv
import tensorflow as tf
import tensorflow_hub as hub

module = hub.Module("https://tfhub.dev/google/imagenet/mobilenet_v2_140_224/feature_vector/2")
height, width = hub.get_expected_image_size(module)
ch = 3
batch_size = 10

image_list = tf.convert_to_tensor(['images/img_{:04d}.jpg'.format(i+1) for i in range(2500)])
input_queue = tf.train.slice_input_producer([image_list], num_epochs=1, shuffle=False)

image_bytes = tf.read_file(input_queue[0])
image = tf.image.decode_image(image_bytes, channels=ch)
image = tf.image.resize_bilinear([image], [height, width])
image = tf.reshape(image, tf.stack([height, width, ch]))
images = tf.train.batch([image], batch_size=batch_size, allow_smaller_final_batch=True)
features = module(images)

with open('feature_vecs.tsv', 'w') as fw:
    csv_writer = csv.writer(fw, delimiter='\t')
    with tf.Session() as sess:
        sess.run([tf.local_variables_initializer(),
                  tf.global_variables_initializer()])
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)

        try:
            while not coord.should_stop():
                fvecs = sess.run(features)
                csv_writer.writerows(fvecs)
        except:
            pass
        finally:
            coord.request_stop()
            coord.join(threads)
```

もっとシンプルにこんな感じでもいいかと思います。

```python:simple_feature_extraction.py
import csv
import tensorflow as tf
import tensorflow_hub as hub

module = hub.Module("https://tfhub.dev/google/imagenet/mobilenet_v2_140_224/feature_vector/2")
height, width = hub.get_expected_image_size(module)
ch = 3

filename = tf.placeholder(tf.string)
image_bytes = tf.read_file(filename)
image = tf.image.decode_image(image_bytes, channels=ch)
image = tf.image.resize_bilinear([image], [height, width])
features = module(image)

with open('feature_vecs.tsv', 'w') as fw:
    csv_writer = csv.writer(fw, delimiter='\t')
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())

        for image_path in ['images/img_{:04d}.jpg'.format(i+1) for i in range(2500)]:
            fvecs = sess.run(features, feed_dict={filename: image_path})
            csv_writer.writerows(fvecs)
```

Mobilenet V2を使ってますが、InceptionでもResnetでもなんでもいいと思います。
[TensorFlow Hub: Image Modules](https://www.tensorflow.org/hub/modules/image)

これで特徴ベクトルのTSVファイル(`feature_vecs.tsv`)が得られます。

## 設定ファイル

```txt:projector_config.pbtxt
embeddings {
  tensor_path: "feature_vecs.tsv"
  sprite {
    image_path: "sprite.jpg"
    single_image_dim: 50
    single_image_dim: 50
  }
}
```

## TensorBoard起動

`projector_config.pbtxt`のディレクトリで、

```sh
$ tensorboard --logdir .
```

それから、http://localhost:6006/#projector にアクセス。

<img src="https://qiita-image-store.s3.amazonaws.com/0/127038/03d2de69-97fc-730e-c893-4726dfc23d02.png" width=80%>

めでたしめでたし。(もし表示されなかったら、リーロードしてみてください。)
t-SNEも実装されているので、お試しあれ。