TensorFlowチュートリアル

提供: ディーズガレージ wiki
移動先: 案内検索

テスト環境

Windows10のVirtualBoxでUbuntu16.04/64-bit

$ sudo apt-get install python-numpy python-dev python-pip python-wheel
$ sudo apt-get install python3-numpy python3-dev python3-pip python3-wheel
$ sudo apt-get install python-virtualenv python3-tk git openjdk-8-jdk
$ echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
$ curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
$ sudo apt-get update && sudo apt-get install bazel

TensorFlowはvirtualenv版でCPUサポート版
ほぼ全ての学習データがtmpディレクトリに作成されるので注意。再起動すると消える。
貼り付けてるソースは作成時(r1.4)のもの。

Install >

Installing TensorFlow on Ubuntu

UbuntuにTensorFlowをインストールする

$ virtualenv --system-site-packages -p python3 test
$ source ~/test/bin/activate
(test)$ pip3 install --upgrade tensorflow
(test)$ python
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
# b'Hello, TensorFlow!'
# Ctrl+D
(test)$ deactivate
$ rm -r test

Develop > Get Started >

Getting Started With TensorFlow

TensorFlow入門
tf.train API

$ virtualenv --system-site-packages -p python3 started_01
$ source ~/started_01/bin/activate
(started_01)$ pip3 install --upgrade tensorflow
(started_01)$ gedit started_01.py
# コピーペースト
(started_01)$ python started_01.py
# W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
(started_01)$ tensorboard --logdir /tmp/started_01
# ブラウザ http://localhost:6006
# CTRL+C
(started_01)$ deactivate
$ rm -r \
    started_01 \
    started_01.py \
    /tmp/started_01
Tensorboard-started 01.png

started_01.py

import tensorflow as tf

# モデルパラメータ
W = tf.Variable([0.3], dtype=tf.float32, name='W')
b = tf.Variable([-0.3], dtype=tf.float32, name='b')
tf.summary.histogram('W', W)
tf.summary.histogram('b', b)

# モデルの入力と出力
x = tf.placeholder(tf.float32, name='x')
linear_model = W * x + b
y = tf.placeholder(tf.float32, name='y')

# ロス
with tf.name_scope('loss'):
    loss = tf.reduce_sum(tf.square(linear_model - y))
tf.summary.scalar('loss', loss)

# オプティマイザ
with tf.name_scope('optimizer'):
    optimizer = tf.train.GradientDescentOptimizer(0.01)
    train = optimizer.minimize(loss)

# 訓練データ
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]

sess = tf.Session()

# 初期化
sess.run(tf.global_variables_initializer())

merged = tf.summary.merge_all()
writer = tf.summary.FileWriter("/tmp/started_01", sess.graph)

# 訓練
for i in range(1000):
    summary, _ = sess.run([merged, train], {x: x_train, y: y_train})
    writer.add_summary(summary, i)
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s" % (curr_W, curr_b, curr_loss))

tf.Variable tf.float32 tf.placeholder tf.reduce_sum tf.square tf.train.GradientDescentOptimizer tf.Session tf.global_variables_initializer

tf.estimator Basic usage

$ virtualenv --system-site-packages -p python3 started_02
$ source ~/started_02/bin/activate
(started_02)$ pip3 install --upgrade tensorflow
(started_02)$ gedit started_02.py
# コピーペースト
(started_02)$ python started_02.py
# train metrics: {'global_step': 1000, 'loss': 6.9579499e-07, 'average_loss': 1.7394875e-07}
# eval metrics: {'global_step': 1000, 'loss': 0.010243418, 'average_loss': 0.0025608544}
(started_02)$ tensorboard --logdir /tmp/started_02
# ブラウザ http://localhost:6006
# CTRL+C
(started_02)$ deactivate
$ rm -r \
    started_02 \
    started_02.py \
    /tmp/started_02
Tensorboard-started 02.png

started_02.py

# NumPyはデータを読み込み、操作、前処理するためによく使われます。
import tensorflow as tf
import numpy as np

# 機能のリストを宣言する。
# 今は1つの数値機能しかありません。
# より複雑で有用な他の多くのタイプの列があります。
feature_cols = [tf.feature_column.numeric_column("x", shape=[1])]

# 推定器(estimator)は訓練(フィッティング)と評価(推定)を呼び出すためのフロントエンドです。
# 線形回帰、線形分類、多くのニューラルネットワーク分類器および回帰子のような多くの事前定義型があります。
# 次のコードは、線形回帰を行う推定器を提供します。
estimator = tf.estimator.LinearRegressor(
    feature_columns=feature_cols, model_dir='/tmp/started_02')

# TensorFlowには、データセットを読み込んで設定するための多くのヘルパーメソッドが用意されています。
# ここでは、トレーニング用と評価用の2つのデータセットを使用します。
# 必要なデータのバッチ(num_epochs)数と各バッチの大きさを関数に伝えなければなりません。
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])

input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True
)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False
)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False
)

# このメソッドを呼び出してトレーニングデータセットを渡すことで、1000のトレーニングステップを呼び出すことができます
estimator.train(input_fn=input_fn, steps=1000)

# 評価
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r" % train_metrics)
print("eval metrics: %r" % eval_metrics)

tf.feature_column tf.feature_column.numeric_column tf.estimator.LinearRegressor tf.estimator.inputs.numpy_input_fn tf.estimator.Estimator

tf.estimator A custom model

$ virtualenv --system-site-packages -p python3 started_03
$ source ~/started_03/bin/activate
(started_03)$ pip3 install --upgrade tensorflow
(started_03)$ gedit started_03.py
# コピーペースト
(started_03)$ python started_03.py
# train metrics: {'global_step': 1000, 'loss': 1.036556e-10}
# eval metrics: {'global_step': 1000, 'loss': 0.010100458}
(started_03)$ tensorboard --logdir /tmp/started_03
# ブラウザ http://localhost:6006
# CTRL+C
(started_03)$ deactivate
$ rm -r \
    started_03 \
    started_03.py \
    /tmp/started_03
Tensorboard-started 03.png

started_03.py

import numpy as np
import tensorflow as tf

# 特徴のリストを宣言します。今はひとつの実数の特徴しか使いません。


def model_fn(features, labels, mode):
    # 線形モデル
    W = tf.get_variable('W', [1], dtype=tf.float64)
    b = tf.get_variable('b', [1], dtype=tf.float64)
    tf.summary.histogram('W', W)
    tf.summary.histogram('b', b)
    y = W * features['x'] + b

    # ロス
    with tf.name_scope('loss'):
        loss = tf.reduce_sum(tf.square(y - labels))
        tf.summary.scalar('loss', loss)

    # 訓練
    with tf.name_scope('optimizer'):
        global_step = tf.train.get_global_step()
        optimizer = tf.train.GradientDescentOptimizer(0.01)
        train = tf.group(optimizer.minimize(loss),
                         tf.assign_add(global_step, 1))

    # EstimatorSpecは適切な機能性(funcrionality)のために今まで作ったサブグラフを結合します。
    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=y,
        loss=loss,
        train_op=train)


merged = tf.summary.merge_all()
estimator = tf.estimator.Estimator(
    model_fn=model_fn, model_dir='/tmp/started_03')

# データセット
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7., 0.])

input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True
)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False
)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False
)

# 訓練
estimator.train(input_fn=input_fn, steps=1000)

# 評価
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r" % train_metrics)
print("eval metrics: %r" % eval_metrics)

tf.get_variable tf.float64 tf.reduce_sum tf.square tf.train.get_global_step tf.train.GradientDescentOptimizer tf.group tf.assign_add tf.estimator.EstimatorSpec tf.estimator.inputs.numpy_input_fn tf.estimator.Estimator

MNIST For ML Beginners

ML初心者のためのMNIST
Mnist 0-9.png

$ virtualenv --system-site-packages -p python3 beginners
$ source ~/beginners/bin/activate
(beginners)$ pip3 install --upgrade tensorflow
(beginners)$ pip3 install matplotlib
# (beginners)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/mnist_softmax.py
(beginners)$ gedit mnist_softmax.py
# コピーペースト
(beginners)$ python mnist_softmax.py
# Figure 1閉じる
(pros)$ tensorboard --logdir /tmp/beginners
# ブラウザ http://localhost:6006
# CTRL+C
(beginners)$ deactivate
$ rm -r \
    beginners \
    mnist_softmax.py \
    /tmp/tensorflow \
    /tmp/beginners
Tensorboard-beginners.png

mnist_softmax.py

"""非常に単純なMNIST分類器

ドキュメントを参照
https://www.tensorflow.org/get_started/mnist/beginners
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys
from matplotlib import pyplot as plt
from matplotlib import cm

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

FLAGS = None


def main(_):
    # データの読み込み
    mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

    # 画像入力
    x = tf.placeholder(tf.float32, [None, 784], name='x')
    # 重み
    W = tf.Variable(tf.zeros([784, 10]), name='W')
    # バイアス
    b = tf.Variable(tf.zeros([10]), name='b')
    # 内積計算とバイアス加算
    y = tf.matmul(x, W) + b
    # 正解ラベル
    y_ = tf.placeholder(tf.float32, [None, 10], name='y_')

    # クロスエントロピー
    with tf.name_scope('loss'):
        cross_entropy = tf.reduce_mean(
            tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
        cross_entropy_summary = tf.summary.scalar(
            "cross_entropy", cross_entropy)

    # オプティマイザ
    with tf.name_scope('optimizer'):
        train_step = tf.train.GradientDescentOptimizer(
            0.5).minimize(cross_entropy)

    with tf.name_scope("accuracy") as scope:
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        accuracy_summary = tf.summary.scalar("accuracy", accuracy)

    sess = tf.InteractiveSession()

    # 初期化
    sess.run(tf.global_variables_initializer())

    # TensorBoard
    tf.summary.histogram('W', W)
    tf.summary.histogram('b', b)
    tf.summary.histogram('y', y)
    with tf.name_scope('input_reshape'):
        image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
        tf.summary.image('input', image_shaped_input, 10)
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter('/tmp/beginners', sess.graph)

    # 訓練
    for i in range(1000):
        # ランダムに100個のデータポイント(一回分)
        batch_xs, batch_ys = mnist.train.next_batch(100)
        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

        if i % 10 == 0:
            # すべてのsummaryを記録
            summary_str = sess.run(
                merged, feed_dict={x: batch_xs, y_: batch_ys})
            writer.add_summary(summary_str, i)

    # 正答率
    # http://www.mwsoft.jp/programming/tensor/tutorial_beginners.html
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    corrects = sess.run(correct_prediction, feed_dict={
        x: mnist.test.images, y_: mnist.test.labels})
    for i in range(10):
        positive = sum(mnist.test.labels[corrects][:, i] == 1)
        all = sum(mnist.test.labels[:, i] == 1)
        print(i, positive / all)

    # 可視化
    # http://da-yasu.com/?p=3858
    X = mnist.test.images
    y = mnist.test.labels

    for i in range(20):
        plt.subplot(5, 5, i + 1)
        plt.imshow(X[i].reshape(28, 28))
        plt.axis("off")
        for index, j in enumerate(y[i]):
            if j == 1:
                plt.title(index, fontsize=20, color="yellow")
    plt.show()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--data_dir', type=str, default='/tmp/tensorflow/mnist/input_data',
                        help='Directory for storing input data')
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.nn.softmax tf.nn.softmax_cross_entropy_with_logits tf.train.GradientDescentOptimizer tf.InteractiveSession tf.global_variables_initializer tf.equal tf.argmax tf.reduce_mean tf.cast tf.app.run

Deep MNIST for Experts

専門家向けの深いMNIST
Mnist 0-9.png

$ virtualenv --system-site-packages -p python3 pros
$ source ~/pros/bin/activate
(pros)$ pip3 install --upgrade tensorflow
# (pros)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/mnist_deep.py
(pros)$ gedit mnist_deep.py
# コピーペースト
(pros)$ python mnist_deep.py
# test accuracy 0.9912
(pros)$ tensorboard --logdir /tmp/pros
# ブラウザ http://localhost:6006
# CTRL+C
(pros)$ deactivate
$ rm -r \
    pros \
    mnist_deep.py \
    /tmp/tensorflow \
    /tmp/pros
Tensorboard-pros.png

mnist_deep.py

"""畳み込みレイヤを用いた深いMNIST分類器

ドキュメントを参照
https://www.tensorflow.org/get_started/mnist/pros
"""
# チュートリアルとの一貫性を保つためpylintの警告を無効にする
# pylint: disable=invalid-name
# pylint: disable=g-bad-import-order

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

FLAGS = None


def deepnn(x):
    """deepnnは数字を分類するためのディープネットのグラフを作成します。

    Args:
      x: 寸法(N_examples、784)を持つ入力テンソル。この784は標準的なMNIST画像のピクセル数。

    Returns:
      タプル(y、keep_prob)です。
      yはテンソル形状(N_examples、10)であり、桁を10クラス(数字0〜9)のいずれかに分類するためのロジットに等しい値を持つ。
      keep_probは、ドロップアウトの確率のスカラープレースホルダーです。
    """
    # 畳み込みニューラルネット内で使用するための変形。
    # 最後のディメンションは画像がグレースケールであるため1です。
    # RGBイメージでは3、RGBAでは4などです。
    with tf.name_scope('reshape'):
        x_image = tf.reshape(x, [-1, 28, 28, 1])

    # 畳み込み層1
    # 1つのグレースケールイメージを32枚の特徴マップにする。
    # 32は単に試行と経験で得られたマジックナンバー
    with tf.name_scope('conv1'):
        W_conv1 = weight_variable([5, 5, 1, 32])
        b_conv1 = bias_variable([32])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    # プーリング層1
    # 2倍にダウンサンプリング
    with tf.name_scope('pool1'):
        h_pool1 = max_pool_2x2(h_conv1)

    # 畳み込み層2
    # 32枚の特徴マップを64枚にする。
    with tf.name_scope('conv2'):
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

    # プーリング層2
    with tf.name_scope('pool2'):
        h_pool2 = max_pool_2x2(h_conv2)

    # 全結合層
    # 2回のダウンサンプリングの後、28×28の画像は7×7の64枚の特徴マップに縮小されます。
    # これを1024枚の特徴マップにします。
    with tf.name_scope('fc1'):
        W_fc1 = weight_variable([7 * 7 * 64, 1024])
        b_fc1 = bias_variable([1024])

        h_pool2_flat = tf.reshape(h_pool2, [-1, 7 * 7 * 64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

    # ドロップアウト
    # 過学習を防ぐため訓練データごとにニューロンを何割か無視
    with tf.name_scope('dropout'):
        keep_prob = tf.placeholder(tf.float32)
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    # 1024枚の特徴マップを10クラスにする(各桁に1つずつ)。
    with tf.name_scope('fc2'):
        W_fc2 = weight_variable([1024, 10])
        b_fc2 = bias_variable([10])

        y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
    return y_conv, keep_prob


def conv2d(x, W):
    # 畳み込み
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')


def max_pool_2x2(x):
    # プーリング
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                          strides=[1, 2, 2, 1], padding='SAME')


def weight_variable(shape):
    # 重み初期化
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)


def bias_variable(shape):
    # バイアス初期化
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)


def main(_):
    # データの読み込み
    mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

    # モデルの作成
    x = tf.placeholder(tf.float32, [None, 784], name='x')

    # 損失とオプティマイザを定義
    y_ = tf.placeholder(tf.float32, [None, 10], name='y_')

    # ディープネットのグラフを作成する
    y_conv, keep_prob = deepnn(x)

    with tf.name_scope('loss'):
        cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_,
                                                                logits=y_conv)
    cross_entropy = tf.reduce_mean(cross_entropy)

    with tf.name_scope('optimizer'):
        # 1e-4 = 0.0001
        train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

    with tf.name_scope('accuracy'):
        correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))
        correct_prediction = tf.cast(correct_prediction, tf.float32)
    accuracy = tf.reduce_mean(correct_prediction)

    train_writer = tf.summary.FileWriter('/tmp/pros')
    train_writer.add_graph(tf.get_default_graph())

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for i in range(10000):
            batch = mnist.train.next_batch(50)
            if i % 100 == 0:
                train_accuracy = accuracy.eval(feed_dict={
                    x: batch[0], y_: batch[1], keep_prob: 1.0})
                print('step %d, training accuracy %g' % (i, train_accuracy))
            train_step.run(
                feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

        print('test accuracy %g' % accuracy.eval(feed_dict={
            x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--data_dir', type=str,
                        default='/tmp/tensorflow/mnist/input_data',
                        help='Directory for storing input data')
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.name_scope tf.reshape tf.nn.relu tf.matmul tf.placeholder tf.float32 tf.nn.dropout tf.nn.conv2d tf.nn.max_pool tf.truncated_normal tf.Variable tf.constant tf.nn.softmax_cross_entropy_with_logits tf.reduce_mean tf.train.AdamOptimizer tf.equal tf.argmax tf.cast tf.summary.FileWriter tf.get_default_graph tf.Session tf.global_variables_initializer tf.app.run

TensorFlow Mechanics 101

TensorFlow技法101
Mnist 0-9.png

$ virtualenv --system-site-packages -p python3 mechanics
$ source ~/mechanics/bin/activate
(mechanics)$ pip3 install --upgrade tensorflow
# (mechanics)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/mnist.py
# (mechanics)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/fully_connected_feed.py
(mechanics)$ gedit mnist.py
# コピーペースト
(mechanics)$ gedit fully_connected_feed.py
# コピーペースト
(mechanics)$ python fully_connected_feed.py
(mechanics)$ tensorboard --logdir /tmp/tensorflow/mnist/logs/fully_connected_feed
# ブラウザ http://localhost:6006
# CTRL+C
(mechanics)$ deactivate
$ rm -r \
    mechanics \
    mnist.py \
    fully_connected_feed.py \
    /tmp/tensorflow
Tensorboard-mechanics.png

mnist.py

"""MNISTネットワークを構築

モデル構築のためのinference/loss/trainingを実装
1. inference() - 予測のためにネットワークを前進実行するグラフを作成します。
2. loss() - 損失を生成する操作をグラフに追加します。
3. training() - 勾配を計算し適用する操作をグラフに追加します。

このファイルは、さまざまな"fully_connected_*.py"ファイルで使用されるもので、
実行するためのものではありません。
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import math

import tensorflow as tf

# MNISTデータセットには、0〜9の数字を表す10のクラスがあります。
NUM_CLASSES = 10

# MNIST画像は常に28x28ピクセルです。
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE * IMAGE_SIZE


def inference(images, hidden1_units, hidden2_units):
    """MNISTモデルをinferenceに使用できる位置で構築
    Args:
      images:画像のプレースホルダ inputs()から取得
      hidden1_units:1番目の隠れ層のサイズ
      hidden2_units:2番目の隠れ層のサイズ
    Returns:
      softmax_linear:計算されたロジットをテンソルとして出力
    """
    # hidden 1
    with tf.name_scope('hidden1'):
        weights = tf.Variable(
            tf.truncated_normal([IMAGE_PIXELS, hidden1_units],
                                stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))),
            name='weights')
        biases = tf.Variable(tf.zeros([hidden1_units]),
                             name='biases')
        hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
    # hidden 2
    with tf.name_scope('hidden2'):
        weights = tf.Variable(
            tf.truncated_normal([hidden1_units, hidden2_units],
                                stddev=1.0 / math.sqrt(float(hidden1_units))),
            name='weights')
        biases = tf.Variable(tf.zeros([hidden2_units]),
                             name='biases')
        hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
    # softmax linear
    with tf.name_scope('softmax_linear'):
        weights = tf.Variable(
            tf.truncated_normal([hidden2_units, NUM_CLASSES],
                                stddev=1.0 / math.sqrt(float(hidden2_units))),
            name='weights')
        biases = tf.Variable(tf.zeros([NUM_CLASSES]),
                             name='biases')
        logits = tf.matmul(hidden2, weights) + biases
    return logits


def loss(logits, labels):
    """ロジットとラベルからの損失を計算
    Args:
      logits: ロジットテンソル float - [batch_size, NUM_CLASSES]
      labels: ラベルテンソル int32 - [batch_size]
    Returns:
      loss: floatタイプの損失テンソル
    """
    labels = tf.to_int64(labels)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=labels, logits=logits, name='xentropy')
    return tf.reduce_mean(cross_entropy, name='xentropy_mean')


def training(loss, learning_rate):
    """トレーニング操作を設定
    TensorBoardで時間の経過とともに損失を追跡するためのサマライザを作成
    オプティマイザを作成し勾配をすべての学習可能な変数に適用
    この関数が返す操作はモデルを訓練させるために`sess.run()`呼び出しに渡されなければならない
    Args:
      loss: 損失テンソル from loss()
      learning_rate: 勾配降下に使用する学習率
    Returns:
      train_op: トレーニングのための操作
    """
    # スナップショットの損失に関するスカラーを追加
    tf.summary.scalar('loss', loss)
    # 与えられた学習率で勾配降下オプティマイザを作成
    optimizer = tf.train.GradientDescentOptimizer(learning_rate)
    # グローバルステップを追跡する変数を作成
    global_step = tf.Variable(0, name='global_step', trainable=False)
    # オプティマイザを使用して損失を最小限に抑えるgradientを適用
    # (また、グローバルステップカウンタも増やす)
    train_op = optimizer.minimize(loss, global_step=global_step)
    return train_op


def evaluation(logits, labels):
    """ラベルを予測する際のロジットの品質を評価
    Args:
      logits: ロジットテンソル float - [batch_size, NUM_CLASSES]
      labels: ラベルテンソル int32 - [0, NUM_CLASSES]の範囲の値を持つ[batch_size]
    Returns:
      正しく予測された(batch_size外の)サンプル数を持つスカラーint32テンソル
    """
    # クラシファイアモデルでは、in_top_k操作を使用することができる
    # ラベルがその例のすべてのロジットのトップk(ここではk=1)にあるサンプルで
    # 真である形状[batch_size]のboolテンソルを返す
    correct = tf.nn.in_top_k(logits, labels, 1)
    # 真のエントリの数を返す
    return tf.reduce_sum(tf.cast(correct, tf.int32))

tf.name_scope tf.Variable tf.truncated_normal tf.zeros tf.nn.relu tf.matmul tf.to_int64 tf.nn.sparse_softmax_cross_entropy_with_logits tf.reduce_mean tf.summary.scalar tf.train.GradientDescentOptimizer tf.nn.in_top_k tf.reduce_sum tf.cast tf.int32

fully_connected_feed.py

"""フィード辞書を使用してMNISTネットワークをトレーニングし評価"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=missing-docstring
import argparse
import os
import sys
import time

from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.examples.tutorials.mnist import mnist

# 外部フラグとしての基本モデルパラメータ
FLAGS = None


def placeholder_inputs(batch_size):
    """入力テンソルのプレースホルダを生成
    このプレースホルダーは、残りのモデル構築コードによって入力として使用され、
    下の.run()ループでダウンロードされたデータから供給
    Args:
      batch_size: バッチサイズは両方のプレースホルダーにベーク
    Returns:
      images_placeholder: 画像プレースホルダ
      labels_placeholder: ラベルプレースホルダ
    """
    # プレースホルダの形状は、フルイメージとラベルテンソルの形状と一致しますが、
	# 訓練またはテストデータセットのフルサイズではなく、最初の次元がbatch_sizeになる
    images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,
                                                           mnist.IMAGE_PIXELS))
    labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))
    return images_placeholder, labels_placeholder


def fill_feed_dict(data_set, images_pl, labels_pl):
    """与えられたステップを訓練するためにfeed_dictを埋る
    feed_dictは以下の形式をとります:
    feed_dict = {
        <placeholder>: <tensor of values to be passed for placeholder>,
        ....
    }
    Args:
      data_set: 画像とラベルのセット from input_data.read_data_sets()
      images_pl: 画像のプレースホルダ from placeholder_inputs().
      labels_pl: ラベルのプレースホルダ from placeholder_inputs().
    Returns:
      feed_dict: The feed dictionary mapping from placeholders to values.
    """
    # 次のバッチサイズの例で埋められたプレースホルダのfeed_dictを作成
    images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size,
                                                   FLAGS.fake_data)
    feed_dict = {
        images_pl: images_feed,
        labels_pl: labels_feed,
    }
    return feed_dict


def do_eval(sess,
            eval_correct,
            images_placeholder,
            labels_placeholder,
            data_set):
    """データの完全なエポックに対して1つの評価を実行
    Args:
      sess: モデルが訓練されたセッション
      eval_correct: 正しい予測の数を返すテンソル
      images_placeholder: 画像のプレースホルダ
      labels_placeholder: ラベルのプレースホルダ
      data_set: input_data.read_data_sets()から評価する画像とラベルのセット
    """
    # evalの1つのエポックを実行
    true_count = 0  # 正しい予測の数を数える
    steps_per_epoch = data_set.num_examples // FLAGS.batch_size
    num_examples = steps_per_epoch * FLAGS.batch_size
    for step in xrange(steps_per_epoch):
        feed_dict = fill_feed_dict(data_set,
                                   images_placeholder,
                                   labels_placeholder)
        true_count += sess.run(eval_correct, feed_dict=feed_dict)
    precision = float(true_count) / num_examples
    print('Num examples: %d  Num correct: %d  Precision @ 1: %0.04f' %
          (num_examples, true_count, precision))


def run_training():
    """MNISTを訓練"""
    # MNISTの、トレーニング、検証、テストのための画像とラベルのセットを取り込む
    data_sets = input_data.read_data_sets(
        FLAGS.input_data_dir, FLAGS.fake_data)

    # モデルがデフォルトのグラフに組み込まれることをTensorFlowに伝える
    with tf.Graph().as_default():
        # イメージとラベルのプレースホルダを生成
        images_placeholder, labels_placeholder = placeholder_inputs(
            FLAGS.batch_size)
        # 推論モデルから予測を計算するグラフを作成
        logits = mnist.inference(images_placeholder,
                                 FLAGS.hidden1,
                                 FLAGS.hidden2)
        # 損失計算のための操作をグラフに追加
        loss = mnist.loss(logits, labels_placeholder)
        # 勾配を計算して適用する操作をグラフに追加
        train_op = mnist.training(loss, FLAGS.learning_rate)
        # 評価中ラベルとロジットの比較操作を追加
        eval_correct = mnist.evaluation(logits, labels_placeholder)
        # サマリのTFコレクションに基づいてサマリテンソルを構築
        summary = tf.summary.merge_all()
        # 変数イニシャライザ操作を追加
        init = tf.global_variables_initializer()
        # トレーニングチェックポイントを作成するためのセーバーを作成
        saver = tf.train.Saver()
        # グラフ上で操作を実行するためのセッションを作成
        sess = tf.Session()
        # SummaryWriterをインスタンス化してサマリとグラフを出力
        summary_writer = tf.summary.FileWriter(FLAGS.log_dir, sess.graph)
        # そして、すべてが構築された後:
        # 操作を実行して変数を初期化
        sess.run(init)

        # 訓練ループを開始
        for step in xrange(FLAGS.max_steps):
            start_time = time.time()

            # トレーニングステップの画像とラベルの実際のセットをfeed dictionaryに入力
            feed_dict = fill_feed_dict(data_sets.train,
                                       images_placeholder,
                                       labels_placeholder)

            # モデルの1ステップを実行
            # 戻り値は`train_op`(廃棄されます)と`loss`操作からのアクティベーション
            # 操作または変数の値を調べるには、sess.run()に渡されたリストにそれらの値を含めることができる
            # テンソルの値はタプルに返されえる
            _, loss_value = sess.run([train_op, loss],
                                     feed_dict=feed_dict)

            duration = time.time() - start_time

            # サマリを書き概要を頻繁にprint
            if step % 100 == 0:
                # ステータスをstdoutに出力
                print('Step %d: loss = %.2f (%.3f sec)' %
                      (step, loss_value, duration))
                # イベントファイルを更新
                summary_str = sess.run(summary, feed_dict=feed_dict)
                summary_writer.add_summary(summary_str, step)
                summary_writer.flush()

            # チェックポイントを保存しモデルを定期的に評価
            if (step + 1) % 1000 == 0 or (step + 1) == FLAGS.max_steps:
                checkpoint_file = os.path.join(FLAGS.log_dir, 'model.ckpt')
                saver.save(sess, checkpoint_file, global_step=step)
                # トレーニングセットに対して評価
                print('Training Data Eval:')
                do_eval(sess,
                        eval_correct,
                        images_placeholder,
                        labels_placeholder,
                        data_sets.train)
                # 検証セットに対して評価
                print('Validation Data Eval:')
                do_eval(sess,
                        eval_correct,
                        images_placeholder,
                        labels_placeholder,
                        data_sets.validation)
                # テストセットに対して評価
                print('Test Data Eval:')
                do_eval(sess,
                        eval_correct,
                        images_placeholder,
                        labels_placeholder,
                        data_sets.test)


def main(_):
    if tf.gfile.Exists(FLAGS.log_dir):
        tf.gfile.DeleteRecursively(FLAGS.log_dir)
    tf.gfile.MakeDirs(FLAGS.log_dir)
    run_training()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--learning_rate',
        type=float,
        default=0.01,
        help='Initial learning rate.'
    )
    parser.add_argument(
        '--max_steps',
        type=int,
        default=2000,
        help='Number of steps to run trainer.'
    )
    parser.add_argument(
        '--hidden1',
        type=int,
        default=128,
        help='Number of units in hidden layer 1.'
    )
    parser.add_argument(
        '--hidden2',
        type=int,
        default=32,
        help='Number of units in hidden layer 2.'
    )
    parser.add_argument(
        '--batch_size',
        type=int,
        default=100,
        help='Batch size.  Must divide evenly into the dataset sizes.'
    )
    parser.add_argument(
        '--input_data_dir',
        type=str,
        default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                             'tensorflow/mnist/input_data'),
        help='Directory to put the input data.'
    )
    parser.add_argument(
        '--log_dir',
        type=str,
        default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                             'tensorflow/mnist/logs/fully_connected_feed'),
        help='Directory to put the log data.'
    )
    parser.add_argument(
        '--fake_data',
        default=False,
        help='If true, uses fake data for unit testing.',
        action='store_true'
    )

    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.placeholder tf.float32 tf.int32 tf.Graph tf.summary.merge_all tf.global_variables_initializer tf.train.Saver tf.Session tf.summary.FileWriter tf.gfile.Exists tf.gfile.DeleteRecursively tf.gfile.MakeDirs tf.app.run

tf.estimator Quickstart

tf.estimatorクイックスタート
Iris three species.jpg
※記述がpython2.7

$ virtualenv --system-site-packages estimator
$ source ~/estimator/bin/activate
(estimator)$ pip install --upgrade tensorflow
(estimator)$ gedit estimator.py
# コピーペースト
(estimator)$ python estimator.py
# Test Accuracy: 0.966667
(estimator)$ tensorboard --logdir /tmp/iris_model
# ブラウザ http://localhost:6006
# CTRL+C
(estimator)$ deactivate
$ rm -r \
    estimator \
    estimator.py \
    iris_test.csv \
    iris_training.csv \
    /tmp/iris_model
Tensorboard-estimator.png

estimator.py

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
from six.moves.urllib.request import urlopen

import numpy as np
import tensorflow as tf

# データセット
IRIS_TRAINING = "iris_training.csv"
IRIS_TRAINING_URL = "http://download.tensorflow.org/data/iris_training.csv"

IRIS_TEST = "iris_test.csv"
IRIS_TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"


def main():
    # トレーニングセットとテストセットがローカルに保存されていない場合はダウンロード
    if not os.path.exists(IRIS_TRAINING):
        raw = urlopen(IRIS_TRAINING_URL).read()
        with open(IRIS_TRAINING, "wb") as f:
            f.write(raw)

    if not os.path.exists(IRIS_TEST):
        raw = urlopen(IRIS_TEST_URL).read()
        with open(IRIS_TEST, "wb") as f:
            f.write(raw)

    # データセットをロード
    training_set = tf.contrib.learn.datasets.base.load_csv_with_header(
        filename=IRIS_TRAINING,
        target_dtype=np.int,
        features_dtype=np.float32)
    test_set = tf.contrib.learn.datasets.base.load_csv_with_header(
        filename=IRIS_TEST,
        target_dtype=np.int,
        features_dtype=np.float32)

    # すべてのフィーチャに実数値データがあることを指定
    feature_columns = [tf.feature_column.numeric_column("x", shape=[4])]

    # それぞれ10,20,10ユニットで3層のDNNを構築
    classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                            hidden_units=[10, 20, 10],
                                            n_classes=3,
                                            model_dir="/tmp/iris_model")
    # トレーニング入力を定義
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": np.array(training_set.data)},
        y=np.array(training_set.target),
        num_epochs=None,
        shuffle=True)

    # 訓練
    classifier.train(input_fn=train_input_fn, steps=2000)

    # テスト入力を定義
    test_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": np.array(test_set.data)},
        y=np.array(test_set.target),
        num_epochs=1,
        shuffle=False)

    # 精度を評価
    accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"]

    print("\nTest Accuracy: {0:f}\n".format(accuracy_score))

    # 2つの新しい花のサンプルを分類
    new_samples = np.array(
        [[6.4, 3.2, 4.5, 1.5],
         [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)
    predict_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": new_samples},
        num_epochs=1,
        shuffle=False)

    predictions = list(classifier.predict(input_fn=predict_input_fn))
    predicted_classes = [p["classes"] for p in predictions]

    print(
        "New Samples, Class Predictions:    {}\n"
        .format(predicted_classes))


if __name__ == "__main__":
    main()

tf.contrib.learn.datasets tf.feature_column.numeric_column tf.estimator.DNNClassifier tf.estimator.inputs.numpy_input_fn

Building Input Functions with tf.estimator

tf.estimatorによる入力関数の構築
Boston train csv.png

$ virtualenv --system-site-packages -p python3 input_fn
$ source ~/input_fn/bin/activate
(input_fn)$ pip3 install --upgrade tensorflow
(input_fn)$ pip3 install -U pandas
# (input_fn)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/input_fn/boston.py
(input_fn)$ gedit boston.py
# コピーペースト
(input_fn)$ wget http://download.tensorflow.org/data/boston_train.csv
(input_fn)$ wget http://download.tensorflow.org/data/boston_test.csv
(input_fn)$ wget http://download.tensorflow.org/data/boston_predict.csv
(input_fn)$ python boston.py
# Predictions: [array([ 33.24168777], dtype=float32), array([ 18.63273621] …
(input_fn)$ tensorboard --logdir /tmp/boston_model
# ブラウザ http://localhost:6006
# CTRL+C
(input_fn)$ deactivate
$ rm -r \
    input_fn \
    boston.py \
    boston_train.csv \
    boston_test.csv \
    boston_predict.csv \
    /tmp/boston_model
Tensorboard-input fn.png

boston.py

"""住宅データセット用のカスタムinput_fnを持つDNNRegressor"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import itertools

import pandas as pd
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)

COLUMNS = ["crim", "zn", "indus", "nox", "rm", "age",
           "dis", "tax", "ptratio", "medv"]
FEATURES = ["crim", "zn", "indus", "nox", "rm",
            "age", "dis", "tax", "ptratio"]
LABEL = "medv"


def get_input_fn(data_set, num_epochs=None, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
        x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
        y=pd.Series(data_set[LABEL].values),
        num_epochs=num_epochs,
        shuffle=shuffle)


def main(unused_argv):
    # データセットをロード
    training_set = pd.read_csv("boston_train.csv", skipinitialspace=True,
                               skiprows=1, names=COLUMNS)
    test_set = pd.read_csv("boston_test.csv", skipinitialspace=True,
                           skiprows=1, names=COLUMNS)

    # 家の中央値を予測するための6つの例のセット
    prediction_set = pd.read_csv("boston_predict.csv", skipinitialspace=True,
                                 skiprows=1, names=COLUMNS)

    # フィーチャー・コラム
    feature_cols = [tf.feature_column.numeric_column(k) for k in FEATURES]

    # それぞれ10,10ユニットの完全に接続されたDNN2層をビルド
    regressor = tf.estimator.DNNRegressor(feature_columns=feature_cols,
                                          hidden_units=[10, 10],
                                          model_dir="/tmp/boston_model")

    # 訓練
    regressor.train(input_fn=get_input_fn(training_set), steps=5000)

    # test_setの1エポックに亘る損失を評価する。
    ev = regressor.evaluate(
        input_fn=get_input_fn(test_set, num_epochs=1, shuffle=False))
    loss_score = ev["loss"]
    print("Loss: {0:f}".format(loss_score))

    # prediction_setのスライスにわたって予測を出力します。
    y = regressor.predict(
        input_fn=get_input_fn(prediction_set, num_epochs=1, shuffle=False))
    # .predict() dictsの反復子を返します。 リストに変換してprint
    # 予測
    predictions = list(p["predictions"] for p in itertools.islice(y, 6))
    print("Predictions: {}".format(str(predictions)))


if __name__ == "__main__":
    tf.app.run()

tf.logging.set_verbosity tf.logging tf.estimator.inputs.pandas_input_fn tf.feature_column.numeric_column tf.estimator.DNNRegressor tf.app.run

TensorBoard: Visualizing Learning

TensorBoard:学習の可視化
Mnist 0-9.png

$ virtualenv --system-site-packages -p python3 summaries
$ source ~/summaries/bin/activate
(summaries)$ pip3 install --upgrade tensorflow
# (summaries)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py
(summaries)$ gedit mnist_with_summaries.py
# コピーペースト
(summaries)$ python mnist_with_summaries.py
(summaries)$ tensorboard --logdir /tmp/tensorflow/mnist/logs/mnist_with_summaries
# ブラウザ http://localhost:6006
# CTRL+C
(summaries)$ deactivate
$ rm -r \
    summaries \
    mnist_with_summaries.py \
    /tmp/tensorflow
Tensorflow-summaries.png

mnist_with_summaries.py

"""TensorBoardで要約を表示する簡単なMNIST分類器

これは印象的なMNISTモデルですが、tf.name_scopeを使用してTensorBoardグラフエクスプローラで
グラフを見やすくする良い例です。
要約タグに名前を付けて、TensorBoardで有意義にグループ化されるようにします。

すべてのTensorBoardダッシュボードの機能を示します。
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import sys

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data

FLAGS = None


def train():
    # データのインポート
    mnist = input_data.read_data_sets(FLAGS.data_dir,
                                      one_hot=True,
                                      fake_data=FLAGS.fake_data)

    sess = tf.InteractiveSession()
    # 多層モデルを作成

    # プレースホルダに入力
    with tf.name_scope('input'):
        x = tf.placeholder(tf.float32, [None, 784], name='x-input')
        y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')

    with tf.name_scope('input_reshape'):
        image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
        tf.summary.image('input', image_shaped_input, 10)

    # これらの変数を0に初期化することはできません - ネットワークが邪魔になります。
    def weight_variable(shape):
        """適切な初期化を使って重み変数を作成します。"""
        initial = tf.truncated_normal(shape, stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(shape):
        """適切な初期化を行ってバイアス変数を作成します。"""
        initial = tf.constant(0.1, shape=shape)
        return tf.Variable(initial)

    def variable_summaries(var):
        """Tensor(TensorBoardビジュアライゼーション用)に多くの要約を添付します。"""
        with tf.name_scope('summaries'):
            mean = tf.reduce_mean(var)
            tf.summary.scalar('mean', mean)
            with tf.name_scope('stddev'):
                stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
            tf.summary.scalar('stddev', stddev)
            tf.summary.scalar('max', tf.reduce_max(var))
            tf.summary.scalar('min', tf.reduce_min(var))
            tf.summary.histogram('histogram', var)

    def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
        """シンプルなニューラルネット層を作るための再利用可能なコード。

        行列乗算、バイアス加算を行い、ReLUを使用して非線形化します。
        結果グラフが読みやすくなるように名前スコープを設定し、多数の要約操作を追加します。
        """
        # 名前スコープを追加することで、グラフのレイヤーを論理的にグループ化することができます。
        with tf.name_scope(layer_name):
            # この変数は、レイヤーのウェイトの状態を保持します
            with tf.name_scope('weights'):
                weights = weight_variable([input_dim, output_dim])
                variable_summaries(weights)
            with tf.name_scope('biases'):
                biases = bias_variable([output_dim])
                variable_summaries(biases)
            with tf.name_scope('Wx_plus_b'):
                preactivate = tf.matmul(input_tensor, weights) + biases
                tf.summary.histogram('pre_activations', preactivate)
            activations = act(preactivate, name='activation')
            tf.summary.histogram('activations', activations)
            return activations

    hidden1 = nn_layer(x, 784, 500, 'layer1')

    with tf.name_scope('dropout'):
        keep_prob = tf.placeholder(tf.float32)
        tf.summary.scalar('dropout_keep_probability', keep_prob)
        dropped = tf.nn.dropout(hidden1, keep_prob)

    # softmaxの起動をまだ適用しないでください。以下を参照してください。
    y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)

    with tf.name_scope('cross_entropy'):
        # cross-entropyの式、
        #
        # tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.softmax(y)),
        #                               reduction_indices=[1]))
        #
        # は数値的に不安定である可能性があります。
        #
        # そこで、ここでは'y'の出力に対して
        # tf.nn.softmax_cross_entropy_with_logitsを使用してバッチ全体で平均します。

        diff = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)
        with tf.name_scope('total'):
            cross_entropy = tf.reduce_mean(diff)
    tf.summary.scalar('cross_entropy', cross_entropy)

    with tf.name_scope('train'):
        train_step = tf.train.AdamOptimizer(FLAGS.learning_rate).minimize(
            cross_entropy)

    with tf.name_scope('accuracy'):
        with tf.name_scope('correct_prediction'):
            correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        with tf.name_scope('accuracy'):
            accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    tf.summary.scalar('accuracy', accuracy)

    # すべての要約をマージし書き出します
    # /tmp/tensorflow/mnist/logs/mnist_with_summaries (by default)
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter(FLAGS.log_dir + '/train', sess.graph)
    test_writer = tf.summary.FileWriter(FLAGS.log_dir + '/test')
    tf.global_variables_initializer().run()

    # モデルを訓練し要約を書き出します。
    # 10ステップごとにテストセットの精度を測定し、テスト要約を書き出します。
    # 他のすべてのステップ、トレーニングデータのトレーニングステップの実行、トレーニングの要約の追加

    def feed_dict(train):
        """Make a TensorFlow feed_dict: Tensorプレースホルダにデータをマップします。"""
        if train or FLAGS.fake_data:
            xs, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
            k = FLAGS.dropout
        else:
            xs, ys = mnist.test.images, mnist.test.labels
            k = 1.0
        return {x: xs, y_: ys, keep_prob: k}

    for i in range(FLAGS.max_steps):
        if i % 10 == 0:  # 要約とテストセットの精度を記録する
            summary, acc = sess.run(
                [merged, accuracy], feed_dict=feed_dict(False))
            test_writer.add_summary(summary, i)
            print('Accuracy at step %s: %s' % (i, acc))
        else:  # 要約をセットした訓練を記録と訓練
            if i % 100 == 99:  # Record execution stats
                run_options = tf.RunOptions(
                    trace_level=tf.RunOptions.FULL_TRACE)
                run_metadata = tf.RunMetadata()
                summary, _ = sess.run([merged, train_step],
                                      feed_dict=feed_dict(True),
                                      options=run_options,
                                      run_metadata=run_metadata)
                train_writer.add_run_metadata(run_metadata, 'step%03d' % i)
                train_writer.add_summary(summary, i)
                print('Adding run metadata for', i)
            else:  # 要約を記録
                summary, _ = sess.run(
                    [merged, train_step], feed_dict=feed_dict(True))
                train_writer.add_summary(summary, i)
    train_writer.close()
    test_writer.close()


def main(_):
    if tf.gfile.Exists(FLAGS.log_dir):
        tf.gfile.DeleteRecursively(FLAGS.log_dir)
    tf.gfile.MakeDirs(FLAGS.log_dir)
    train()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--fake_data', nargs='?', const=True, type=bool,
                        default=False,
                        help='If true, uses fake data for unit testing.')
    parser.add_argument('--max_steps', type=int, default=1000,
                        help='Number of steps to run trainer.')
    parser.add_argument('--learning_rate', type=float, default=0.001,
                        help='Initial learning rate')
    parser.add_argument('--dropout', type=float, default=0.9,
                        help='Keep probability for training dropout.')
    parser.add_argument(
        '--data_dir',
        type=str,
        default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                             'tensorflow/mnist/input_data'),
        help='Directory for storing input data')
    parser.add_argument(
        '--log_dir',
        type=str,
        default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                             'tensorflow/mnist/logs/mnist_with_summaries'),
        help='Summaries log directory')
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.InteractiveSession tf.name_scope tf.placeholder tf.float32 tf.reshape tf.summary.image tf.truncated_normal tf.Variable tf.constant tf.reduce_mean tf.summary.scalar tf.sqrt tf.square tf.reduce_max tf.reduce_min tf.summary.histogram tf.matmul tf.nn.dropout tf.identity tf.reduce_mean tf.reduce_sum tf.log tf.softmax
tf.nn.softmax_cross_entropy_with_logits tf.train.AdamOptimizer tf.argmax tf.cast tf.summary.merge_all tf.summary.FileWriter tf.global_variables_initializer tf.RunOptions tf.RunMetadata tf.gfile.Exists tf.gfile.DeleteRecursively tf.gfile.MakeDirs

tf.app.run

TensorBoard Histogram Dashboard

TensorBoardヒストグラムダッシュボード

$ virtualenv --system-site-packages -p python3 histograms
$ source ~/histograms/bin/activate
(histograms)$ pip3 install --upgrade tensorflow
(histograms)$ gedit histograms.py
# コピーペースト
(histograms)$ python histograms.py
(histograms)$ tensorboard --logdir /tmp/histogram_example
# ブラウザ http://localhost:6006
# CTRL+C
(histograms)$ deactivate
$ rm -r \
    histograms \
    histograms.py \
    /tmp/histogram_example
import tensorflow as tf

k = tf.placeholder(tf.float32)

# 移動平均を使って正規分布にする
mean_moving_normal = tf.random_normal(shape=[1000], mean=(5 * k), stddev=1)
# その分布をヒストグラムの要約に記録する
tf.summary.histogram("normal/moving_mean", mean_moving_normal)

# セッションの設定と要約の書き出し
sess = tf.Session()
writer = tf.summary.FileWriter("/tmp/histogram_example")

summaries = tf.summary.merge_all()

# ループを設定してディスクに要約を書き込む
N = 400
for step in range(N):
    k_val = step / float(N)
    summ = sess.run(summaries, feed_dict={k: k_val})
    writer.add_summary(summ, global_step=step)

tf.placeholder tf.float32 tf.random_normal tf.summary.histogram tf.Session tf.summary.FileWriter tf.summary.merge_all

Develop > Tutorials >

Using GPUs

GPUの使用

Image Recognition

画像認識
Cropped panda.jpg

$ git clone https://github.com/tensorflow/models
$ virtualenv --system-site-packages -p python3 recognition
$ source ~/recognition/bin/activate
(recognition)$ pip3 install --upgrade tensorflow
(recognition)$ cd models/tutorials/image/imagenet
(recognition)$ python classify_image.py
# giant panda, panda, panda bear, coon bear,… (score = 0.89107)
(recognition)$ deactivate
$ cd ~
$ rm -r \
    recognition \
    models \
    /tmp/imagenet

classify_image.py

"""インセプションによる簡単な画像分類

ImageNet 2012 Challengeデータセットで訓練されたInceptionで画像分類を実行する。

このプログラムは、保存されたGraphDefプロトコルバッファからグラフを作成し、
入力JPEG画像の推論を実行します。
それは、その確率とともに上位5つの予測の人間が読める文字列を出力します。

--image_file引数をjpgイメージに変更して、そのイメージの分類を計算します。

このスクリプトを使用してイメージ認識を実行する方法の詳細については、
チュートリアルおよびWebサイトを参照してください。

https://tensorflow.org/tutorials/image_recognition/
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os.path
import re
import sys
import tarfile

import numpy as np
from six.moves import urllib
import tensorflow as tf

FLAGS = None

# pylint: disable=line-too-long
DATA_URL = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
# pylint: enable=line-too-long


class NodeLookup(object):
    """整数ノードIDを人間が読めるラベルに変換します。"""

    def __init__(self,
                 label_lookup_path=None,
                 uid_lookup_path=None):
        if not label_lookup_path:
            label_lookup_path = os.path.join(
                FLAGS.model_dir, 'imagenet_2012_challenge_label_map_proto.pbtxt')
        if not uid_lookup_path:
            uid_lookup_path = os.path.join(
                FLAGS.model_dir, 'imagenet_synset_to_human_label_map.txt')
        self.node_lookup = self.load(label_lookup_path, uid_lookup_path)

    def load(self, label_lookup_path, uid_lookup_path):
        """各softmaxノードに人間が読める英語の名前をロードします。

        Args:
          label_lookup_path: 文字列UIDを整数ノードIDに変換します。
          uid_lookup_path: 文字列UIDを人間が読める文字列に変換します。

        Returns:
          整数ノードIDから人間が読める文字列に変換します。
        """
        if not tf.gfile.Exists(uid_lookup_path):
            tf.logging.fatal('File does not exist %s', uid_lookup_path)
        if not tf.gfile.Exists(label_lookup_path):
            tf.logging.fatal('File does not exist %s', label_lookup_path)

        # 文字列UIDから人間が読める文字列へのマッピングをロードする
        proto_as_ascii_lines = tf.gfile.GFile(uid_lookup_path).readlines()
        uid_to_human = {}
        p = re.compile(r'[n\d]*[ \S,]*')
        for line in proto_as_ascii_lines:
            parsed_items = p.findall(line)
            uid = parsed_items[0]
            human_string = parsed_items[2]
            uid_to_human[uid] = human_string

        # 文字列UIDから整数ノードIDへのマッピングをロードします。
        node_id_to_uid = {}
        proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines()
        for line in proto_as_ascii:
            if line.startswith('  target_class:'):
                target_class = int(line.split(': ')[1])
            if line.startswith('  target_class_string:'):
                target_class_string = line.split(': ')[1]
                node_id_to_uid[target_class] = target_class_string[1:-2]

        # 整数ノードIDの最終マッピングを人間が読める文字列にロードする
        node_id_to_name = {}
        for key, val in node_id_to_uid.items():
            if val not in uid_to_human:
                tf.logging.fatal('Failed to locate: %s', val)
            name = uid_to_human[val]
            node_id_to_name[key] = name

        return node_id_to_name

    def id_to_string(self, node_id):
        if node_id not in self.node_lookup:
            return ''
        return self.node_lookup[node_id]


def create_graph():
    """保存されたGraphDefファイルからグラフを作成し保存します。"""
    # Creates graph from saved graph_def.pb.
    with tf.gfile.FastGFile(os.path.join(
            FLAGS.model_dir, 'classify_image_graph_def.pb'), 'rb') as f:
        graph_def = tf.GraphDef()
        graph_def.ParseFromString(f.read())
        _ = tf.import_graph_def(graph_def, name='')


def run_inference_on_image(image):
    """画像上で推論を実行します。

    Args:
      image: 画像ファイル名

    Returns:
      Nothing
    """
    if not tf.gfile.Exists(image):
        tf.logging.fatal('File does not exist %s', image)
    image_data = tf.gfile.FastGFile(image, 'rb').read()

    # 保存されたGraphDefからグラフを作成します。
    create_graph()

    with tf.Session() as sess:
        # 有用なテンソル:
        # 'softmax:0': 1000個のラベルにわたって正規化された予測を含むテンソル。
        # 'pool_3:0': 画像の2048浮動表現を含む最後の2番目の層を含むテンソル。
        # 'DecodeJpeg/contents:0': イメージのJPEGエンコーディングを提供する文字列を含むテンソル。
        # image_dataを入力としてグラフに供給することによってsoftmaxテンソルを実行します。
        softmax_tensor = sess.graph.get_tensor_by_name('softmax:0')
        predictions = sess.run(softmax_tensor,
                               {'DecodeJpeg/contents:0': image_data})
        predictions = np.squeeze(predictions)

        # ノードID --> 英語の文字列検索を作成します。
        node_lookup = NodeLookup()

        top_k = predictions.argsort()[-FLAGS.num_top_predictions:][::-1]
        for node_id in top_k:
            human_string = node_lookup.id_to_string(node_id)
            score = predictions[node_id]
            print('%s (score = %.5f)' % (human_string, score))


def maybe_download_and_extract():
    """モデルのtarファイルをダウンロードして抽出します。"""
    dest_directory = FLAGS.model_dir
    if not os.path.exists(dest_directory):
        os.makedirs(dest_directory)
    filename = DATA_URL.split('/')[-1]
    filepath = os.path.join(dest_directory, filename)
    if not os.path.exists(filepath):
        def _progress(count, block_size, total_size):
            sys.stdout.write('\r>> Downloading %s %.1f%%' % (
                filename, float(count * block_size) / float(total_size) * 100.0))
            sys.stdout.flush()
        filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress)
        print()
        statinfo = os.stat(filepath)
        print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
    tarfile.open(filepath, 'r:gz').extractall(dest_directory)


def main(_):
    maybe_download_and_extract()
    image = (FLAGS.image_file if FLAGS.image_file else
             os.path.join(FLAGS.model_dir, 'cropped_panda.jpg'))
    run_inference_on_image(image)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    # classify_image_graph_def.pb:
    #   GraphDefプロトコルバッファのバイナリ表現。
    # imagenet_synset_to_human_label_map.txt:
    #   synset IDから人間が読める文字列にマップする。
    # imagenet_2012_challenge_label_map_proto.pbtxt:
    #   ラベルをsynset IDにマッピングするプロトコルバッファのテキスト表現。
    parser.add_argument(
        '--model_dir',
        type=str,
        default='/tmp/imagenet',
        help="""\
      Path to classify_image_graph_def.pb,
      imagenet_synset_to_human_label_map.txt, and
      imagenet_2012_challenge_label_map_proto.pbtxt.\
      """
    )
    parser.add_argument(
        '--image_file',
        type=str,
        default='',
        help='Absolute path to image file.'
    )
    parser.add_argument(
        '--num_top_predictions',
        type=int,
        default=5,
        help='Display this many predictions.'
    )
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.gfile.Exists tf.logging.fatal tf.gfile.GFile tf.gfile.FastGFile tf.GraphDef tf.import_graph_def tf.Session tf.app.run

Usage with the C++ API
Grace hopper.jpg
※./configureしないとbazelできない

$ git clone -b r1.4 https://github.com/tensorflow/tensorflow
$ cd tensorflow
$ curl -L "https://storage.googleapis.com/download.tensorflow.org/models/inception_v3_2016_08_28_frozen.pb.tar.gz" | tar -C tensorflow/examples/label_image/data -xz
$ cd ~
$ virtualenv --system-site-packages -p python3 null
$ source ~/null/bin/activate
(null)$ cd tensorflow
(null)$ ./configure
# Please specify the location of python. [Default is /home/tensorflow/null/bin/python]: /home/tensorflow/null/bin/python3.5
# Please input the desired Python library path to use.  Default is [/home/tensorflow/null/lib/python3.5/site-packages] リターン
# Do you wish to build TensorFlow with jemalloc as malloc support? [Y/n]: n
# Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
# Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
# Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
# Do you wish to build TensorFlow with XLA JIT support? [y/N]: n
# Do you wish to build TensorFlow with GDR support? [y/N]: n
# Do you wish to build TensorFlow with VERBS support? [y/N]: n
# Do you wish to build TensorFlow with OpenCL support? [y/N]: n
# Do you wish to build TensorFlow with CUDA support? [y/N]: n
# Do you wish to build TensorFlow with MPI support? [y/N]: n
# Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: リターン
(null)$ bazel build tensorflow/examples/label_image/...
(null)$ bazel-bin/tensorflow/examples/label_image/label_image
# military uniform (653): 0.834306
(null)$ deactivate
$ cd ~
$ rm -r \
    null \
    tensorflow

How to Retrain Inception's Final Layer for New Categories

インセプションの最終層を新しいカテゴリに再訓練する方法
Daisies.jpg
※./configureしないとbazelできない

$ git clone -b r1.4 https://github.com/tensorflow/tensorflow
$ curl -O http://download.tensorflow.org/example_images/flower_photos.tgz
$ tar xzf flower_photos.tgz
$ virtualenv --system-site-packages -p python3 retraining
$ source ~/retraining/bin/activate
(retraining)$ cd tensorflow
(retraining)$ ./configure
# Please specify the location of python. [Default is /home/tensorflow/retraining/bin/python]: /home/tensorflow/retraining/bin/python3.5
# Please input the desired Python library path to use.  Default is [/home/tensorflow/retraining/lib/python3.5/site-packages] リターン
# Do you wish to build TensorFlow with jemalloc as malloc support? [Y/n]: n
# Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
# Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
# Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
# Do you wish to build TensorFlow with XLA JIT support? [y/N]: n
# Do you wish to build TensorFlow with GDR support? [y/N]: n
# Do you wish to build TensorFlow with VERBS support? [y/N]: n
# Do you wish to build TensorFlow with OpenCL support? [y/N]: n
# Do you wish to build TensorFlow with CUDA support? [y/N]: n
# Do you wish to build TensorFlow with MPI support? [y/N]: n
# Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: リターン
(retraining)$ bazel build --config opt tensorflow/examples/image_retraining:retrain
(retraining)$ bazel-bin/tensorflow/examples/image_retraining/retrain --image_dir ~/flower_photos
# INFO:tensorflow:Final test accuracy = 90.6% (N=362)
(retraining)$ cd ~
(retraining)$ pip3 install --upgrade tensorflow
(retraining)$ tensorboard --logdir /tmp/retrain_logs
# ブラウザ http://localhost:6006
# CTRL+C
(retraining)$ deactivate
$ rm -r \
    retraining \
    tensorflow \
    flower_photos \
    flower_photos.tgz \
    /tmp/bottleneck \
    /tmp/imagenet \
    /tmp/retrain_logs \
    /tmp/output_graph.pb \
    /tmp/output_labels.txt

Other Model Architectures

$ git clone -b r1.4 https://github.com/tensorflow/tensorflow
$ curl -O http://download.tensorflow.org/example_images/flower_photos.tgz
$ tar xzf flower_photos.tgz
$ virtualenv --system-site-packages -p python3 other
$ source ~/other/bin/activate
(other)$ pip3 install --upgrade tensorflow
(other)$ cd tensorflow
(other)$ python tensorflow/examples/image_retraining/retrain.py --image_dir ~/flower_photos --architecture mobilenet_0.25_128_quantized
# INFO:tensorflow:Final test accuracy = 79.0% (N=362)
(other)$ deactivate
$ cd ~
$ rm -r \
    other \
    tensorflow \
    flower_photos \
    flower_photos.tgz \
    /tmp/bottleneck \
    /tmp/imagenet \
    /tmp/retrain_logs \
    /tmp/output_graph.pb \
    /tmp/output_labels.txt

retrain.py

"""Inception v3またはMobilenetモデルによる簡単な転送学習。

TensorBoardをサポートしています。

この例では、ImageNetイメージでトレーニングされたInception v3またはMobilenetモデルを取得し、
他のクラスのイメージを認識できる新しいトップレイヤーをトレーニングする方法を示します。

最上層は、各画像の2048次元ベクトル(Mobilenetの1001次元)を入力として受け取る。
我々は、この表現の上にソフトマックス層を訓練する。
softmax層がN個のラベルを含むと仮定すると、
これは学習されたバイアスおよび重みに対応するN + 2048 * N(または1001 * N)
モデルパラメータを学習することに対応する。

次に、クラス名の付いたサブフォルダが格納されているフォルダを想定した例を示します。
各サブフォルダには、各ラベルの画像がいっぱいです。
サンプルのフォルダflower_photosは次のような構造を持つ必要があります:

~/flower_photos/daisy/photo1.jpg
~/flower_photos/daisy/photo2.jpg
...
~/flower_photos/rose/anotherphoto77.jpg
...
~/flower_photos/sunflower/somepicture.jpg

これらのサブフォルダ名は、各画像にどのラベルが適用されるかを定義するため重要ですが、
ファイル名自体は重要ではありません。
画像が準備されたら、次のようなコマンドでトレーニングを実行できます:


```bash
bazel build tensorflow/examples/image_retraining:retrain && \
bazel-bin/tensorflow/examples/image_retraining/retrain \
    --image_dir ~/flower_photos
```

あるいは、もしあなたがTensorflowをpipでインストールしていれば、
 `retrain.py`はbazelなしで実行できます:

```bash
python tensorflow/examples/image_retraining/retrain.py \
    --image_dir ~/flower_photos
```

image_dir引数は、画像のサブフォルダを含む任意のフォルダに置き換えることができます。
各画像のラベルは、それが入っているサブフォルダの名前から取られます。

これにより、label_imageサンプルコードなど、
任意のTensorFlowプログラムによってロードおよび実行できる新しいモデルファイルが作成されます。

デフォルトでは、このスクリプトは高精度ですが、
比較的大きく、遅いInception v3モデルアーキテクチャを使用します。
良いトレーニングデータを収集したことを検証するためにこれを開始することをお勧めしますが、
リソースが限られたプラットフォームで展開する場合は、
Mobilenetモデルで `--architecture`フラグを試すことができます。 例えば:

mobilenetの浮動小数点バージョンを実行する:
```bash
python tensorflow/examples/image_retraining/retrain.py \
    --image_dir ~/flower_photos --architecture mobilenet_1.0_224
```

mobilenetの量子化されたバージョンを実行する:
```bash
python tensorflow/examples/image_retraining/retrain.py \
    --image_dir ~/flower_photos/   --architecture mobilenet_1.0_224_quantized
```

32種類のMobilenetモデルが用意されており、
さまざまなファイルサイズとレイテンシオプションが用意されています。
最初の数字は、サイズを制御するために '1.0'、 '0.75'、 '0.50'、または '0.25'になり、
2番目の数字は '224'、 '192'、 '160' 128 '、より小さいサイズの方が高速に動作します。
Mobilenetの詳細についてはこちらをご覧ください。
https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html

TensorBoardで使用するには:

デフォルトでは、このスクリプトは要約を/tmp/retrain_logsディレクトリに記録します。

次のコマンドで要約を視覚化します:

tensorboard --logdir /tmp/retrain_logs

"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
from datetime import datetime
import hashlib
import os.path
import random
import re
import sys
import tarfile

import numpy as np
from six.moves import urllib
import tensorflow as tf

from tensorflow.contrib.quantize.python import quant_ops
from tensorflow.python.framework import graph_util
from tensorflow.python.framework import tensor_shape
from tensorflow.python.platform import gfile
from tensorflow.python.util import compat

FLAGS = None

# これらはすべて、Inception v3で使用している特定のモデルアーキテクチャに関連付けられている
# すべてのパラメータです。
# これらには、テンソル名やそのサイズなどが含まれます。
# このスクリプトを別のモデルで使用するように変更する場合は、
# 使用しているネットワークの値を反映するようにこれらのスクリプトを更新する必要があります。

MAX_NUM_IMAGES_PER_CLASS = 2 ** 27 - 1  # ~134M


def create_image_lists(image_dir, testing_percentage, validation_percentage):
    """ファイルシステムからトレーニングイメージのリストを作成する

    イメージディレクトリ内のサブフォルダを分析し、安定したトレーニング、テスト、
    および検証セットに分割し、各ラベルとそのパスのイメージリストを記述するデータ構造を返します。

    Args:
      image_dir: イメージのサブフォルダを含むフォルダへの文字列パス。
      testing_percentage: テスト用に予約するイメージの整数パーセンテージ。
      validation_percentage: 検証のために予約されたイメージの整数パーセンテージ。

    Returns:
      各ラベルサブフォルダのエントリを含む辞書。
      画像は各ラベル内でトレーニング、テスト、および検証セットに分割されています。
    """
    if not gfile.Exists(image_dir):
        tf.logging.error("Image directory '" + image_dir + "' not found.")
        return None
    result = {}
    sub_dirs = [x[0] for x in gfile.Walk(image_dir)]
    # The root directory comes first, so skip it.
    is_root_dir = True
    for sub_dir in sub_dirs:
        if is_root_dir:
            is_root_dir = False
            continue
        extensions = ['jpg', 'jpeg', 'JPG', 'JPEG']
        file_list = []
        dir_name = os.path.basename(sub_dir)
        if dir_name == image_dir:
            continue
        tf.logging.info("Looking for images in '" + dir_name + "'")
        for extension in extensions:
            file_glob = os.path.join(image_dir, dir_name, '*.' + extension)
            file_list.extend(gfile.Glob(file_glob))
        if not file_list:
            tf.logging.warning('No files found')
            continue
        if len(file_list) < 20:
            tf.logging.warning(
                'WARNING: Folder has less than 20 images, which may cause issues.')
        elif len(file_list) > MAX_NUM_IMAGES_PER_CLASS:
            tf.logging.warning(
                'WARNING: Folder {} has more than {} images. Some images will '
                'never be selected.'.format(dir_name, MAX_NUM_IMAGES_PER_CLASS))
        label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower())
        training_images = []
        testing_images = []
        validation_images = []
        for file_name in file_list:
            base_name = os.path.basename(file_name)
            # ファイル名に「_nohash_」の後に何かを無視して、イメージを置くセットを決めるときは、
            # データセットの作成者は、互いに近いバリエーションの写真をグループ化する方法を持っています。
            # 例えば、これは植物病データセットで使用され、同じ葉の複数の画像をグループ化する。
            hash_name = re.sub(r'_nohash_.*$', '', file_name)
            # これはちょっと魔法のようですが、このファイルをトレーニング、テスト、
            # または検証セットに入れるかどうかを決定する必要があります。
            # その後、さらにファイルが追加されても、既存のファイルを同じセットに保存します。
            # これを行うには、ファイル名自体に基づいて安定した方法を決定する必要があります。
            # そこで、そのハッシュを行い、それを使ってそれを割り当てる確率値を生成します。
            hash_name_hashed = hashlib.sha1(
                compat.as_bytes(hash_name)).hexdigest()
            percentage_hash = ((int(hash_name_hashed, 16) %
                                (MAX_NUM_IMAGES_PER_CLASS + 1)) *
                               (100.0 / MAX_NUM_IMAGES_PER_CLASS))
            if percentage_hash < validation_percentage:
                validation_images.append(base_name)
            elif percentage_hash < (testing_percentage + validation_percentage):
                testing_images.append(base_name)
            else:
                training_images.append(base_name)
        result[label_name] = {
            'dir': dir_name,
            'training': training_images,
            'testing': testing_images,
            'validation': validation_images,
        }
    return result


def get_image_path(image_lists, label_name, index, image_dir, category):
    """"指定されたインデックスにあるラベルのイメージへのパスを返します。

    Args:
      image_lists: 各ラベルの画像をトレーニングする辞書
      label_name: イメージを取得するラベルの文字列
      index: 私たちが望むイメージのIntオフセット。
      これは、ラベルに使用可能な画像数によってモジュロされるので、任意に大きくすることができます。
      image_dir: トレーニングイメージを含むサブフォルダのルートフォルダ文字列。
      category: 画像を取り込むセットの名前文字列。トレーニング、テスト、または検証。

    Returns:
      要求されたパラメータを満たすイメージへのファイルシステムパス文字列。

    """
    if label_name not in image_lists:
        tf.logging.fatal('Label does not exist %s.', label_name)
    label_lists = image_lists[label_name]
    if category not in label_lists:
        tf.logging.fatal('Category does not exist %s.', category)
    category_list = label_lists[category]
    if not category_list:
        tf.logging.fatal('Label %s has no images in the category %s.',
                         label_name, category)
    mod_index = index % len(category_list)
    base_name = category_list[mod_index]
    sub_dir = label_lists['dir']
    full_path = os.path.join(image_dir, sub_dir, base_name)
    return full_path


def get_bottleneck_path(image_lists, label_name, index, bottleneck_dir,
                        category, architecture):
    """"指定されたインデックスにあるラベルのボトルネックファイルへのパスを返します。

    Args:
      image_lists: 各ラベルの画像をトレーニングする辞書
      label_name: イメージを取得するラベルの文字列
      index: 私たちが望むイメージの整数オフセット。
      これは、ラベルに使用可能な画像数によってモジュロされるので、任意に大きくすることができます。
      bottleneck_dir: ボトルネック値のキャッシュファイルを保持するフォルダ文字列。
      category: 画像を取り込むセットの名前文字列。トレーニング、テスト、または検証。
      architecture: モデルアーキテクチャの名前。

    Returns:
      要求されたパラメータを満たすイメージへのファイルシステムパス文字列。
    """
    return get_image_path(image_lists, label_name, index, bottleneck_dir,
                          category) + '_' + architecture + '.txt'


def create_model_graph(model_info):
    """"保存されたGraphDefファイルからグラフを作成し、Graphオブジェクトを返します。

    Args:
      model_info: モデルアーキテクチャに関する情報を含む辞書。

    Returns:
      訓練されたインセプションネットワークとさまざまなテンソルを保持したグラフを操作します。
    """
    with tf.Graph().as_default() as graph:
        model_path = os.path.join(
            FLAGS.model_dir, model_info['model_file_name'])
        print('Model path: ', model_path)
        with gfile.FastGFile(model_path, 'rb') as f:
            graph_def = tf.GraphDef()
            graph_def.ParseFromString(f.read())
            bottleneck_tensor, resized_input_tensor = (tf.import_graph_def(
                graph_def,
                name='',
                return_elements=[
                    model_info['bottleneck_tensor_name'],
                    model_info['resized_input_tensor_name'],
                ]))
    return graph, bottleneck_tensor, resized_input_tensor


def run_bottleneck_on_image(sess, image_data, image_data_tensor,
                            decoded_image_tensor, resized_input_tensor,
                            bottleneck_tensor):
    """画像上の推論を実行して、「ボトルネック」サマリー・レイヤーを抽出します。

    Args:
      sess: 現在アクティブなTensorFlowセッション。
      image_data: 生のJPEGデータの文字列。
      image_data_tensor: グラフにデータレイヤーを入力します。
      decoded_image_tensor: 初期画像のサイズ変更と前処理の出力。
      resized_input_tensor: 認識グラフの入力ノード。
      bottleneck_tensor: 最終的なソフトマックスの前のレイヤー。

    Returns:
      ボトルネック値のNumpy配列
    """
    # 最初にJPEG画像をデコードし、サイズを変更し、ピクセル値を再スケーリングします。
    resized_input_values = sess.run(decoded_image_tensor,
                                    {image_data_tensor: image_data})
    # 認識ネットワークを介して実行します。
    bottleneck_values = sess.run(bottleneck_tensor,
                                 {resized_input_tensor: resized_input_values})
    bottleneck_values = np.squeeze(bottleneck_values)
    return bottleneck_values


def maybe_download_and_extract(data_url):
    """モデルのtarファイルをダウンロードして抽出します。

    使用しているプレトレーニングされたモデルがまだ存在しない場合、
    この関数はTensorFlow.orgのWebサイトからダウンロードし、ディレクトリに展開します。

    Args:
      data_url: pretrainedモデルを含むtarファイルのWebロケーション。
    """
    dest_directory = FLAGS.model_dir
    if not os.path.exists(dest_directory):
        os.makedirs(dest_directory)
    filename = data_url.split('/')[-1]
    filepath = os.path.join(dest_directory, filename)
    if not os.path.exists(filepath):

        def _progress(count, block_size, total_size):
            sys.stdout.write('\r>> Downloading %s %.1f%%' %
                             (filename,
                              float(count * block_size) / float(total_size) * 100.0))
            sys.stdout.flush()

        filepath, _ = urllib.request.urlretrieve(data_url, filepath, _progress)
        print()
        statinfo = os.stat(filepath)
        tf.logging.info('Successfully downloaded', filename, statinfo.st_size,
                        'bytes.')
        print('Extracting file from ', filepath)
        tarfile.open(filepath, 'r:gz').extractall(dest_directory)
    else:
        print('Not extracting or downloading files, model already present in disk')


def ensure_dir_exists(dir_name):
    """フォルダがディスク上に存在することを確認します。

    Args:
      dir_name: 作成するフォルダへのパス文字列。
    """
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)


bottleneck_path_2_bottleneck_values = {}


def create_bottleneck_file(bottleneck_path, image_lists, label_name, index,
                           image_dir, category, sess, jpeg_data_tensor,
                           decoded_image_tensor, resized_input_tensor,
                           bottleneck_tensor):
    """単一のボトルネックファイルを作成します。"""
    tf.logging.info('Creating bottleneck at ' + bottleneck_path)
    image_path = get_image_path(image_lists, label_name, index,
                                image_dir, category)
    if not gfile.Exists(image_path):
        tf.logging.fatal('File does not exist %s', image_path)
    image_data = gfile.FastGFile(image_path, 'rb').read()
    try:
        bottleneck_values = run_bottleneck_on_image(
            sess, image_data, jpeg_data_tensor, decoded_image_tensor,
            resized_input_tensor, bottleneck_tensor)
    except Exception as e:
        raise RuntimeError('Error during processing file %s (%s)' % (image_path,
                                                                     str(e)))
    bottleneck_string = ','.join(str(x) for x in bottleneck_values)
    with open(bottleneck_path, 'w') as bottleneck_file:
        bottleneck_file.write(bottleneck_string)


def get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir,
                             category, bottleneck_dir, jpeg_data_tensor,
                             decoded_image_tensor, resized_input_tensor,
                             bottleneck_tensor, architecture):
    """イメージのボトルネック値を取得または計算します。

    キャッシュされたバージョンのボトルネックデータがディスク上に存在する場合は、
    そのデータを返し、そうでなければデータを計算し、将来の使用のためにディスクに保存します。

    Args:
      sess: 現在アクティブなTensorFlowセッション。
      image_lists: 各ラベルの画像をトレーニングする辞書。
      label_name: イメージを取得するラベルの文字列。
      index: 私たちが望むイメージの整数オフセット。
      これは、ラベルに使用可能な画像数によってモジュロされるので、任意に大きくすることができます。
      image_dir: トレーニングイメージを含むサブフォルダのルートフォルダ文字列。
      category: 画像を取り込むために設定された名前文字列。トレーニング、テスト、または検証。
      bottleneck_dir: ボトルネック値のキャッシュファイルを保持するフォルダ文字列。
      jpeg_data_tensor: ロードされたjpegデータを供給するテンソル。
      decoded_image_tensor: 画像のデコードとサイズ変更の出力。
      resized_input_tensor: 認識グラフの入力ノード。
      bottleneck_tensor: ボトルネック値の出力テンソル。
      architecture: モデルアーキテクチャの名前。

    Returns:
      画像のボトルネックレイヤーによって生成された値のNumpy配列
    """
    label_lists = image_lists[label_name]
    sub_dir = label_lists['dir']
    sub_dir_path = os.path.join(bottleneck_dir, sub_dir)
    ensure_dir_exists(sub_dir_path)
    bottleneck_path = get_bottleneck_path(image_lists, label_name, index,
                                          bottleneck_dir, category, architecture)
    if not os.path.exists(bottleneck_path):
        create_bottleneck_file(bottleneck_path, image_lists, label_name, index,
                               image_dir, category, sess, jpeg_data_tensor,
                               decoded_image_tensor, resized_input_tensor,
                               bottleneck_tensor)
    with open(bottleneck_path, 'r') as bottleneck_file:
        bottleneck_string = bottleneck_file.read()
    did_hit_error = False
    try:
        bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
    except ValueError:
        tf.logging.warning('Invalid float found, recreating bottleneck')
        did_hit_error = True
    if did_hit_error:
        create_bottleneck_file(bottleneck_path, image_lists, label_name, index,
                               image_dir, category, sess, jpeg_data_tensor,
                               decoded_image_tensor, resized_input_tensor,
                               bottleneck_tensor)
        with open(bottleneck_path, 'r') as bottleneck_file:
            bottleneck_string = bottleneck_file.read()
        # 新しく作成した後では発生しないので、例外をここに伝播できるようにする
        bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
    return bottleneck_values


def cache_bottlenecks(sess, image_lists, image_dir, bottleneck_dir,
                      jpeg_data_tensor, decoded_image_tensor,
                      resized_input_tensor, bottleneck_tensor, architecture):
    """すべてのトレーニング、テスト、および検証のボトルネックがキャッシュされるようにします。

    同じ画像を複数回読み取る可能性が高いため(トレーニング中に歪みが適用されていない場合)、
    前処理中にボトルネックレイヤの値を各画像ごとに1回計算してから、
    それらのキャッシュ値 トレーニング中に繰り返し。
    ここでは、見つけたすべての画像を調べ、それらの値を計算し、それらを保存します。

    Args:
      sess: 現在アクティブなTensorFlowセッション。
      image_lists: 各ラベルの画像をトレーニングする辞書。
      image_dir: トレーニングイメージを含むサブフォルダのルートフォルダ文字列。
      bottleneck_dir: ボトルネック値のキャッシュファイルを保持するフォルダ文字列。
      jpeg_data_tensor: ファイルからjpegデータのテンソルを入力します。
      decoded_image_tensor: 画像のデコードとサイズ変更の出力。
      resized_input_tensor: 認識グラフの入力ノード。
      bottleneck_tensor: グラフの最後から2番目の出力層。
      architecture: モデルアーキテクチャの名前。

    Returns:
      何もない。
    """
    how_many_bottlenecks = 0
    ensure_dir_exists(bottleneck_dir)
    for label_name, label_lists in image_lists.items():
        for category in ['training', 'testing', 'validation']:
            category_list = label_lists[category]
            for index, unused_base_name in enumerate(category_list):
                get_or_create_bottleneck(
                    sess, image_lists, label_name, index, image_dir, category,
                    bottleneck_dir, jpeg_data_tensor, decoded_image_tensor,
                    resized_input_tensor, bottleneck_tensor, architecture)

                how_many_bottlenecks += 1
                if how_many_bottlenecks % 100 == 0:
                    tf.logging.info(
                        str(how_many_bottlenecks) + ' bottleneck files created.')


def get_random_cached_bottlenecks(sess, image_lists, how_many, category,
                                  bottleneck_dir, image_dir, jpeg_data_tensor,
                                  decoded_image_tensor, resized_input_tensor,
                                  bottleneck_tensor, architecture):
    """キャッシュされたイメージのボトルネック値を取得します。

    歪みが適用されていない場合、
    この関数はキャッシュされたボトルネック値をディスクから直接イメージで取り出すことができます。
    指定されたカテゴリから画像のランダムなセットを選択します。

    Args:
      sess: 現在のTensorFlowセッション。
      image_lists: 各ラベルの画像をトレーニングする辞書。
      how_many: 正の場合は、このサイズのランダムサンプルが選択されます。
      負の場合、すべてのボトルネックが検索されます。
      category: トレーニング、テスト、または検証から引き出す名前の文字列。
      bottleneck_dir: ボトルネック値のキャッシュファイルを保持するフォルダ文字列。
      image_dir: トレーニングイメージを含むサブフォルダのルートフォルダ文字列。
      jpeg_data_tensor: jpeg画像データを供給するレイヤー。
      decoded_image_tensor: 画像のデコードとサイズ変更の出力。
      resized_input_tensor: 認識グラフの入力ノード。
      bottleneck_tensor: CNNグラフのボトルネック出力層。
      architecture: モデルアーキテクチャの名前。

    Returns:
      ボトルネックアレイのリスト、対応するグランド真理、および関連するファイル名。
    """
    class_count = len(image_lists.keys())
    bottlenecks = []
    ground_truths = []
    filenames = []
    if how_many >= 0:
        # ボトルネックのランダムサンプルを取得します。
        for unused_i in range(how_many):
            label_index = random.randrange(class_count)
            label_name = list(image_lists.keys())[label_index]
            image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1)
            image_name = get_image_path(image_lists, label_name, image_index,
                                        image_dir, category)
            bottleneck = get_or_create_bottleneck(
                sess, image_lists, label_name, image_index, image_dir, category,
                bottleneck_dir, jpeg_data_tensor, decoded_image_tensor,
                resized_input_tensor, bottleneck_tensor, architecture)
            bottlenecks.append(bottleneck)
            ground_truths.append(label_index)
            filenames.append(image_name)
    else:
        # すべてのボトルネックを取得します。
        for label_index, label_name in enumerate(image_lists.keys()):
            for image_index, image_name in enumerate(
                    image_lists[label_name][category]):
                image_name = get_image_path(image_lists, label_name, image_index,
                                            image_dir, category)
                bottleneck = get_or_create_bottleneck(
                    sess, image_lists, label_name, image_index, image_dir, category,
                    bottleneck_dir, jpeg_data_tensor, decoded_image_tensor,
                    resized_input_tensor, bottleneck_tensor, architecture)
                bottlenecks.append(bottleneck)
                ground_truths.append(label_index)
                filenames.append(image_name)
    return bottlenecks, ground_truths, filenames


def get_random_distorted_bottlenecks(
        sess, image_lists, how_many, category, image_dir, input_jpeg_tensor,
        distorted_image, resized_input_tensor, bottleneck_tensor):
    """ひずみの後、トレーニング画像のボトルネック値を取得します。

    作物、スケール、フリップなどの歪みを訓練している場合は、
    すべての画像のフルモデルを再計算する必要があります。
    そのため、キャッシュされたボトルネック値を使用することはできません。
    その代わりに、要求されたカテゴリのランダムな画像を見つけ、
    ディストーション・グラフを介して実行し、次にフル・グラフを実行して、
    それぞれのボトルネックの結果を取得します。

    Args:
      sess: 現在のTensorFlowセッション。
      image_lists: 各ラベルの画像をトレーニングする辞書。
      how_many: 返す整数のボトルネック値。
      category: フェッチする一連のイメージ(トレーニング、テスト、または検証)の名前文字列。
      image_dir: トレーニングイメージを含むサブフォルダのルートフォルダ文字列。
      input_jpeg_tensor: 入力層は画像データを送ります。
      distorted_image: 歪みグラフの出力ノード。
      resized_input_tensor: 認識グラフの入力ノード。
      bottleneck_tensor: CNNグラフのボトルネック出力層。

    Returns:
      ボトルネックアレイとそれに対応するグランド真理のリスト
    """
    class_count = len(image_lists.keys())
    bottlenecks = []
    ground_truths = []
    for unused_i in range(how_many):
        label_index = random.randrange(class_count)
        label_name = list(image_lists.keys())[label_index]
        image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1)
        image_path = get_image_path(image_lists, label_name, image_index, image_dir,
                                    category)
        if not gfile.Exists(image_path):
            tf.logging.fatal('File does not exist %s', image_path)
        jpeg_data = gfile.FastGFile(image_path, 'rb').read()
        # 画像上で実行中の推論を送る前に、distorted_image_dataをnumpy配列として
        # 実現することに注意してください。
        # これには2つのメモリコピーが含まれ、他の実装では最適化される可能性があります。
        distorted_image_data = sess.run(distorted_image,
                                        {input_jpeg_tensor: jpeg_data})
        bottleneck_values = sess.run(bottleneck_tensor,
                                     {resized_input_tensor: distorted_image_data})
        bottleneck_values = np.squeeze(bottleneck_values)
        bottlenecks.append(bottleneck_values)
        ground_truths.append(label_index)
    return bottlenecks, ground_truths


def should_distort_images(flip_left_right, random_crop, random_scale,
                          random_brightness):
    """入力フラグから歪みが有効かどうか。

    Args:
      flip_left_right: イメージを水平方向にランダムにミラーリングするかどうかを指定します。
      random_crop: クロップボックスの周りで使用される合計マージンを設定する整数パーセンテージ。
      random_scale: スケールをどの程度変えるかの整数パーセンテージ。
      random_brightness: ピクセル値をランダムに掛ける整数の範囲。

    Returns:
      歪みを適用するかどうかを示すブール値。
    """
    return (flip_left_right or (random_crop != 0) or (random_scale != 0) or
            (random_brightness != 0))


def add_input_distortions(flip_left_right, random_crop, random_scale,
                          random_brightness, input_width, input_height,
                          input_depth, input_mean, input_std):
    """指定された歪みを適用する操作を作成します。

    トレーニング中は、作物、鱗、フリップのような単純な歪みによって画像を実行すると、
    結果を改善するのに役立ちます。
    これらは現実の世界で期待される種類の変化を反映しているので、
    自然なデータに効果的に対処するためにモデルを訓練するのに役立ちます。
    ここでは、提供されたパラメータを取得し、それらを画像に適用する操作のネットワークを構築します。

    クロッピング
    ~~~~~~~~

    クロッピングは、イメージ全体のランダムな位置にバウンディングボックスを配置することによって行われます。
    クロッピングパラメータは、入力画像に対するボックスのサイズを制御します。
    ゼロの場合、ボックスは入力と同じサイズであり、トリミングは実行されません。
    値が50%の場合、クロップボックスは入力の幅と高さの半分になります。
    ダイアグラムでは次のようになります。

    <       width         >
    +---------------------+
    |                     |
    |   width - crop%     |
    |    <      >         |
    |    +------+         |
    |    |      |         |
    |    |      |         |
    |    |      |         |
    |    +------+         |
    |                     |
    |                     |
    +---------------------+

    スケーリング
    ~~~~~~~

    スケーリングは、境界ボックスが常に中央に配置され、
    そのサイズが与えられた範囲内でランダムに変化する点を除いてクロッピングのようなものです。
    たとえば、スケール率がゼロの場合、境界ボックスは入力と同じサイズで、スケーリングは適用されません。
    それが50%の場合、バウンディングボックスは、幅と高さの半分とフルサイズの間のランダムな範囲になります。

    Args:
      flip_left_right: イメージを水平方向にランダムにミラーリングするかどうかを指定します。
      random_crop: クロップボックスの周りで使用される合計マージンを設定する整数パーセンテージ。
      random_scale: スケールをどの程度変えるかの整数パーセンテージ。
      random_brightness: ピクセル値を無作為にグラフで掛ける整数の範囲。
      input_width: モデル化する予定の入力イメージの水平サイズ。
      input_height: モデル化する予定の入力イメージの垂直サイズ。
      input_depth: 予想される入力イメージが持つべきチャンネル数。
      input_mean: グラフの画像内でゼロでなければならないピクセル値。
      input_std: 認識前にピクセル値をどのくらい分割するか。

    Returns:
      jpeg入力レイヤーと歪んだ結果のテンソル。
    """

    jpeg_data = tf.placeholder(tf.string, name='DistortJPGInput')
    decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth)
    decoded_image_as_float = tf.cast(decoded_image, dtype=tf.float32)
    decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
    margin_scale = 1.0 + (random_crop / 100.0)
    resize_scale = 1.0 + (random_scale / 100.0)
    margin_scale_value = tf.constant(margin_scale)
    resize_scale_value = tf.random_uniform(tensor_shape.scalar(),
                                           minval=1.0,
                                           maxval=resize_scale)
    scale_value = tf.multiply(margin_scale_value, resize_scale_value)
    precrop_width = tf.multiply(scale_value, input_width)
    precrop_height = tf.multiply(scale_value, input_height)
    precrop_shape = tf.stack([precrop_height, precrop_width])
    precrop_shape_as_int = tf.cast(precrop_shape, dtype=tf.int32)
    precropped_image = tf.image.resize_bilinear(decoded_image_4d,
                                                precrop_shape_as_int)
    precropped_image_3d = tf.squeeze(precropped_image, squeeze_dims=[0])
    cropped_image = tf.random_crop(precropped_image_3d,
                                   [input_height, input_width, input_depth])
    if flip_left_right:
        flipped_image = tf.image.random_flip_left_right(cropped_image)
    else:
        flipped_image = cropped_image
    brightness_min = 1.0 - (random_brightness / 100.0)
    brightness_max = 1.0 + (random_brightness / 100.0)
    brightness_value = tf.random_uniform(tensor_shape.scalar(),
                                         minval=brightness_min,
                                         maxval=brightness_max)
    brightened_image = tf.multiply(flipped_image, brightness_value)
    offset_image = tf.subtract(brightened_image, input_mean)
    mul_image = tf.multiply(offset_image, 1.0 / input_std)
    distort_result = tf.expand_dims(mul_image, 0, name='DistortResult')
    return jpeg_data, distort_result


def variable_summaries(var):
    """テンソル(TensorBoardビジュアライゼーション用)に多くの要約を添付します。"""
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean', mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev', stddev)
        tf.summary.scalar('max', tf.reduce_max(var))
        tf.summary.scalar('min', tf.reduce_min(var))
        tf.summary.histogram('histogram', var)


def add_final_training_ops(class_count, final_tensor_name, bottleneck_tensor,
                           bottleneck_tensor_size, quantize_layer):
    """トレーニング用に新しいsoftmaxと完全に接続されたレイヤーを追加します。

    新しいクラスを識別するために最上位レイヤを再テストする必要があるため、
    この関数はグラフに適切な操作を加え、重みを保持するいくつかの変数を追加し、
    後方パスのすべての勾配を設定します。

    ソフトマックスと完全に接続されたレイヤの設定は、次の項目に基づいています。
    https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/index.html

    Args:
      class_count: 私たちが認識しようとしているもののカテゴリの数。
      final_tensor_name: 結果を生成する新しい最終ノードの名前文字列。
      bottleneck_tensor: メインCNNグラフの出力。
      bottleneck_tensor_size: ボトルネックベクトルのエントリ数。
      quantize_layer: 新しいレイヤーを量子化するかどうかを指定するブール値。

    Returns:
      トレーニングとクロスエントロピーの結果のテンソルと、
      ボトルネック入力とグランドトゥルース入力のテンソル。
    """
    with tf.name_scope('input'):
        bottleneck_input = tf.placeholder_with_default(
            bottleneck_tensor,
            shape=[None, bottleneck_tensor_size],
            name='BottleneckInputPlaceholder')

        ground_truth_input = tf.placeholder(
            tf.int64, [None], name='GroundTruthInput')

    # 次の作業を `final_training_ops`として整理することで、TensorBoardで見やすくなります。
    layer_name = 'final_training_ops'
    with tf.name_scope(layer_name):
        with tf.name_scope('weights'):
            initial_value = tf.truncated_normal(
                [bottleneck_tensor_size, class_count], stddev=0.001)
            layer_weights = tf.Variable(initial_value, name='final_weights')
            if quantize_layer:
                quantized_layer_weights = quant_ops.MovingAvgQuantize(
                    layer_weights, is_training=True)
                variable_summaries(quantized_layer_weights)

            variable_summaries(layer_weights)
        with tf.name_scope('biases'):
            layer_biases = tf.Variable(
                tf.zeros([class_count]), name='final_biases')
            if quantize_layer:
                quantized_layer_biases = quant_ops.MovingAvgQuantize(
                    layer_biases, is_training=True)
                variable_summaries(quantized_layer_biases)

            variable_summaries(layer_biases)

        with tf.name_scope('Wx_plus_b'):
            if quantize_layer:
                logits = tf.matmul(bottleneck_input,
                                   quantized_layer_weights) + quantized_layer_biases
                logits = quant_ops.MovingAvgQuantize(
                    logits,
                    init_min=-32.0,
                    init_max=32.0,
                    is_training=True,
                    num_bits=8,
                    narrow_range=False,
                    ema_decay=0.5)
                tf.summary.histogram('pre_activations', logits)
            else:
                logits = tf.matmul(
                    bottleneck_input, layer_weights) + layer_biases
                tf.summary.histogram('pre_activations', logits)

    final_tensor = tf.nn.softmax(logits, name=final_tensor_name)

    tf.summary.histogram('activations', final_tensor)

    with tf.name_scope('cross_entropy'):
        cross_entropy_mean = tf.losses.sparse_softmax_cross_entropy(
            labels=ground_truth_input, logits=logits)

    tf.summary.scalar('cross_entropy', cross_entropy_mean)

    with tf.name_scope('train'):
        optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)
        train_step = optimizer.minimize(cross_entropy_mean)

    return (train_step, cross_entropy_mean, bottleneck_input, ground_truth_input,
            final_tensor)


def add_evaluation_step(result_tensor, ground_truth_tensor):
    """結果の正確さを評価するために必要な操作を挿入します。

    Args:
      result_tensor: 結果を生成する新しい最終ノード。
      ground_truth_tensor: ノードは真理値データを与えます。

    Returns:
      タプル(評価ステップ、予測)。
    """
    with tf.name_scope('accuracy'):
        with tf.name_scope('correct_prediction'):
            prediction = tf.argmax(result_tensor, 1)
            correct_prediction = tf.equal(prediction, ground_truth_tensor)
        with tf.name_scope('accuracy'):
            evaluation_step = tf.reduce_mean(
                tf.cast(correct_prediction, tf.float32))
    tf.summary.scalar('accuracy', evaluation_step)
    return evaluation_step, prediction


def save_graph_to_file(sess, graph, graph_file_name):
    output_graph_def = graph_util.convert_variables_to_constants(
        sess, graph.as_graph_def(), [FLAGS.final_tensor_name])

    with gfile.FastGFile(graph_file_name, 'wb') as f:
        f.write(output_graph_def.SerializeToString())
    return


def prepare_file_system():
    # TensorBoardのサマリーを書き込むディレクトリを設定する
    if tf.gfile.Exists(FLAGS.summaries_dir):
        tf.gfile.DeleteRecursively(FLAGS.summaries_dir)
    tf.gfile.MakeDirs(FLAGS.summaries_dir)
    if FLAGS.intermediate_store_frequency > 0:
        ensure_dir_exists(FLAGS.intermediate_output_graphs_dir)
    return


def create_model_info(architecture):
    """モデルアーキテクチャの名前が与えられると、それに関する情報が返されます。

    転送学習を使用して再学習できるさまざまなベースイメージ認識事前トレーニングモデルがあります。
    この機能は、モデルの名前からダウンロードしてトレーニングするために必要な属性に変換されます。

    Args:
      architecture: モデルアーキテクチャの名前。

    Returns:
      モデルに関する情報の辞書。または名前が認識されない場合はNone

    Raises:
      ValueError: アーキテクチャ名が不明な場合
    """
    architecture = architecture.lower()
    is_quantized = False
    if architecture == 'inception_v3':
        # pylint: disable=line-too-long
        data_url = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
        # pylint: enable=line-too-long
        bottleneck_tensor_name = 'pool_3/_reshape:0'
        bottleneck_tensor_size = 2048
        input_width = 299
        input_height = 299
        input_depth = 3
        resized_input_tensor_name = 'Mul:0'
        model_file_name = 'classify_image_graph_def.pb'
        input_mean = 128
        input_std = 128
    elif architecture.startswith('mobilenet_'):
        parts = architecture.split('_')
        if len(parts) != 3 and len(parts) != 4:
            tf.logging.error("Couldn't understand architecture name '%s'",
                             architecture)
            return None
        version_string = parts[1]
        if (version_string != '1.0' and version_string != '0.75' and
                version_string != '0.50' and version_string != '0.25'):
            tf.logging.error(
                """"The Mobilenet version should be '1.0', '0.75', '0.50', or '0.25',
  but found '%s' for architecture '%s'""",
                version_string, architecture)
            return None
        size_string = parts[2]
        if (size_string != '224' and size_string != '192' and
                size_string != '160' and size_string != '128'):
            tf.logging.error(
                """The Mobilenet input size should be '224', '192', '160', or '128',
 but found '%s' for architecture '%s'""",
                size_string, architecture)
            return None
        if len(parts) == 3:
            is_quantized = False
        else:
            if parts[3] != 'quantized':
                tf.logging.error(
                    "Couldn't understand architecture suffix '%s' for '%s'", parts[3],
                    architecture)
                return None
            is_quantized = True

        if is_quantized:
            data_url = 'http://download.tensorflow.org/models/mobilenet_v1_'
            data_url += version_string + '_' + size_string + '_quantized_frozen.tgz'
            bottleneck_tensor_name = 'MobilenetV1/Predictions/Reshape:0'
            resized_input_tensor_name = 'Placeholder:0'
            model_dir_name = ('mobilenet_v1_' + version_string + '_' + size_string +
                              '_quantized_frozen')
            model_base_name = 'quantized_frozen_graph.pb'

        else:
            data_url = 'http://download.tensorflow.org/models/mobilenet_v1_'
            data_url += version_string + '_' + size_string + '_frozen.tgz'
            bottleneck_tensor_name = 'MobilenetV1/Predictions/Reshape:0'
            resized_input_tensor_name = 'input:0'
            model_dir_name = 'mobilenet_v1_' + version_string + '_' + size_string
            model_base_name = 'frozen_graph.pb'

        bottleneck_tensor_size = 1001
        input_width = int(size_string)
        input_height = int(size_string)
        input_depth = 3
        model_file_name = os.path.join(model_dir_name, model_base_name)
        input_mean = 127.5
        input_std = 127.5
    else:
        tf.logging.error(
            "Couldn't understand architecture name '%s'", architecture)
        raise ValueError('Unknown architecture', architecture)

    return {
        'data_url': data_url,
        'bottleneck_tensor_name': bottleneck_tensor_name,
        'bottleneck_tensor_size': bottleneck_tensor_size,
        'input_width': input_width,
        'input_height': input_height,
        'input_depth': input_depth,
        'resized_input_tensor_name': resized_input_tensor_name,
        'model_file_name': model_file_name,
        'input_mean': input_mean,
        'input_std': input_std,
        'quantize_layer': is_quantized,
    }


def add_jpeg_decoding(input_width, input_height, input_depth, input_mean,
                      input_std):
    """JPEGデコードとサイズ変更を行う操作をグラフに追加します。

    Args:
      input_width: 認識グラフに入力される画像の希望の幅。
      input_height: 認識グラフに入力される画像の希望の幅。
      input_depth: レコグナイザグラフに供給される画像の所望のチャンネル。
      input_mean: グラフの画像内でゼロでなければならないピクセル値。
      input_std: 認識前にピクセル値をどのくらい分割するか。

    Returns:
      ノードがJPEGデータを供給するためのテンソル、および前処理ステップの出力。
    """
    jpeg_data = tf.placeholder(tf.string, name='DecodeJPGInput')
    decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth)
    decoded_image_as_float = tf.cast(decoded_image, dtype=tf.float32)
    decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
    resize_shape = tf.stack([input_height, input_width])
    resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
    resized_image = tf.image.resize_bilinear(decoded_image_4d,
                                             resize_shape_as_int)
    offset_image = tf.subtract(resized_image, input_mean)
    mul_image = tf.multiply(offset_image, 1.0 / input_std)
    return jpeg_data, mul_image


def main(_):
    # ロギング出力が見えるようにする必要があります。
    # See https://github.com/tensorflow/tensorflow/issues/3047
    tf.logging.set_verbosity(tf.logging.INFO)

    # トレーニング中に使用できる必要なディレクトリを準備する
    prepare_file_system()

    # 使用するモデルアーキテクチャに関する情報を収集します。
    model_info = create_model_info(FLAGS.architecture)
    if not model_info:
        tf.logging.error('Did not recognize architecture flag')
        return -1

    # 事前に訓練されたグラフを設定します。
    maybe_download_and_extract(model_info['data_url'])
    graph, bottleneck_tensor, resized_image_tensor = (
        create_model_graph(model_info))

    # フォルダ構造を見て、すべての画像のリストを作成します。
    image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage,
                                     FLAGS.validation_percentage)
    class_count = len(image_lists.keys())
    if class_count == 0:
        tf.logging.error(
            'No valid folders of images found at ' + FLAGS.image_dir)
        return -1
    if class_count == 1:
        tf.logging.error('Only one valid folder of images found at ' +
                         FLAGS.image_dir +
                         ' - multiple classes are needed for classification.')
        return -1

    # コマンドラインフラグによって歪みが適用されているかどうかを確認してください。
    do_distort_images = should_distort_images(
        FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale,
        FLAGS.random_brightness)

    with tf.Session(graph=graph) as sess:
        # 画像デコードサブグラフを設定します。
        jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(
            model_info['input_width'], model_info['input_height'],
            model_info['input_depth'], model_info['input_mean'],
            model_info['input_std'])

        if do_distort_images:
            # ひずみを適用するので、必要な操作を設定します。
            (distorted_jpeg_data_tensor,
             distorted_image_tensor) = add_input_distortions(
                 FLAGS.flip_left_right, FLAGS.random_crop, FLAGS.random_scale,
                 FLAGS.random_brightness, model_info['input_width'],
                 model_info['input_height'], model_info['input_depth'],
                 model_info['input_mean'], model_info['input_std'])
        else:
            # 「ボトルネック」の画像サマリーを計算してディスク上にキャッシュしていることを確認します。
            cache_bottlenecks(sess, image_lists, FLAGS.image_dir,
                              FLAGS.bottleneck_dir, jpeg_data_tensor,
                              decoded_image_tensor, resized_image_tensor,
                              bottleneck_tensor, FLAGS.architecture)

        # トレーニングする新しいレイヤーを追加します。
        (train_step, cross_entropy, bottleneck_input, ground_truth_input,
         final_tensor) = add_final_training_ops(
             len(image_lists.keys()), FLAGS.final_tensor_name, bottleneck_tensor,
             model_info['bottleneck_tensor_size'], model_info['quantize_layer'])

        # 新しいレイヤの精度を評価するために必要な操作を作成します。
        evaluation_step, prediction = add_evaluation_step(
            final_tensor, ground_truth_input)

        # すべての要約をマージしてsummaries_dirに書き出します。
        merged = tf.summary.merge_all()
        train_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/train',
                                             sess.graph)

        validation_writer = tf.summary.FileWriter(
            FLAGS.summaries_dir + '/validation')

        # すべての重みを初期のデフォルト値に設定します。
        init = tf.global_variables_initializer()
        sess.run(init)

        # コマンドラインで要求された回数だけトレーニングを実行します。
        for i in range(FLAGS.how_many_training_steps):
            # 入力ボトルネック値のバッチを取得します。入力ボトルネック値は、
            # 毎回新しく計算された歪みや、ディスクに保存されたキャッシュから計算されます。
            if do_distort_images:
                (train_bottlenecks,
                 train_ground_truth) = get_random_distorted_bottlenecks(
                     sess, image_lists, FLAGS.train_batch_size, 'training',
                     FLAGS.image_dir, distorted_jpeg_data_tensor,
                     distorted_image_tensor, resized_image_tensor, bottleneck_tensor)
            else:
                (train_bottlenecks,
                 train_ground_truth, _) = get_random_cached_bottlenecks(
                     sess, image_lists, FLAGS.train_batch_size, 'training',
                     FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor,
                     decoded_image_tensor, resized_image_tensor, bottleneck_tensor,
                     FLAGS.architecture)
            # ボトルネックとグラウンドトゥルーをグラフに送り、トレーニングステップを実行します。
            # TensorBoardの訓練要約を「結合された」操作で取り込みます。
            train_summary, _ = sess.run(
                [merged, train_step],
                feed_dict={bottleneck_input: train_bottlenecks,
                           ground_truth_input: train_ground_truth})
            train_writer.add_summary(train_summary, i)

            # 時々グラフがどれくらいうまく訓練されているかを表示する。
            is_last_step = (i + 1 == FLAGS.how_many_training_steps)
            if (i % FLAGS.eval_step_interval) == 0 or is_last_step:
                train_accuracy, cross_entropy_value = sess.run(
                    [evaluation_step, cross_entropy],
                    feed_dict={bottleneck_input: train_bottlenecks,
                               ground_truth_input: train_ground_truth})
                tf.logging.info('%s: Step %d: Train accuracy = %.1f%%' %
                                (datetime.now(), i, train_accuracy * 100))
                tf.logging.info('%s: Step %d: Cross entropy = %f' %
                                (datetime.now(), i, cross_entropy_value))
                validation_bottlenecks, validation_ground_truth, _ = (
                    get_random_cached_bottlenecks(
                        sess, image_lists, FLAGS.validation_batch_size, 'validation',
                        FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor,
                        decoded_image_tensor, resized_image_tensor, bottleneck_tensor,
                        FLAGS.architecture))
                # バリデーションステップを実行し、TensorBoardのトレーニング概要を `merged` opで取得します。
                validation_summary, validation_accuracy = sess.run(
                    [merged, evaluation_step],
                    feed_dict={bottleneck_input: validation_bottlenecks,
                               ground_truth_input: validation_ground_truth})
                validation_writer.add_summary(validation_summary, i)
                tf.logging.info('%s: Step %d: Validation accuracy = %.1f%% (N=%d)' %
                                (datetime.now(), i, validation_accuracy * 100,
                                 len(validation_bottlenecks)))

            # 中間結果を保存する
            intermediate_frequency = FLAGS.intermediate_store_frequency

            if (intermediate_frequency > 0 and (i % intermediate_frequency == 0)
                    and i > 0):
                intermediate_file_name = (FLAGS.intermediate_output_graphs_dir +
                                          'intermediate_' + str(i) + '.pb')
                tf.logging.info('Save intermediate result to : ' +
                                intermediate_file_name)
                save_graph_to_file(sess, graph, intermediate_file_name)

        # すべてのトレーニングを完了しました。
        # 以前使用していなかったいくつかの新しい画像について、最終的なテスト評価を行います。
        test_bottlenecks, test_ground_truth, test_filenames = (
            get_random_cached_bottlenecks(
                sess, image_lists, FLAGS.test_batch_size, 'testing',
                FLAGS.bottleneck_dir, FLAGS.image_dir, jpeg_data_tensor,
                decoded_image_tensor, resized_image_tensor, bottleneck_tensor,
                FLAGS.architecture))
        test_accuracy, predictions = sess.run(
            [evaluation_step, prediction],
            feed_dict={bottleneck_input: test_bottlenecks,
                       ground_truth_input: test_ground_truth})
        tf.logging.info('Final test accuracy = %.1f%% (N=%d)' %
                        (test_accuracy * 100, len(test_bottlenecks)))

        if FLAGS.print_misclassified_test_images:
            tf.logging.info('=== MISCLASSIFIED TEST IMAGES ===')
            for i, test_filename in enumerate(test_filenames):
                if predictions[i] != test_ground_truth[i]:
                    tf.logging.info('%70s  %s' %
                                    (test_filename,
                                     list(image_lists.keys())[predictions[i]]))

        # 訓練されたグラフとラベルを、定数として記憶された重みで書き出します。
        save_graph_to_file(sess, graph, FLAGS.output_graph)
        with gfile.FastGFile(FLAGS.output_labels, 'w') as f:
            f.write('\n'.join(image_lists.keys()) + '\n')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--image_dir',
        type=str,
        default='',
        help='Path to folders of labeled images.'
    )
    parser.add_argument(
        '--output_graph',
        type=str,
        default='/tmp/output_graph.pb',
        help='Where to save the trained graph.'
    )
    parser.add_argument(
        '--intermediate_output_graphs_dir',
        type=str,
        default='/tmp/intermediate_graph/',
        help='Where to save the intermediate graphs.'
    )
    parser.add_argument(
        '--intermediate_store_frequency',
        type=int,
        default=0,
        help="""\
         How many steps to store intermediate graph. If "0" then will not
         store.\
      """
    )
    parser.add_argument(
        '--output_labels',
        type=str,
        default='/tmp/output_labels.txt',
        help='Where to save the trained graph\'s labels.'
    )
    parser.add_argument(
        '--summaries_dir',
        type=str,
        default='/tmp/retrain_logs',
        help='Where to save summary logs for TensorBoard.'
    )
    parser.add_argument(
        '--how_many_training_steps',
        type=int,
        default=4000,
        help='How many training steps to run before ending.'
    )
    parser.add_argument(
        '--learning_rate',
        type=float,
        default=0.01,
        help='How large a learning rate to use when training.'
    )
    parser.add_argument(
        '--testing_percentage',
        type=int,
        default=10,
        help='What percentage of images to use as a test set.'
    )
    parser.add_argument(
        '--validation_percentage',
        type=int,
        default=10,
        help='What percentage of images to use as a validation set.'
    )
    parser.add_argument(
        '--eval_step_interval',
        type=int,
        default=10,
        help='How often to evaluate the training results.'
    )
    parser.add_argument(
        '--train_batch_size',
        type=int,
        default=100,
        help='How many images to train on at a time.'
    )
    parser.add_argument(
        '--test_batch_size',
        type=int,
        default=-1,
        help="""\
      How many images to test on. This test set is only used once, to evaluate
      the final accuracy of the model after training completes.
      A value of -1 causes the entire test set to be used, which leads to more
      stable results across runs.\
      """
    )
    parser.add_argument(
        '--validation_batch_size',
        type=int,
        default=100,
        help="""\
      How many images to use in an evaluation batch. This validation set is
      used much more often than the test set, and is an early indicator of how
      accurate the model is during training.
      A value of -1 causes the entire validation set to be used, which leads to
      more stable results across training iterations, but may be slower on large
      training sets.\
      """
    )
    parser.add_argument(
        '--print_misclassified_test_images',
        default=False,
        help="""\
      Whether to print out a list of all misclassified test images.\
      """,
        action='store_true'
    )
    parser.add_argument(
        '--model_dir',
        type=str,
        default='/tmp/imagenet',
        help="""\
      Path to classify_image_graph_def.pb,
      imagenet_synset_to_human_label_map.txt, and
      imagenet_2012_challenge_label_map_proto.pbtxt.\
      """
    )
    parser.add_argument(
        '--bottleneck_dir',
        type=str,
        default='/tmp/bottleneck',
        help='Path to cache bottleneck layer values as files.'
    )
    parser.add_argument(
        '--final_tensor_name',
        type=str,
        default='final_result',
        help="""\
      The name of the output classification layer in the retrained graph.\
      """
    )
    parser.add_argument(
        '--flip_left_right',
        default=False,
        help="""\
      Whether to randomly flip half of the training images horizontally.\
      """,
        action='store_true'
    )
    parser.add_argument(
        '--random_crop',
        type=int,
        default=0,
        help="""\
      A percentage determining how much of a margin to randomly crop off the
      training images.\
      """
    )
    parser.add_argument(
        '--random_scale',
        type=int,
        default=0,
        help="""\
      A percentage determining how much to randomly scale up the size of the
      training images by.\
      """
    )
    parser.add_argument(
        '--random_brightness',
        type=int,
        default=0,
        help="""\
      A percentage determining how much to randomly multiply the training image
      input pixels up or down by.\
      """
    )
    parser.add_argument(
        '--architecture',
        type=str,
        default='inception_v3',
        help="""\
      Which model architecture to use. 'inception_v3' is the most accurate, but
      also the slowest. For faster or smaller models, chose a MobileNet with the
      form 'mobilenet_<parameter size>_<input_size>[_quantized]'. For example,
      'mobilenet_1.0_224' will pick a model that is 17 MB in size and takes 224
      pixel input images, while 'mobilenet_0.25_128_quantized' will choose a much
      less accurate, but smaller and faster network that's 920 KB on disk and
      takes 128x128 images. See https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html
      for more information on Mobilenet.\
      """)
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

tf.logging.error tf.logging.info tf.logging.warning tf.logging.fatal tf.Graph tf.GraphDef tf.import_graph_def tf.placeholder tf.string
tf.image.decode_jpeg tf.cast tf.float32 tf.expand_dims tf.constant tf.random_uniform tf.multiply tf.stack tf.int32 tf.image.resize_bilinear tf.squeeze tf.random_crop tf.image.random_flip_left_right tf.subtract tf.name_scope tf.reduce_mean tf.sqrt tf.square tf.summary.scalar tf.reduce_max tf.reduce_min tf.summary.histogram tf.placeholder_with_default tf.int64 tf.truncated_normal tf.Variable tf.zeros tf.matmul tf.nn.softmax tf.losses.sparse_softmax_cross_entropy tf.train.GradientDescentOptimizer tf.gfile.Exists tf.gfile.DeleteRecursively tf.gfile.MakeDirs tf.logging.set_verbosity tf.logging tf.Session tf.summary.merge_all tf.summary.FileWriter tf.global_variables_initializer tf.app.run

A Guide to TF Layers: Building a Convolutional Neural Network

TF層ガイド:畳み込みニューラルネットワークの構築
Mnist 0-9.png

$ virtualenv --system-site-packages -p python3 layers
$ source ~/layers/bin/activate
(layers)$ pip3 install --upgrade tensorflow
(layers)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/layers/cnn_mnist.py
(layers)$ python cnn_mnist.py
# 終わらないので設定変更
# Ctrl+C
(layers)$ gedit cnn_mnist.py
# 147行目steps=20000をsteps=5000
(layers)$ python cnn_mnist.py
# {'global_step': 5001, 'accuracy': 0.92500001, 'loss': 0.27036309}
(layers)$ deactivate
$ rm -r \
    layers \
    MNIST-data \
    cnn_mnist.py \
    /tmp/mnist_convnet_model

cnn_mnist.py

"""tf.layersで構築されたMNISTの畳み込みニューラルネットワーク推定器"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf

tf.logging.set_verbosity(tf.logging.INFO)


def cnn_model_fn(features, labels, mode):
    """Model function for CNN."""
    # 入力レイヤ
    # Xを4次元テンソルに変形: [batch_size, width, height, channels]
    # MNIST画像は28×28ピクセルであり、1つのカラーチャネル
    input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

    # 畳み込みレイヤ #1
    # ReLUを有効にした5x5フィルタを使用して32のフィーチャを計算します。
    # パディングは、幅と高さを保持するために追加されています。
    # 入力テンソル形状: [batch_size, 28, 28, 1]
    # 出力テンソル形状: [batch_size, 28, 28, 32]
    conv1 = tf.layers.conv2d(
        inputs=input_layer,
        filters=32,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    # プール層 #1
    # 2x2フィルタと2のストライドを持つ最初の最大プール層
    # 入力テンソル形状: [batch_size, 28, 28, 32]
    # 出力テンソル形状: [batch_size, 14, 14, 32]
    pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

    # 畳み込み層 #2
    # 5x5フィルタを使用して64のフィーチャを計算します。
    # パディングは、幅と高さを保持するために追加されています。
    # 入力テンソル形状: [batch_size, 14, 14, 32]
    # 出力テンソル形状: [batch_size, 14, 14, 64]
    conv2 = tf.layers.conv2d(
        inputs=pool1,
        filters=64,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    # プール層 #2
    # 2×2のフィルタおよび2のストライドを有する第2の最大プール層
    # 入力テンソル形状: [batch_size, 14, 14, 64]
    # 出力テンソル形状: [batch_size, 7, 7, 64]
    pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

    # ベクトルのバッチにテンソルをフラット化する
    # 入力テンソル形状: [batch_size, 7, 7, 64]
    # 出力テンソル形状: [batch_size, 7 * 7 * 64]
    pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])

    # 高密度層
    # 1024個のニューロンと密接に接続された層
    # 入力テンソル形状: [batch_size, 7 * 7 * 64]
    # 出力テンソル形状: [batch_size, 1024]
    dense = tf.layers.dense(
        inputs=pool2_flat, units=1024, activation=tf.nn.relu)

    # ドロップアウト操作を追加します。 要素が保持される確率は0.6
    dropout = tf.layers.dropout(
        inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

    # ロジット層
    # 入力テンソル形状: [batch_size, 1024]
    # 出力テンソル形状: [batch_size, 10]
    logits = tf.layers.dense(inputs=dropout, units=10)

    predictions = {
        # 予測を生成する(PREDICTおよびEVALモード用)
        "classes": tf.argmax(input=logits, axis=1),
        # グラフに `softmax_tensor`を追加してください。
        # これはPREDICTと `logging_hook`によって使用されます。
        "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    # 損失の計算(TRAINモードとEVALモードの両方)
    onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=10)
    loss = tf.losses.softmax_cross_entropy(
        onehot_labels=onehot_labels, logits=logits)

    # トレーニングオペレーションを設定する(TRAINモードの場合)
    if mode == tf.estimator.ModeKeys.TRAIN:
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(
            loss=loss,
            global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

    # 評価指標を追加する(EVALモードの場合)
    eval_metric_ops = {
        "accuracy": tf.metrics.accuracy(
            labels=labels, predictions=predictions["classes"])}
    return tf.estimator.EstimatorSpec(
        mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)


def main(unused_argv):
    # トレーニングと評価データを読み込む
    mnist = tf.contrib.learn.datasets.load_dataset("mnist")
    train_data = mnist.train.images  # Returns np.array
    train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
    eval_data = mnist.test.images  # Returns np.array
    eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)

    # Estimatorの作成
    mnist_classifier = tf.estimator.Estimator(
        model_fn=cnn_model_fn, model_dir="/tmp/mnist_convnet_model")

    # 予測のログを設定する
    # "softmax"テンソルの値を "確率"というラベルで記録する。
    tensors_to_log = {"probabilities": "softmax_tensor"}
    logging_hook = tf.train.LoggingTensorHook(
        tensors=tensors_to_log, every_n_iter=50)

    # モデルをトレーニングする
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": train_data},
        y=train_labels,
        batch_size=100,
        num_epochs=None,
        shuffle=True)
    mnist_classifier.train(
        input_fn=train_input_fn,
        steps=20000,
        hooks=[logging_hook])

    # モデルの評価と結果のprint
    eval_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": eval_data},
        y=eval_labels,
        num_epochs=1,
        shuffle=False)
    eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)
    print(eval_results)


if __name__ == "__main__":
    tf.app.run()

tf.logging.set_verbosity tf.logging tf.reshape tf.layers.conv2d tf.nn.relu tf.layers.max_pooling2d tf.layers.dense tf.layers.dropout tf.estimator.ModeKeys tf.argmax tf.nn.softmax tf.estimator.EstimatorSpec tf.one_hot tf.cast tf.int32 tf.losses.softmax_cross_entropy tf.train.GradientDescentOptimizer tf.train.get_global_step tf.metrics.accuracy tf.contrib.learn.datasets tf.estimator.Estimator tf.train.LoggingTensorHook tf.estimator.inputs.numpy_input_fn tf.app.run

Convolutional Neural Networks

畳み込みニューラルネットワーク
Cifar image summary.png

$ git clone https://github.com/tensorflow/models
$ virtualenv --system-site-packages -p python3 deepcnn
$ source ~/deepcnn/bin/activate
(deepcnn)$ pip3 install --upgrade tensorflow
(deepcnn)$ cd models/tutorials/image/cifar10/
(deepcnn)$ python cifar10_train.py
# 終わらないので設定変更
# Ctrl+C
(deepcnn)$ gedit cifar10_train.py
# max_steps', type=int, default=1000000,をmax_steps', type=int, default=1000,
(deepcnn)$ python cifar10_train.py
(deepcnn)$ tensorboard --logdir /tmp/cifar10_train
# ブラウザ http://localhost:6006
# CTRL+C
(deepcnn)$ python cifar10_eval.py
# precision @ 1 = 0.814
(deepcnn)$ deactivate
$ cd ~
$ rm -r \
    deepcnn \
    models \
    /tmp/cifar10_data \
    /tmp/cifar10_train \
    /tmp/cifar10_eval

cifar10_train.py

"""単一のGPUを使用してCIFAR-10をトレーニングするバイナリ。

正確さ:
cifar10_tele.pyは、cifar10_eval.pyによって判断されるように、
100Kステップ(256エポックのデータ)後に〜86%の精度を達成します。

速度: With batch_size 128.

System        | Step Time (sec/batch)  |     Accuracy
------------------------------------------------------------------
1 Tesla K20m  | 0.35-0.60              | ~86% at 60K steps  (5 hours)
1 Tesla K40m  | 0.25-0.35              | ~86% at 100K steps (4 hours)

使用法:
CIFAR-10データセットをダウンロードし、プログラムをコンパイルし、
モデルをトレーニングする方法については、チュートリアルとWebサイトを参照してください。

http://tensorflow.org/tutorials/deep_cnn/
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from datetime import datetime
import time

import tensorflow as tf

import cifar10

parser = cifar10.parser

parser.add_argument('--train_dir', type=str, default='/tmp/cifar10_train',
                    help='Directory where to write event logs and checkpoint.')

parser.add_argument('--max_steps', type=int, default=1000000,
                    help='Number of batches to run.')

parser.add_argument('--log_device_placement', type=bool, default=False,
                    help='Whether to log device placement.')

parser.add_argument('--log_frequency', type=int, default=10,
                    help='How often to log results to the console.')


def train():
    """CIFAR-10にはいくつかのステップがあります。"""
    with tf.Graph().as_default():
        global_step = tf.train.get_or_create_global_step()

        # CIFAR-10の画像とラベルを取得します。
        # CPU:0への入力パイプラインを強制して、時々GPUで動作が終了し、速度が遅くなることを回避します。
        with tf.device('/cpu:0'):
            images, labels = cifar10.distorted_inputs()

        # 推論モデルからロジット予測を計算するグラフを作成します。
        logits = cifar10.inference(images)

        # 損失を計算する。
        loss = cifar10.loss(logits, labels)

        # 1つのバッチの例を使用してモデルをトレーニングし、モデルパラメータを更新するグラフを作成します。
        train_op = cifar10.train(loss, global_step)

        class _LoggerHook(tf.train.SessionRunHook):
            """ログの損失とランタイム"""

            def begin(self):
                self._step = -1
                self._start_time = time.time()

            def before_run(self, run_context):
                self._step += 1
                return tf.train.SessionRunArgs(loss)  # 損失の価値を求めます。

            def after_run(self, run_context, run_values):
                if self._step % FLAGS.log_frequency == 0:
                    current_time = time.time()
                    duration = current_time - self._start_time
                    self._start_time = current_time

                    loss_value = run_values.results
                    examples_per_sec = FLAGS.log_frequency * FLAGS.batch_size / duration
                    sec_per_batch = float(duration / FLAGS.log_frequency)

                    format_str = ('%s: step %d, loss = %.2f (%.1f examples/sec; %.3f '
                                  'sec/batch)')
                    print(format_str % (datetime.now(), self._step, loss_value,
                                        examples_per_sec, sec_per_batch))

        with tf.train.MonitoredTrainingSession(
            checkpoint_dir=FLAGS.train_dir,
            hooks=[tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
                   tf.train.NanTensorHook(loss),
                   _LoggerHook()],
            config=tf.ConfigProto(
                log_device_placement=FLAGS.log_device_placement)) as mon_sess:
            while not mon_sess.should_stop():
                mon_sess.run(train_op)


def main(argv=None):  # pylint: disable=unused-argument
    cifar10.maybe_download_and_extract()
    if tf.gfile.Exists(FLAGS.train_dir):
        tf.gfile.DeleteRecursively(FLAGS.train_dir)
    tf.gfile.MakeDirs(FLAGS.train_dir)
    train()


if __name__ == '__main__':
    FLAGS = parser.parse_args()
    tf.app.run()

cifar10.py

"""CIFAR-10ネットワークを構築します。

利用可能な機能の概要:

 # トレーニング用に入力画像とラベルを計算します。
 # 評価を実行する場合は、代わりにinputs()を使用してください。
 inputs, labels = distorted_inputs()

 # 予測を行うために、モデル入力に対する推論を計算する。
 predictions = inference(inputs)

 # ラベルに関する予測の全損失を計算する。
 loss = loss(predictions, labels)

 # 損失に関するトレーニングの1つのステップを実行するグラフを作成します。
 train_op = train(loss, global_step)
"""
# pylint: disable=missing-docstring
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import re
import sys
import tarfile

from six.moves import urllib
import tensorflow as tf

import cifar10_input

parser = argparse.ArgumentParser()

# 基本モデルパラメータ
parser.add_argument('--batch_size', type=int, default=128,
                    help='Number of images to process in a batch.')

parser.add_argument('--data_dir', type=str, default='/tmp/cifar10_data',
                    help='Path to the CIFAR-10 data directory.')

parser.add_argument('--use_fp16', type=bool, default=False,
                    help='Train the model using fp16.')

FLAGS = parser.parse_args()

# CIFAR-10データセットを記述するグローバル定数
IMAGE_SIZE = cifar10_input.IMAGE_SIZE
NUM_CLASSES = cifar10_input.NUM_CLASSES
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = cifar10_input.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN
NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = cifar10_input.NUM_EXAMPLES_PER_EPOCH_FOR_EVAL


# トレーニングプロセスを記述する定数
MOVING_AVERAGE_DECAY = 0.9999     # 移動平均に使用する減衰
NUM_EPOCHS_PER_DECAY = 350.0      # 学習率が低下した後のエポック
LEARNING_RATE_DECAY_FACTOR = 0.1  # 学習率減衰係数
INITIAL_LEARNING_RATE = 0.1       # 初期学習率

# モデルが複数のGPUで訓練されている場合は、操作を区別するためにすべてのOp名の前にtower_nameを付けます。
# この接頭辞は、モデルを視覚化するときに要約の名前から削除されることに注意してください。
TOWER_NAME = 'tower'

DATA_URL = 'http://www.cs.toronto.edu/~kriz/cifar-10-binary.tar.gz'


def _activation_summary(x):
    """活性化の要約を作成するためのヘルパー

    アクティベーションのヒストグラムを提供する要約を作成します。
    アクティベーションの希薄さを測定するサマリを作成します。

    Args:
      x: テンソル
    Returns:
      なし
    """
    # これがマルチGPUトレーニングセッションの場合は、名前から 'tower_ [0-9] /'を削除してください。
    # これはテンソルボード上での表示の明瞭さを助ける。
    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メモリに格納された変数を作成します。

    Args:
      name: 変数の名前
      shape: intのリスト
      initializer: 変数の初期化子

    Returns:
      可変テンソル
    """
    with tf.device('/cpu:0'):
        dtype = tf.float16 if FLAGS.use_fp16 else tf.float32
        var = tf.get_variable(
            name, shape, initializer=initializer, dtype=dtype)
    return var


def _variable_with_weight_decay(name, shape, stddev, wd):
    """減量して初期化された変数を作成するヘルパー。

    変数は、切り捨てられた正規分布で初期化されることに注意してください。
    減量は、1つが指定されている場合にのみ追加されます。

    Args:
      name: 変数の名前
      shape: intのリスト
      stddev: 切り捨てガウス分布の標準偏差
      wd: このフロートを乗じたL2Loss重量減を加えます。
      Noneの場合、この変数に重量減が追加されません。

    Returns:
      可変テンソル
    """
    dtype = tf.float16 if FLAGS.use_fp16 else tf.float32
    var = _variable_on_cpu(
        name,
        shape,
        tf.truncated_normal_initializer(stddev=stddev, dtype=dtype))
    if wd is not None:
        weight_decay = tf.multiply(tf.nn.l2_loss(var), wd, name='weight_loss')
        tf.add_to_collection('losses', weight_decay)
    return var


def distorted_inputs():
    """Reader opsを使用して、CIFARトレーニング用に歪んだ入力を作成します。

    Returns:
      images: 画像 [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3] サイズの4次元テンソル
      labels: ラベル [batch_size] サイズの1次元テンソル

    Raises:
      ValueError: data_dirがない場合
    """
    if not FLAGS.data_dir:
        raise ValueError('Please supply a data_dir')
    data_dir = os.path.join(FLAGS.data_dir, 'cifar-10-batches-bin')
    images, labels = cifar10_input.distorted_inputs(data_dir=data_dir,
                                                    batch_size=FLAGS.batch_size)
    if FLAGS.use_fp16:
        images = tf.cast(images, tf.float16)
        labels = tf.cast(labels, tf.float16)
    return images, labels


def inputs(eval_data):
    """Reader opsを使用してCIFAR評価の入力を構成します。

    Args:
      eval_data: ブール 訓練または評価データセットを使用する必要があるかどうかを示します。

    Returns:
      images: 画像 [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3] サイズの4次元テンソル
      labels: ラベル [batch_size] サイズの1次元テンソル

    Raises:
      ValueError: data_dirがない場合
    """
    if not FLAGS.data_dir:
        raise ValueError('Please supply a data_dir')
    data_dir = os.path.join(FLAGS.data_dir, 'cifar-10-batches-bin')
    images, labels = cifar10_input.inputs(eval_data=eval_data,
                                          data_dir=data_dir,
                                          batch_size=FLAGS.batch_size)
    if FLAGS.use_fp16:
        images = tf.cast(images, tf.float16)
        labels = tf.cast(labels, tf.float16)
    return images, labels


def inference(images):
    """CIFAR-10モデルを構築します。

    Args:
      images: 画像はdistorted_inputs()またはinputs()から返されます。

    Returns:
      Logits.
    """
    # tf.Variable()の代わりにtf.get_variable()を使用して、
    # 複数のGPUトレーニングの実行間で変数を共有するために、すべての変数をインスタンス化します。
    # このモデルを単一のGPUでのみ実行した場合、
    # tf.get_variable()のすべてのインスタンスをtf.Variable()に置き換えることで、この関数を単純化できます。
    #
    # conv1
    with tf.variable_scope('conv1') as scope:
        kernel = _variable_with_weight_decay('weights',
                                             shape=[5, 5, 3, 64],
                                             stddev=5e-2,
                                             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))
        pre_activation = tf.nn.bias_add(conv, biases)
        conv1 = tf.nn.relu(pre_activation, name=scope.name)
        _activation_summary(conv1)

    # pool1
    pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                           padding='SAME', name='pool1')
    # norm1
    norm1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                      name='norm1')

    # conv2
    with tf.variable_scope('conv2') as scope:
        kernel = _variable_with_weight_decay('weights',
                                             shape=[5, 5, 64, 64],
                                             stddev=5e-2,
                                             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))
        pre_activation = tf.nn.bias_add(conv, biases)
        conv2 = tf.nn.relu(pre_activation, name=scope.name)
        _activation_summary(conv2)

    # norm2
    norm2 = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75,
                      name='norm2')
    # pool2
    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:
        # すべてを深さに移動して、単一の行列乗算を実行できます。
        reshape = tf.reshape(pool2, [FLAGS.batch_size, -1])
        dim = reshape.get_shape()[1].value
        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)

    # linear layer(WX + b),
    # tf.nn.sparse_softmax_cross_entropy_with_logitsはスケーリングされていないロジットを受け入れ、
    # 効率のために内部的にsoftmaxを実行するため、ここではsoftmaxを適用しません。
    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_linear


def loss(logits, labels):
    """すべての学習可能な変数にL2Lossを追加します。

    "Loss"と "Loss / avg"の要約を追加します。
    Args:
      logits: inference()からのログ
      labels: distorted_inputsまたはinputs()のラベル。 1次元テンソル形状[batch_size]

    Returns:
      float型の損失テンソル
    """
    # バッチ全体の平均クロスエントロピー損失を計算します。
    labels = tf.cast(labels, tf.int64)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=labels, logits=logits, name='cross_entropy_per_example')
    cross_entropy_mean = tf.reduce_mean(cross_entropy, name='cross_entropy')
    tf.add_to_collection('losses', cross_entropy_mean)

    # 全損失は、クロスエントロピー損失+すべての重量減衰項(L2損失)として定義される。
    return tf.add_n(tf.get_collection('losses'), name='total_loss')


def _add_loss_summaries(total_loss):
    """CIFAR-10モデルの損失のサマリーを追加します。

    ネットワークのパフォーマンスを視覚化するために、すべての損失と関連する要約の移動平均を生成します。

    Args:
      total_loss: loss()からの合計損失
    Returns:
      loss_averages_op: opは損失の移動平均を生成します。
    """
    # すべての個々の損失と総損失の移動平均を計算します。
    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]:
        # それぞれの損失に'(raw)'と名前をつけて、損失の移動平均バージョンを元の損失名とします。
        tf.summary.scalar(l.op.name + ' (raw)', l)
        tf.summary.scalar(l.op.name, loss_averages.average(l))

    return loss_averages_op


def train(total_loss, global_step):
    """CIFAR-10モデルを訓練する。

    オプティマイザを作成し、学習可能なすべての変数に適用します。
    トレーニング可能なすべての変数の移動平均を追加します。

    Args:
      total_loss: loss()からの合計損失
      global_step: 整数処理されたトレーニングステップの数を数える変数
    Returns:
      train_op: トレーニングのためのop
    """
    # 学習率に影響を与える変数
    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


def maybe_download_and_extract():
    """Alexのウェブサイトからtarballをダウンロードして解凍します。"""
    dest_directory = FLAGS.data_dir
    if not os.path.exists(dest_directory):
        os.makedirs(dest_directory)
    filename = DATA_URL.split('/')[-1]
    filepath = os.path.join(dest_directory, filename)
    if not os.path.exists(filepath):
        def _progress(count, block_size, total_size):
            sys.stdout.write('\r>> Downloading %s %.1f%%' % (filename,
                                                             float(count * block_size) / float(total_size) * 100.0))
            sys.stdout.flush()
        filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress)
        print()
        statinfo = os.stat(filepath)
        print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
    extracted_dir_path = os.path.join(dest_directory, 'cifar-10-batches-bin')
    if not os.path.exists(extracted_dir_path):
        tarfile.open(filepath, 'r:gz').extractall(dest_directory)

cifar10_input.py

"""CIFAR-10バイナリファイル形式をデコードするルーチン"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os

from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

# このサイズの画像を処理します。
# これは、元のCIFARイメージサイズである32 x 32とは異なります。
# この数値を変更すると、モデルアーキテクチャ全体が変更され、モデルを再トレーニングする必要があります。
IMAGE_SIZE = 24

# CIFAR-10データセットを記述するグローバル定数
NUM_CLASSES = 10
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000
NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = 10000


def read_cifar10(filename_queue):
    """CIFAR10データファイルの例を読み込み、解析します。

    Recommendation: N-way読み込みの並列性が必要な場合は、この関数をN回呼び出します。
    これはN個の独立したReadersがそれらのファイル内の異なるファイルと位置を読んでくれて、
    より良い例の混合が得られます。

    Args:
      filename_queue: 読み込むファイル名を持つ文字列のキュー

    Returns:
      次のフィールドを持つ単一の例を表すオブジェクト:
        height: 結果の行数(32)
        width: 結果の列数(32)
        depth: 結果のカラーチャネル数(3)
        key: この例のファイル名とレコード番号を記述するスカラー文字列テンソル
        label: 0..9の範囲のラベルを持つint32テンソル
        uint8image: [height, width, depth] uint8 テンソルと画像データ
    """

    class CIFAR10Record(object):
        pass
    result = CIFAR10Record()

    # CIFAR-10データセット内の画像の寸法
    # 入力形式の説明については、
    # http://www.cs.toronto.edu/~kriz/cifar.html
    # を参照してください。
    label_bytes = 1  # CIFAR-100の場合は2
    result.height = 32
    result.width = 32
    result.depth = 3
    image_bytes = result.height * result.width * result.depth
    # すべてのレコードはラベルに続いてイメージがあり、それぞれに固定バイト数があります。
    record_bytes = label_bytes + image_bytes

    # filename_queueからファイル名を取得してレコードを読み込みます。
    # CIFAR-10形式のヘッダーもフッターもないので、header_bytesとfooter_bytesはデフォルトの0のままにします。
    reader = tf.FixedLengthRecordReader(record_bytes=record_bytes)
    result.key, value = reader.read(filename_queue)

    # 文字列から、record_bytes長いuint8のベクトルに変換します。
    record_bytes = tf.decode_raw(value, tf.uint8)

    # 最初のバイトはuint8->int32から変換するラベルを表します。
    result.label = tf.cast(
        tf.strided_slice(record_bytes, [0], [label_bytes]), tf.int32)

    # ラベルの後の残りのバイトはイメージを表します。
    # イメージは[depth * height * width]から[depth、height、width]に変更されます。
    depth_major = tf.reshape(
        tf.strided_slice(record_bytes, [label_bytes],
                         [label_bytes + image_bytes]),
        [result.depth, result.height, result.width])
    # [depth, height, width]から[height, width, depth]に変換します。
    result.uint8image = tf.transpose(depth_major, [1, 2, 0])

    return result


def _generate_image_and_label_batch(image, label, min_queue_examples,
                                    batch_size, shuffle):
    """イメージとラベルのキューに入れられたバッチを構築します。

    Args:
      image: type.float32の[height, width, 3]の3次元テンソル。
      label: type.int32の1次元テンソル
      min_queue_examples: int32、例のバッチを提供するキューに保持するサンプルの最小数。
      batch_size: 1バッチあたりの画像数
      shuffle: シャッフルキューを使用するかどうかを示すブール値

    Returns:
      images: 画像 [batch_size, height, width, 3]サイズの4次元テンソル
      labels: ラベル [batch_size]サイズの1次元テンソル
    """
    # サンプルをシャッフルするキューを作成し、
    # 次に、「batch_size」イメージ+ラベルをサンプルキューから読み込みます。
    num_preprocess_threads = 16
    if shuffle:
        images, label_batch = tf.train.shuffle_batch(
            [image, label],
            batch_size=batch_size,
            num_threads=num_preprocess_threads,
            capacity=min_queue_examples + 3 * batch_size,
            min_after_dequeue=min_queue_examples)
    else:
        images, label_batch = tf.train.batch(
            [image, label],
            batch_size=batch_size,
            num_threads=num_preprocess_threads,
            capacity=min_queue_examples + 3 * batch_size)

    # ビジュアライザーにトレーニング画像を表示します。
    tf.summary.image('images', images)

    return images, tf.reshape(label_batch, [batch_size])


def distorted_inputs(data_dir, batch_size):
    """Reader opsを使用して、CIFARトレーニング用に歪んだ入力を作成します。

    Args:
      data_dir: CIFAR-10データディレクトリへのパス
      batch_size: 1バッチあたりの画像数

    Returns:
      images: 画像 [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3]サイズの4次元テンソル
      labels: ラベル [batch_size]サイズの1次元テンソル
    """
    filenames = [os.path.join(data_dir, 'data_batch_%d.bin' % i)
                 for i in xrange(1, 6)]
    for f in filenames:
        if not tf.gfile.Exists(f):
            raise ValueError('Failed to find file: ' + f)

    # 読み込むファイル名を生成するキューを作成します。
    filename_queue = tf.train.string_input_producer(filenames)

    # ファイル名のキューにあるファイルの例を読みます。
    read_input = read_cifar10(filename_queue)
    reshaped_image = tf.cast(read_input.uint8image, tf.float32)

    height = IMAGE_SIZE
    width = IMAGE_SIZE

    # ネットワークを訓練するための画像処理。
    # 画像に適用される多くのランダムな歪みに注意してください。

    # 画像の[height, width]セクションをランダムにトリミングします。
    distorted_image = tf.random_crop(reshaped_image, [height, width, 3])

    # ランダムにイメージを水平方向に反転させます。
    distorted_image = tf.image.random_flip_left_right(distorted_image)

    # これらの操作は可換ではないため、操作の順序をランダム化することを検討してください。
    # 注記:per_image_standardizationは平均値を0にしてstddevユニットを作るので、
    # tensorflow#1458を参照してください。
    distorted_image = tf.image.random_brightness(distorted_image,
                                                 max_delta=63)
    distorted_image = tf.image.random_contrast(distorted_image,
                                               lower=0.2, upper=1.8)

    # 平均を差し引いてピクセルの分散で除算します。
    float_image = tf.image.per_image_standardization(distorted_image)

    # テンソルの形状を設定します。
    float_image.set_shape([height, width, 3])
    read_input.label.set_shape([1])

    # ランダムシャフリングが良好な混合特性を有することを確認する。
    min_fraction_of_examples_in_queue = 0.4
    min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN *
                             min_fraction_of_examples_in_queue)
    print('Filling queue with %d CIFAR images before starting to train. '
          'This will take a few minutes.' % min_queue_examples)

    # 例のキューを構築して、画像とラベルのバッチを生成します。
    return _generate_image_and_label_batch(float_image, read_input.label,
                                           min_queue_examples, batch_size,
                                           shuffle=True)


def inputs(eval_data, data_dir, batch_size):
    """Reader opsを使用してCIFAR評価の入力を構成します。

    Args:
      eval_data: ブール 訓練または評価データセットを使用する必要があるかどうかを示します
      data_dir: CIFAR-10データディレクトリへのパス
      batch_size: 1バッチあたりの画像数

    Returns:
      images: 画像 [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3]サイズの4次元テンソル
      labels: ラベル [batch_size]サイズの1次元テンソル
    """
    if not eval_data:
        filenames = [os.path.join(data_dir, 'data_batch_%d.bin' % i)
                     for i in xrange(1, 6)]
        num_examples_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN
    else:
        filenames = [os.path.join(data_dir, 'test_batch.bin')]
        num_examples_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_EVAL

    for f in filenames:
        if not tf.gfile.Exists(f):
            raise ValueError('Failed to find file: ' + f)

    # 読み込むファイル名を生成するキューを作成します。
    filename_queue = tf.train.string_input_producer(filenames)

    # ファイル名のキューにあるファイルの例を読みます。
    read_input = read_cifar10(filename_queue)
    reshaped_image = tf.cast(read_input.uint8image, tf.float32)

    height = IMAGE_SIZE
    width = IMAGE_SIZE

    # 評価のための画像処理
    # イメージの中心を[height, width]でトリミングします。
    resized_image = tf.image.resize_image_with_crop_or_pad(reshaped_image,
                                                           height, width)

    # 平均を差し引いてピクセルの分散で除算します。
    float_image = tf.image.per_image_standardization(resized_image)

    # テンソルの形状を設定します。
    float_image.set_shape([height, width, 3])
    read_input.label.set_shape([1])

    # ランダムシャフリングが良好な混合特性を有することを確認する。
    min_fraction_of_examples_in_queue = 0.4
    min_queue_examples = int(num_examples_per_epoch *
                             min_fraction_of_examples_in_queue)

    # 例のキューを構築して、画像とラベルのバッチを生成します。
    return _generate_image_and_label_batch(float_image, read_input.label,
                                           min_queue_examples, batch_size,
                                           shuffle=False)

Vector Representations of Words

言葉のベクトル表現
Tsne.png

$ virtualenv --system-site-packages -p python3 word2vec
$ source ~/word2vec/bin/activate
(word2vec)$ pip3 install --upgrade tensorflow
(word2vec)$ pip3 install sklearn scipy matplotlib
(word2vec)$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/r1.4/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
(word2vec)$ python word2vec_basic.py
# tmpディレクトリにt-SNE画像ができる
(word2vec)$ deactivate
$ rm -r \
    word2vec \
    word2vec_basic.py \
    /tmp/text8.zip \
    /tmp/tsne.png

word2vec_basic.py

"""基本的なword2vecの例。"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections
import math
import os
import random
from tempfile import gettempdir
import zipfile

import numpy as np
from six.moves import urllib
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

# ステップ1:データをダウンロードします。
url = 'http://mattmahoney.net/dc/'


# pylint: disable=redefined-outer-name
def maybe_download(filename, expected_bytes):
    """存在しない場合はファイルをダウンロードし、正しいサイズであることを確認します。"""
    local_filename = os.path.join(gettempdir(), filename)
    if not os.path.exists(local_filename):
        local_filename, _ = urllib.request.urlretrieve(url + filename,
                                                       local_filename)
    statinfo = os.stat(local_filename)
    if statinfo.st_size == expected_bytes:
        print('Found and verified', filename)
    else:
        print(statinfo.st_size)
        raise Exception('Failed to verify ' + local_filename +
                        '. Can you get to it with a browser?')
    return local_filename


filename = maybe_download('text8.zip', 31344016)


# データを文字列のリストに読み込みます。
def read_data(filename):
    """zipファイルで囲まれた最初のファイルを単語のリストとして抽出します。"""
    with zipfile.ZipFile(filename) as f:
        data = tf.compat.as_str(f.read(f.namelist()[0])).split()
    return data


vocabulary = read_data(filename)
print('Data size', len(vocabulary))

# ステップ2:辞書を作成し、まれな単語をUNKトークンに置き換えます。
vocabulary_size = 50000


def build_dataset(words, n_words):
    """生の入力をデータセットに処理します。"""
    count = [['UNK', -1]]
    count.extend(collections.Counter(words).most_common(n_words - 1))
    dictionary = dict()
    for word, _ in count:
        dictionary[word] = len(dictionary)
    data = list()
    unk_count = 0
    for word in words:
        index = dictionary.get(word, 0)
        if index == 0:  # dictionary['UNK']
            unk_count += 1
        data.append(index)
    count[0][1] = unk_count
    reversed_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
    return data, count, dictionary, reversed_dictionary


# 4つのグローバル変数を設定する:
# data - コードのリスト(0からvocabulary_size-1までの整数)
# これは元のテキストですが、単語はコードに置き換えられます
# count - 出現数をカウントする単語(文字列)のマップ
# dictionary - 単語(文字列)のコード(整数)へのマップ
# reverse_dictionary - コード(整数)を単語(文字列)にマッピングします。
data, count, dictionary, reverse_dictionary = build_dataset(vocabulary,
                                                            vocabulary_size)
del vocabulary  # メモリを減らすためのヒント
print('Most common words (+UNK)', count[:5])
print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])

data_index = 0

# ステップ3:スキップグラムモデルのトレーニングバッチを生成する機能


def generate_batch(batch_size, num_skips, skip_window):
    global data_index
    assert batch_size % num_skips == 0
    assert num_skips <= 2 * skip_window
    batch = np.ndarray(shape=(batch_size), dtype=np.int32)
    labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
    span = 2 * skip_window + 1  # [ skip_window target skip_window ]
    buffer = collections.deque(maxlen=span)
    if data_index + span > len(data):
        data_index = 0
    buffer.extend(data[data_index:data_index + span])
    data_index += span
    for i in range(batch_size // num_skips):
        context_words = [w for w in range(span) if w != skip_window]
        words_to_use = random.sample(context_words, num_skips)
        for j, context_word in enumerate(words_to_use):
            batch[i * num_skips + j] = buffer[skip_window]
            labels[i * num_skips + j, 0] = buffer[context_word]
        if data_index == len(data):
            buffer[:] = data[:span]
            data_index = span
        else:
            buffer.append(data[data_index])
            data_index += 1
    # バッチの終わりに単語をスキップしないようにするには、少し前に戻ってください。
    data_index = (data_index + len(data) - span) % len(data)
    return batch, labels


batch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1)
for i in range(8):
    print(batch[i], reverse_dictionary[batch[i]],
          '->', labels[i, 0], reverse_dictionary[labels[i, 0]])

# ステップ4:スキップグラムモデルを構築し、訓練する。

batch_size = 128
embedding_size = 128  # 埋め込みベクトルの次元
skip_window = 1       # 左右にどれだけの単語を考慮するか
num_skips = 2         # 入力を再利用してラベルを生成する回数
num_sampled = 64      # サンプリングする負のサンプル数

# 最近接のサンプルをランダムに検証します。
# ここでは、バリデーションのサンプルを数値IDの低い単語に限定しています。
# これは、建設でも最も頻繁に使用されます。
# これら3つの変数は、モデルの精度を表示するためにのみ使用され、計算には影響しません。
valid_size = 16     # 類似性を評価するための単語のランダムセット
valid_window = 100  # ディストリビューションの先頭にdevサンプルを選んでください
valid_examples = np.random.choice(valid_window, valid_size, replace=False)


graph = tf.Graph()

with graph.as_default():

    # 入力データ
    train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
    train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
    valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

    # GPUの実装が不足しているため、Opsと変数がCPUに固定されていました
    with tf.device('/cpu:0'):
        # 入力用埋め込みを調べる
        embeddings = tf.Variable(
            tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
        embed = tf.nn.embedding_lookup(embeddings, train_inputs)

        # NCE損失のための変数を構築する
        nce_weights = tf.Variable(
            tf.truncated_normal([vocabulary_size, embedding_size],
                                stddev=1.0 / math.sqrt(embedding_size)))
        nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

    # バッチの平均NCE損失を計算します。
    # tf.nce_lossは、損失を評価するたびに、負のラベルの新しいサンプルを自動的に描画します。
    # NCE損失の意味の説明:
    # http://mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/
    loss = tf.reduce_mean(
        tf.nn.nce_loss(weights=nce_weights,
                       biases=nce_biases,
                       labels=train_labels,
                       inputs=embed,
                       num_sampled=num_sampled,
                       num_classes=vocabulary_size))

    # 学習率1.0を使用して最急降下法オプティマイザを構築します。
    optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)

    # minibatchの例とすべての埋め込みとのコサイン類似度を計算する。
    norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
    normalized_embeddings = embeddings / norm
    valid_embeddings = tf.nn.embedding_lookup(
        normalized_embeddings, valid_dataset)
    similarity = tf.matmul(
        valid_embeddings, normalized_embeddings, transpose_b=True)

    # 変数初期化子を追加します。
    init = tf.global_variables_initializer()

# ステップ5:トレーニングを開始します。
num_steps = 100001

with tf.Session(graph=graph) as session:
    # すべての変数を使用する前に初期化する必要があります。
    init.run()
    print('Initialized')

    average_loss = 0
    for step in xrange(num_steps):
        batch_inputs, batch_labels = generate_batch(
            batch_size, num_skips, skip_window)
        feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels}

        # オプティマイザのopを評価することで、1つの更新ステップを実行します。
        # (これはsession.run()の戻り値のリストに含まれています)
        _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)
        average_loss += loss_val

        if step % 2000 == 0:
            if step > 0:
                average_loss /= 2000
            # 平均損失は、過去2000回分の損失の見積もりです。
            print('Average loss at step ', step, ': ', average_loss)
            average_loss = 0

        # これは高価であることに注意してください(500ステップごとに計算された場合〜20%の減速)
        if step % 10000 == 0:
            sim = similarity.eval()
            for i in xrange(valid_size):
                valid_word = reverse_dictionary[valid_examples[i]]
                top_k = 8  # 最近傍点の数
                nearest = (-sim[i, :]).argsort()[1:top_k + 1]
                log_str = 'Nearest to %s:' % valid_word
                for k in xrange(top_k):
                    close_word = reverse_dictionary[nearest[k]]
                    log_str = '%s %s,' % (log_str, close_word)
                print(log_str)
    final_embeddings = normalized_embeddings.eval()

# ステップ6:埋め込みを視覚化する。


# pylint: disable=missing-docstring
# 埋め込み間の距離の可視化を描画する関数。
def plot_with_labels(low_dim_embs, labels, filename):
    assert low_dim_embs.shape[0] >= len(labels), 'More labels than embeddings'
    plt.figure(figsize=(18, 18))  # インチで
    for i, label in enumerate(labels):
        x, y = low_dim_embs[i, :]
        plt.scatter(x, y)
        plt.annotate(label,
                     xy=(x, y),
                     xytext=(5, 2),
                     textcoords='offset points',
                     ha='right',
                     va='bottom')

    plt.savefig(filename)


try:
    # pylint: disable=g-import-not-at-top
    from sklearn.manifold import TSNE
    import matplotlib.pyplot as plt

    tsne = TSNE(perplexity=30, n_components=2,
                init='pca', n_iter=5000, method='exact')
    plot_only = 500
    low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only, :])
    labels = [reverse_dictionary[i] for i in xrange(plot_only)]
    plot_with_labels(low_dim_embs, labels,
                     os.path.join(gettempdir(), 'tsne.png'))

except ImportError as ex:
    print('Please install sklearn, matplotlib, and scipy to show embeddings.')
    print(ex)

Recurrent Neural Networks

リカレントニューラルネットワーク
Ptb word lm.png

$ wget http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz
$ tar xvfz simple-examples.tgz -C $HOME
$ git clone https://github.com/tensorflow/models
$ virtualenv --system-site-packages -p python3 recurrent
$ source ~/recurrent/bin/activate
(recurrent)$ pip3 install --upgrade tensorflow
(recurrent)$ cd models/tutorials/rnn/ptb
(recurrent)$ python ptb_word_lm.py --data_path=$HOME/simple-examples/data/ --model=small --num_gpus=0
# 終わらないので設定変更
# Ctrl+C
(deepcnn)$ gedit ptb_word_lm.py
# 329行目max_max_epoch = 13をmax_max_epoch = 2
(recurrent)$ python ptb_word_lm.py --data_path=$HOME/simple-examples/data/ --model=small --num_gpus=0
# Test Perplexity: 142.160
(recurrent)$ deactivate
$ cd ~
$ rm -r \
    recurrent \
    models \
    simple-examples \
    simple-examples.tgz

ptb_word_lm.py

"""PTB LSTMモデルを構築するための例/ベンチマーク。

次のようなモデルを学習します:
(Zaremba, et. al.) リカレントニューラルネットワーク正規化
http://arxiv.org/abs/1409.2329

サポートされているモデル構成は3種類あります:
===========================================
| config | epochs | train | valid  | test
===========================================
| small  | 13     | 37.99 | 121.39 | 115.91
| medium | 39     | 48.45 |  86.16 |  82.07
| large  | 55     | 37.87 |  82.62 |  78.29
正確な結果は、ランダムな初期化によって異なる場合があります。

モデルで使用されるハイパーパラメータ:
- init_scale - 重みの初期スケール
- learning_rate - 学習率の初期値
- max_grad_norm - 勾配の最大許容ノルム
- num_layers - LSTM層の数
- num_steps - LSTMのアンロールされたステップの数
- hidden_size - LSTMユニットの数
- max_epoch - 最初の学習率で訓練されたエポックの数
- max_max_epoch - トレーニングのエポックの総数
- keep_prob - ドロップアウト層に重みを保持する確率
- lr_decay - "max_epoch"後の各エポックの学習率の減衰
- batch_size - バッチサイズ
- rnn_mode - lstmセルの低レベル実装:cudnn_lstm、basic_lstm、
  およびlstm_block_cellクラスを表すCUDNN、BASIC、またはBLOCKのいずれか。

この例で必要なデータは、
Tomas MikolovのWebページのPTBデータセットのdata / dirにあります。:

$ wget http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz
$ tar xvf simple-examples.tgz

実行:

$ python ptb_word_lm.py --data_path=simple-examples/data/

"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import time

import numpy as np
import tensorflow as tf

import reader
import util

from tensorflow.python.client import device_lib

flags = tf.flags
logging = tf.logging

flags.DEFINE_string(
    "model", "small",
    "A type of model. Possible options are: small, medium, large.")
flags.DEFINE_string("data_path", None,
                    "Where the training/test data is stored.")
flags.DEFINE_string("save_path", None,
                    "Model output directory.")
flags.DEFINE_bool("use_fp16", False,
                  "Train using 16-bit floats instead of 32bit floats")
flags.DEFINE_integer("num_gpus", 1,
                     "If larger than 1, Grappler AutoParallel optimizer "
                     "will create multiple training replicas with each GPU "
                     "running one replica.")
flags.DEFINE_string("rnn_mode", None,
                    "The low level implementation of lstm cell: one of CUDNN, "
                    "BASIC, and BLOCK, representing cudnn_lstm, basic_lstm, "
                    "and lstm_block_cell classes.")
FLAGS = flags.FLAGS
BASIC = "basic"
CUDNN = "cudnn"
BLOCK = "block"


def data_type():
    return tf.float16 if FLAGS.use_fp16 else tf.float32


class PTBInput(object):
    """入力データ"""

    def __init__(self, config, data, name=None):
        self.batch_size = batch_size = config.batch_size
        self.num_steps = num_steps = config.num_steps
        self.epoch_size = ((len(data) // batch_size) - 1) // num_steps
        self.input_data, self.targets = reader.ptb_producer(
            data, batch_size, num_steps, name=name)


class PTBModel(object):
    """PTBモデル"""

    def __init__(self, is_training, config, input_):
        self._is_training = is_training
        self._input = input_
        self._rnn_params = None
        self._cell = None
        self.batch_size = input_.batch_size
        self.num_steps = input_.num_steps
        size = config.hidden_size
        vocab_size = config.vocab_size

        with tf.device("/cpu:0"):
            embedding = tf.get_variable(
                "embedding", [vocab_size, size], dtype=data_type())
            inputs = tf.nn.embedding_lookup(embedding, input_.input_data)

        if is_training and config.keep_prob < 1:
            inputs = tf.nn.dropout(inputs, config.keep_prob)

        output, state = self._build_rnn_graph(inputs, config, is_training)

        softmax_w = tf.get_variable(
            "softmax_w", [size, vocab_size], dtype=data_type())
        softmax_b = tf.get_variable(
            "softmax_b", [vocab_size], dtype=data_type())
        logits = tf.nn.xw_plus_b(output, softmax_w, softmax_b)
        # 系列ロスの3次元テンソルになるようにロジットを変形する
        logits = tf.reshape(
            logits, [self.batch_size, self.num_steps, vocab_size])

        # バッチ上のコントリビューション損失と平均を使用する
        loss = tf.contrib.seq2seq.sequence_loss(
            logits,
            input_.targets,
            tf.ones([self.batch_size, self.num_steps], dtype=data_type()),
            average_across_timesteps=False,
            average_across_batch=True)

        # コストを更新する
        self._cost = tf.reduce_sum(loss)
        self._final_state = state

        if not is_training:
            return

        self._lr = tf.Variable(0.0, trainable=False)
        tvars = tf.trainable_variables()
        grads, _ = tf.clip_by_global_norm(tf.gradients(self._cost, tvars),
                                          config.max_grad_norm)
        optimizer = tf.train.GradientDescentOptimizer(self._lr)
        self._train_op = optimizer.apply_gradients(
            zip(grads, tvars),
            global_step=tf.train.get_or_create_global_step())

        self._new_lr = tf.placeholder(
            tf.float32, shape=[], name="new_learning_rate")
        self._lr_update = tf.assign(self._lr, self._new_lr)

    def _build_rnn_graph(self, inputs, config, is_training):
        if config.rnn_mode == CUDNN:
            return self._build_rnn_graph_cudnn(inputs, config, is_training)
        else:
            return self._build_rnn_graph_lstm(inputs, config, is_training)

    def _build_rnn_graph_cudnn(self, inputs, config, is_training):
        """CUDNNセルを使用して推論グラフを作成します。"""
        inputs = tf.transpose(inputs, [1, 0, 2])
        self._cell = tf.contrib.cudnn_rnn.CudnnLSTM(
            num_layers=config.num_layers,
            num_units=config.hidden_size,
            input_size=config.hidden_size,
            dropout=1 - config.keep_prob if is_training else 0)
        params_size_t = self._cell.params_size()
        self._rnn_params = tf.get_variable(
            "lstm_params",
            initializer=tf.random_uniform(
                [params_size_t], -config.init_scale, config.init_scale),
            validate_shape=False)
        c = tf.zeros([config.num_layers, self.batch_size, config.hidden_size],
                     tf.float32)
        h = tf.zeros([config.num_layers, self.batch_size, config.hidden_size],
                     tf.float32)
        self._initial_state = (tf.contrib.rnn.LSTMStateTuple(h=h, c=c),)
        outputs, h, c = self._cell(inputs, h, c, self._rnn_params, is_training)
        outputs = tf.transpose(outputs, [1, 0, 2])
        outputs = tf.reshape(outputs, [-1, config.hidden_size])
        return outputs, (tf.contrib.rnn.LSTMStateTuple(h=h, c=c),)

    def _get_lstm_cell(self, config, is_training):
        if config.rnn_mode == BASIC:
            return tf.contrib.rnn.BasicLSTMCell(
                config.hidden_size, forget_bias=0.0, state_is_tuple=True,
                reuse=not is_training)
        if config.rnn_mode == BLOCK:
            return tf.contrib.rnn.LSTMBlockCell(
                config.hidden_size, forget_bias=0.0)
        raise ValueError("rnn_mode %s not supported" % config.rnn_mode)

    def _build_rnn_graph_lstm(self, inputs, config, is_training):
        """推論グラフを標準的なLSTMセルを使って構築します。"""
        # 1に初期化された忘却ゲートバイアスを用いてわずかに良好な結果が得られるが、
        # モデルのハイパーパラメータは紙に報告されたものと異なる必要がある。
        def make_cell():
            cell = self._get_lstm_cell(config, is_training)
            if is_training and config.keep_prob < 1:
                cell = tf.contrib.rnn.DropoutWrapper(
                    cell, output_keep_prob=config.keep_prob)
            return cell

        cell = tf.contrib.rnn.MultiRNNCell(
            [make_cell() for _ in range(config.num_layers)], state_is_tuple=True)

        self._initial_state = cell.zero_state(config.batch_size, data_type())
        state = self._initial_state
        # tensorflow_models/tutorials/rnn/rnn.pyのrnn()の簡略版。
        # これにより、チュートリアルの目的でのみ、展開されたLSTMが構築されます。
        # 一般的には、rnn.pyのrnn()またはstate_saving_rnn()を使用します。
        #
        # 以下のコードの代替バージョンは次のとおりです:
        #
        # inputs = tf.unstack(inputs, num=num_steps, axis=1)
        # outputs, state = tf.contrib.rnn.static_rnn(cell, inputs,
        #                            initial_state=self._initial_state)
        outputs = []
        with tf.variable_scope("RNN"):
            for time_step in range(self.num_steps):
                if time_step > 0:
                    tf.get_variable_scope().reuse_variables()
                (cell_output, state) = cell(inputs[:, time_step, :], state)
                outputs.append(cell_output)
        output = tf.reshape(tf.concat(outputs, 1), [-1, config.hidden_size])
        return output, state

    def assign_lr(self, session, lr_value):
        session.run(self._lr_update, feed_dict={self._new_lr: lr_value})

    def export_ops(self, name):
        """opsをコレクションにエクスポートします。"""
        self._name = name
        ops = {util.with_prefix(self._name, "cost"): self._cost}
        if self._is_training:
            ops.update(lr=self._lr, new_lr=self._new_lr,
                       lr_update=self._lr_update)
            if self._rnn_params:
                ops.update(rnn_params=self._rnn_params)
        for name, op in ops.items():
            tf.add_to_collection(name, op)
        self._initial_state_name = util.with_prefix(self._name, "initial")
        self._final_state_name = util.with_prefix(self._name, "final")
        util.export_state_tuples(self._initial_state, self._initial_state_name)
        util.export_state_tuples(self._final_state, self._final_state_name)

    def import_ops(self):
        """コレクションからopsをインポートします。"""
        if self._is_training:
            self._train_op = tf.get_collection_ref("train_op")[0]
            self._lr = tf.get_collection_ref("lr")[0]
            self._new_lr = tf.get_collection_ref("new_lr")[0]
            self._lr_update = tf.get_collection_ref("lr_update")[0]
            rnn_params = tf.get_collection_ref("rnn_params")
            if self._cell and rnn_params:
                params_saveable = tf.contrib.cudnn_rnn.RNNParamsSaveable(
                    self._cell,
                    self._cell.params_to_canonical,
                    self._cell.canonical_to_params,
                    rnn_params,
                    base_variable_scope="Model/RNN")
                tf.add_to_collection(
                    tf.GraphKeys.SAVEABLE_OBJECTS, params_saveable)
        self._cost = tf.get_collection_ref(
            util.with_prefix(self._name, "cost"))[0]
        num_replicas = FLAGS.num_gpus if self._name == "Train" else 1
        self._initial_state = util.import_state_tuples(
            self._initial_state, self._initial_state_name, num_replicas)
        self._final_state = util.import_state_tuples(
            self._final_state, self._final_state_name, num_replicas)

    @property
    def input(self):
        return self._input

    @property
    def initial_state(self):
        return self._initial_state

    @property
    def cost(self):
        return self._cost

    @property
    def final_state(self):
        return self._final_state

    @property
    def lr(self):
        return self._lr

    @property
    def train_op(self):
        return self._train_op

    @property
    def initial_state_name(self):
        return self._initial_state_name

    @property
    def final_state_name(self):
        return self._final_state_name


class SmallConfig(object):
    """Smallの設定"""
    init_scale = 0.1
    learning_rate = 1.0
    max_grad_norm = 5
    num_layers = 2
    num_steps = 20
    hidden_size = 200
    max_epoch = 4
    max_max_epoch = 3
    keep_prob = 1.0
    lr_decay = 0.5
    batch_size = 20
    vocab_size = 10000
    rnn_mode = BLOCK


class MediumConfig(object):
    """Mediumの設定"""
    init_scale = 0.05
    learning_rate = 1.0
    max_grad_norm = 5
    num_layers = 2
    num_steps = 35
    hidden_size = 650
    max_epoch = 6
    max_max_epoch = 39
    keep_prob = 0.5
    lr_decay = 0.8
    batch_size = 20
    vocab_size = 10000
    rnn_mode = BLOCK


class LargeConfig(object):
    """Largeの設定"""
    init_scale = 0.04
    learning_rate = 1.0
    max_grad_norm = 10
    num_layers = 2
    num_steps = 35
    hidden_size = 1500
    max_epoch = 14
    max_max_epoch = 55
    keep_prob = 0.35
    lr_decay = 1 / 1.15
    batch_size = 20
    vocab_size = 10000
    rnn_mode = BLOCK


class TestConfig(object):
    """テストのための小さな設定"""
    init_scale = 0.1
    learning_rate = 1.0
    max_grad_norm = 1
    num_layers = 1
    num_steps = 2
    hidden_size = 2
    max_epoch = 1
    max_max_epoch = 1
    keep_prob = 1.0
    lr_decay = 0.5
    batch_size = 20
    vocab_size = 10000
    rnn_mode = BLOCK


def run_epoch(session, model, eval_op=None, verbose=False):
    """指定されたデータに対してモデルを実行します"""
    start_time = time.time()
    costs = 0.0
    iters = 0
    state = session.run(model.initial_state)

    fetches = {
        "cost": model.cost,
        "final_state": model.final_state,
    }
    if eval_op is not None:
        fetches["eval_op"] = eval_op

    for step in range(model.input.epoch_size):
        feed_dict = {}
        for i, (c, h) in enumerate(model.initial_state):
            feed_dict[c] = state[i].c
            feed_dict[h] = state[i].h

        vals = session.run(fetches, feed_dict)
        cost = vals["cost"]
        state = vals["final_state"]

        costs += cost
        iters += model.input.num_steps

        if verbose and step % (model.input.epoch_size // 10) == 10:
            print("%.3f perplexity: %.3f speed: %.0f wps" %
                  (step * 1.0 / model.input.epoch_size, np.exp(costs / iters),
                   iters * model.input.batch_size * max(1, FLAGS.num_gpus) /
                   (time.time() - start_time)))

    return np.exp(costs / iters)


def get_config():
    """モデルの設定を取得します"""
    config = None
    if FLAGS.model == "small":
        config = SmallConfig()
    elif FLAGS.model == "medium":
        config = MediumConfig()
    elif FLAGS.model == "large":
        config = LargeConfig()
    elif FLAGS.model == "test":
        config = TestConfig()
    else:
        raise ValueError("Invalid model: %s", FLAGS.model)
    if FLAGS.rnn_mode:
        config.rnn_mode = FLAGS.rnn_mode
    if FLAGS.num_gpus != 1 or tf.__version__ < "1.3.0":
        config.rnn_mode = BASIC
    return config


def main(_):
    if not FLAGS.data_path:
        raise ValueError("Must set --data_path to PTB data directory")
    gpus = [
        x.name for x in device_lib.list_local_devices() if x.device_type == "GPU"
    ]
    if FLAGS.num_gpus > len(gpus):
        raise ValueError(
            "Your machine has only %d gpus "
            "which is less than the requested --num_gpus=%d."
            % (len(gpus), FLAGS.num_gpus))

    raw_data = reader.ptb_raw_data(FLAGS.data_path)
    train_data, valid_data, test_data, _ = raw_data

    config = get_config()
    eval_config = get_config()
    eval_config.batch_size = 1
    eval_config.num_steps = 1

    with tf.Graph().as_default():
        initializer = tf.random_uniform_initializer(-config.init_scale,
                                                    config.init_scale)

        with tf.name_scope("Train"):
            train_input = PTBInput(
                config=config, data=train_data, name="TrainInput")
            with tf.variable_scope("Model", reuse=None, initializer=initializer):
                m = PTBModel(is_training=True, config=config,
                             input_=train_input)
            tf.summary.scalar("Training Loss", m.cost)
            tf.summary.scalar("Learning Rate", m.lr)

        with tf.name_scope("Valid"):
            valid_input = PTBInput(
                config=config, data=valid_data, name="ValidInput")
            with tf.variable_scope("Model", reuse=True, initializer=initializer):
                mvalid = PTBModel(is_training=False,
                                  config=config, input_=valid_input)
            tf.summary.scalar("Validation Loss", mvalid.cost)

        with tf.name_scope("Test"):
            test_input = PTBInput(
                config=eval_config, data=test_data, name="TestInput")
            with tf.variable_scope("Model", reuse=True, initializer=initializer):
                mtest = PTBModel(is_training=False, config=eval_config,
                                 input_=test_input)

        models = {"Train": m, "Valid": mvalid, "Test": mtest}
        for name, model in models.items():
            model.export_ops(name)
        metagraph = tf.train.export_meta_graph()
        if tf.__version__ < "1.1.0" and FLAGS.num_gpus > 1:
            raise ValueError("num_gpus > 1 is not supported for TensorFlow versions "
                             "below 1.1.0")
        soft_placement = False
        if FLAGS.num_gpus > 1:
            soft_placement = True
            util.auto_parallel(metagraph, m)

    with tf.Graph().as_default():
        tf.train.import_meta_graph(metagraph)
        for model in models.values():
            model.import_ops()
        sv = tf.train.Supervisor(logdir=FLAGS.save_path)
        config_proto = tf.ConfigProto(allow_soft_placement=soft_placement)
        with sv.managed_session(config=config_proto) as session:
            for i in range(config.max_max_epoch):
                lr_decay = config.lr_decay ** max(i +
                                                  1 - config.max_epoch, 0.0)
                m.assign_lr(session, config.learning_rate * lr_decay)

                print("Epoch: %d Learning rate: %.3f" %
                      (i + 1, session.run(m.lr)))
                train_perplexity = run_epoch(session, m, eval_op=m.train_op,
                                             verbose=True)
                print("Epoch: %d Train Perplexity: %.3f" %
                      (i + 1, train_perplexity))
                valid_perplexity = run_epoch(session, mvalid)
                print("Epoch: %d Valid Perplexity: %.3f" %
                      (i + 1, valid_perplexity))

            test_perplexity = run_epoch(session, mtest)
            print("Test Perplexity: %.3f" % test_perplexity)

            if FLAGS.save_path:
                print("Saving model to %s." % FLAGS.save_path)
                sv.saver.save(session, FLAGS.save_path,
                              global_step=sv.global_step)


if __name__ == "__main__":
    tf.app.run()

reader.py

"""PTBテキストファイルを解析するユーティリティ。"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections
import os
import sys

import tensorflow as tf

Py3 = sys.version_info[0] == 3


def _read_words(filename):
    with tf.gfile.GFile(filename, "r") as f:
        if Py3:
            return f.read().replace("\n", "<eos>").split()
        else:
            return f.read().decode("utf-8").replace("\n", "<eos>").split()


def _build_vocab(filename):
    data = _read_words(filename)

    counter = collections.Counter(data)
    count_pairs = sorted(counter.items(), key=lambda x: (-x[1], x[0]))

    words, _ = list(zip(*count_pairs))
    word_to_id = dict(zip(words, range(len(words))))

    return word_to_id


def _file_to_word_ids(filename, word_to_id):
    data = _read_words(filename)
    return [word_to_id[word] for word in data if word in word_to_id]


def ptb_raw_data(data_path=None):
    """データディレクトリ "data_path"からPTB生データをロードします。

    PTBテキストファイルを読み込み、文字列を整数IDに変換し、入力のミニバッチ処理を実行します。

    PTBデータセットは、Tomas MikolovのWebページから入手できます:

    http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz

    Args:
      data_path: simple-examples.tgzが抽出されたディレクトリへの文字列パス。

    Returns:
      タプル (train_data, valid_data, test_data, vocabulary)
      各データオブジェクトはPTBIteratorに渡すことができます。
    """

    train_path = os.path.join(data_path, "ptb.train.txt")
    valid_path = os.path.join(data_path, "ptb.valid.txt")
    test_path = os.path.join(data_path, "ptb.test.txt")

    word_to_id = _build_vocab(train_path)
    train_data = _file_to_word_ids(train_path, word_to_id)
    valid_data = _file_to_word_ids(valid_path, word_to_id)
    test_data = _file_to_word_ids(test_path, word_to_id)
    vocabulary = len(word_to_id)
    return train_data, valid_data, test_data, vocabulary


def ptb_producer(raw_data, batch_size, num_steps, name=None):
    """生のPTBデータを繰り返します。

    これは、raw_dataをサンプルのバッチにチャンク化し、これらのバッチから描画されるテンソルを返します。

    Args:
      raw_data: ptb_raw_dataからの生データ出力の1つ
      batch_size: 整数 バッチサイズ
      num_steps: 整数 アンロールの回数
      name: この操作の名前(オプション)

    Returns:
      一組のテンソル、各形状[batch_size, num_steps]
      タプルの2番目の要素は、同じデータが1つ右にタイムシフトされています。

    Raises:
      tf.errors.InvalidArgumentError: batch_sizeまたはnum_stepsが高すぎる場合
    """
    with tf.name_scope(name, "PTBProducer", [raw_data, batch_size, num_steps]):
        raw_data = tf.convert_to_tensor(
            raw_data, name="raw_data", dtype=tf.int32)

        data_len = tf.size(raw_data)
        batch_len = data_len // batch_size
        data = tf.reshape(raw_data[0: batch_size * batch_len],
                          [batch_size, batch_len])

        epoch_size = (batch_len - 1) // num_steps
        assertion = tf.assert_positive(
            epoch_size,
            message="epoch_size == 0, decrease batch_size or num_steps")
        with tf.control_dependencies([assertion]):
            epoch_size = tf.identity(epoch_size, name="epoch_size")

        i = tf.train.range_input_producer(epoch_size, shuffle=False).dequeue()
        x = tf.strided_slice(data, [0, i * num_steps],
                             [batch_size, (i + 1) * num_steps])
        x.set_shape([batch_size, num_steps])
        y = tf.strided_slice(data, [0, i * num_steps + 1],
                             [batch_size, (i + 1) * num_steps + 1])
        y.set_shape([batch_size, num_steps])
        return x, y

util.py

"""Grappler自動並列オプティマイザのユーティリティ。"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from tensorflow.core.framework import variable_pb2
from tensorflow.core.protobuf import rewriter_config_pb2

FLAGS = tf.flags.FLAGS


def export_state_tuples(state_tuples, name):
    for state_tuple in state_tuples:
        tf.add_to_collection(name, state_tuple.c)
        tf.add_to_collection(name, state_tuple.h)


def import_state_tuples(state_tuples, name, num_replicas):
    restored = []
    for i in range(len(state_tuples) * num_replicas):
        c = tf.get_collection_ref(name)[2 * i + 0]
        h = tf.get_collection_ref(name)[2 * i + 1]
        restored.append(tf.contrib.rnn.LSTMStateTuple(c, h))
    return tuple(restored)


def with_prefix(prefix, name):
    """nameに接頭辞を追加します。"""
    return "/".join((prefix, name))


def with_autoparallel_prefix(replica_id, name):
    return with_prefix("AutoParallel-Replica-%d" % replica_id, name)


class UpdateCollection(object):
    """AutoParallelオプティマイザのMetaGraphDefのコレクション情報を更新します。"""

    def __init__(self, metagraph, model):
        self._metagraph = metagraph
        self.replicate_states(model.initial_state_name)
        self.replicate_states(model.final_state_name)
        self.update_snapshot_name("variables")
        self.update_snapshot_name("trainable_variables")

    def update_snapshot_name(self, var_coll_name):
        var_list = self._metagraph.collection_def[var_coll_name]
        for i, value in enumerate(var_list.bytes_list.value):
            var_def = variable_pb2.VariableDef()
            var_def.ParseFromString(value)
            # どういうわけかノード 'Model/global_step/read'はファンアウトを持たず、
            # スナップショットにしか使われないようです。 これは他のすべての変数とは異なります。
            if var_def.snapshot_name != "Model/global_step/read:0":
                var_def.snapshot_name = with_autoparallel_prefix(
                    0, var_def.snapshot_name)
            value = var_def.SerializeToString()
            var_list.bytes_list.value[i] = value

    def replicate_states(self, state_coll_name):
        state_list = self._metagraph.collection_def[state_coll_name]
        num_states = len(state_list.node_list.value)
        for replica_id in range(1, FLAGS.num_gpus):
            for i in range(num_states):
                state_list.node_list.value.append(
                    state_list.node_list.value[i])
        for replica_id in range(FLAGS.num_gpus):
            for i in range(num_states):
                index = replica_id * num_states + i
                state_list.node_list.value[index] = with_autoparallel_prefix(
                    replica_id, state_list.node_list.value[index])


def auto_parallel(metagraph, model):
    from tensorflow.python.grappler import tf_optimizer
    rewriter_config = rewriter_config_pb2.RewriterConfig()
    rewriter_config.optimizers.append("autoparallel")
    rewriter_config.auto_parallel.enable = True
    rewriter_config.auto_parallel.num_replicas = FLAGS.num_gpus
    optimized_graph = tf_optimizer.OptimizeGraph(rewriter_config, metagraph)
    metagraph.graph_def.CopyFrom(optimized_graph)
    UpdateCollection(metagraph, model)

Sequence-to-Sequence Models

Sequence-to-Sequenceモデル
Encdec.jpg
Hands-on – Let's train an NMT model
※Tensorflowr1.4を使用する場合はmasterではなくtf-1.4ブランチ

$ git clone -b tf-1.4 https://github.com/tensorflow/nmt
$ virtualenv --system-site-packages -p python3 seq2seq
$ source ~/seq2seq/bin/activate
(seq2seq)$ pip3 install --upgrade tensorflow
(seq2seq)$ cd nmt
(seq2seq)$ nmt/scripts/download_iwslt15.sh /tmp/nmt_data
(seq2seq)$ mkdir /tmp/nmt_model
# 終わらないので設定変更
(seq2seq)$ python -m nmt.nmt \
    --src=vi --tgt=en \
    --vocab_prefix=/tmp/nmt_data/vocab  \
    --train_prefix=/tmp/nmt_data/train \
    --dev_prefix=/tmp/nmt_data/tst2012  \
    --test_prefix=/tmp/nmt_data/tst2013 \
    --out_dir=/tmp/nmt_model \
    --num_train_steps=1200 \
    --steps_per_stats=100 \
    --num_layers=2 \
    --num_units=128 \
    --dropout=0.2 \
    --metrics=bleu
# tst2013.viからmy_infer_file.viにいくつかの文をコピーペースト
(seq2seq)$ gedit /tmp/my_infer_file.vi
(seq2seq)$ gedit /tmp/nmt_data/tst2013.vi
(seq2seq)$ python -m nmt.nmt \
    --out_dir=/tmp/nmt_model \
    --inference_input_file=/tmp/my_infer_file.vi \
    --inference_output_file=/tmp/nmt_model/output_infer
# /tmp/nmt_modelディレクトリにoutput_inferができる
(seq2seq)$ tensorboard --port 22222 --logdir /tmp/nmt_model
# ブラウザ http://localhost:22222
# CTRL+C
(seq2seq)$ deactivate
$ cd ~
$ rm -r \
    seq2seq \
    nmt \
    /tmp/nmt_data \
    /tmp/nmt_model \
    /tmp/my_infer_file.vi

Hands-on – building an attention-based NMT model
※Tensorflowr1.4を使用する場合はmasterではなくtf-1.4ブランチ

$ git clone -b tf-1.4 https://github.com/tensorflow/nmt
$ virtualenv --system-site-packages -p python3 attention
$ source ~/attention/bin/activate
(attention)$ pip3 install --upgrade tensorflow
(attention)$ cd nmt
(attention)$ nmt/scripts/download_iwslt15.sh /tmp/nmt_data
(attention)$ mkdir /tmp/nmt_attention_model
# 終わらないので設定変更
(attention)$ python -m nmt.nmt \
    --attention=scaled_luong \
    --src=vi --tgt=en \
    --vocab_prefix=/tmp/nmt_data/vocab  \
    --train_prefix=/tmp/nmt_data/train \
    --dev_prefix=/tmp/nmt_data/tst2012  \
    --test_prefix=/tmp/nmt_data/tst2013 \
    --out_dir=/tmp/nmt_attention_model \
    --num_train_steps=1200 \
    --steps_per_stats=100 \
    --num_layers=2 \
    --num_units=128 \
    --dropout=0.2 \
    --metrics=bleu
# tst2013.viからmy_infer_file.viにいくつかの文をコピーペースト
(attention)$ gedit /tmp/my_infer_file.vi
(attention)$ gedit /tmp/nmt_data/tst2013.vi
(attention)$ python -m nmt.nmt \
    --out_dir=/tmp/nmt_attention_model \
    --inference_input_file=/tmp/my_infer_file.vi \
    --inference_output_file=/tmp/nmt_attention_model/output_infer
# /tmp/nmt_attention_modelディレクトリにoutput_inferができる
(attention)$ deactivate
$ cd ~
$ rm -r \
    attention \
    nmt \
    /tmp/nmt_data \
    /tmp/nmt_attention_model \
    /tmp/my_infer_file.vi

nmt.py

"""TensorFlow NMTモデルの実装"""
from __future__ import print_function

import argparse
import os
import random
import sys

# import matplotlib.image as mpimg
import numpy as np
import tensorflow as tf

from . import inference
from . import train
from .utils import evaluation_utils
from .utils import misc_utils as utils
from .utils import vocab_utils

utils.check_tensorflow_version()

FLAGS = None


def add_arguments(parser):
    """ArgumentParserをビルドします。"""
    parser.register("type", "bool", lambda v: v.lower() == "true")

    # ネットワーク
    parser.add_argument("--num_units", type=int,
                        default=32, help="Network size.")
    parser.add_argument("--num_layers", type=int, default=2,
                        help="Network depth.")
    parser.add_argument("--encoder_type", type=str, default="uni", help="""\
      uni | bi | gnmt. For bi, we build num_layers/2 bi-directional layers.For
      gnmt, we build 1 bi-directional layer, and (num_layers - 1) uni-
      directional layers.\
      """)
    parser.add_argument("--residual", type="bool", nargs="?", const=True,
                        default=False,
                        help="Whether to add residual connections.")
    parser.add_argument("--time_major", type="bool", nargs="?", const=True,
                        default=True,
                        help="Whether to use time-major mode for dynamic RNN.")
    parser.add_argument("--num_embeddings_partitions", type=int, default=0,
                        help="Number of partitions for embedding vars.")

    # attentionの仕組み
    parser.add_argument("--attention", type=str, default="", help="""\
      luong | scaled_luong | bahdanau | normed_bahdanau or set to "" for no
      attention\
      """)
    parser.add_argument(
        "--attention_architecture",
        type=str,
        default="standard",
        help="""\
      standard | gnmt | gnmt_v2.
      standard: use top layer to compute attention.
      gnmt: GNMT style of computing attention, use previous bottom layer to
          compute attention.
      gnmt_v2: similar to gnmt, but use current bottom layer to compute
          attention.\
      """)
    parser.add_argument(
        "--pass_hidden_state", type="bool", nargs="?", const=True,
        default=True,
        help="""\
      Whether to pass encoder's hidden state to decoder when using an attention
      based model.\
      """)

    # オプティマイザ
    parser.add_argument("--optimizer", type=str,
                        default="sgd", help="sgd | adam")
    parser.add_argument("--learning_rate", type=float, default=1.0,
                        help="Learning rate. Adam: 0.001 | 0.0001")
    parser.add_argument("--learning_rate_warmup_steps", type=int, default=0,
                        help="How many steps we inverse-decay learning.")
    parser.add_argument("--learning_rate_warmup_factor", type=float, default=1.0,
                        help="The inverse decay factor for each warmup step.")
    parser.add_argument("--start_decay_step", type=int, default=0,
                        help="When we start to decay")
    parser.add_argument("--decay_steps", type=int, default=10000,
                        help="How frequent we decay")
    parser.add_argument("--decay_factor", type=float, default=0.98,
                        help="How much we decay.")
    parser.add_argument(
        "--learning_rate_decay_scheme", type=str, default="", help="""\
      If specified, overwrite start_decay_step, decay_steps, decay_factor.
      Options include:
        luong: after 1/2 num train steps, we start halving the learning rate
        for 5 times before finishing.\
      """)

    parser.add_argument(
        "--num_train_steps", type=int, default=12000, help="Num steps to train.")
    parser.add_argument("--colocate_gradients_with_ops", type="bool", nargs="?",
                        const=True,
                        default=True,
                        help=("Whether try colocating gradients with "
                              "corresponding op"))

    # イニシャライザ
    parser.add_argument("--init_op", type=str, default="uniform",
                        help="uniform | glorot_normal | glorot_uniform")
    parser.add_argument("--init_weight", type=float, default=0.1,
                        help=("for uniform init_op, initialize weights "
                              "between [-this, this]."))

    # データ
    parser.add_argument("--src", type=str, default=None,
                        help="Source suffix, e.g., en.")
    parser.add_argument("--tgt", type=str, default=None,
                        help="Target suffix, e.g., de.")
    parser.add_argument("--train_prefix", type=str, default=None,
                        help="Train prefix, expect files with src/tgt suffixes.")
    parser.add_argument("--dev_prefix", type=str, default=None,
                        help="Dev prefix, expect files with src/tgt suffixes.")
    parser.add_argument("--test_prefix", type=str, default=None,
                        help="Test prefix, expect files with src/tgt suffixes.")
    parser.add_argument("--out_dir", type=str, default=None,
                        help="Store log/model files.")

    # Vocab
    parser.add_argument("--vocab_prefix", type=str, default=None, help="""\
      Vocab prefix, expect files with src/tgt suffixes.If None, extract from
      train files.\
      """)
    parser.add_argument("--sos", type=str, default="<s>",
                        help="Start-of-sentence symbol.")
    parser.add_argument("--eos", type=str, default="</s>",
                        help="End-of-sentence symbol.")
    parser.add_argument("--share_vocab", type="bool", nargs="?", const=True,
                        default=False,
                        help="""\
      Whether to use the source vocab and embeddings for both source and
      target.\
      """)
    parser.add_argument("--check_special_token", type="bool", default=True,
                        help="""\
                      Whether check special sos, eos, unk tokens exist in the
                      vocab files.\
                      """)

    # 配列の長さ
    parser.add_argument("--src_max_len", type=int, default=50,
                        help="Max length of src sequences during training.")
    parser.add_argument("--tgt_max_len", type=int, default=50,
                        help="Max length of tgt sequences during training.")
    parser.add_argument("--src_max_len_infer", type=int, default=None,
                        help="Max length of src sequences during inference.")
    parser.add_argument("--tgt_max_len_infer", type=int, default=None,
                        help="""\
      Max length of tgt sequences during inference.  Also use to restrict the
      maximum decoding length.\
      """)

    # デフォルトの設定がうまくいきます(めったに変更する必要はありません)
    parser.add_argument("--unit_type", type=str, default="lstm",
                        help="lstm | gru | layer_norm_lstm")
    parser.add_argument("--forget_bias", type=float, default=1.0,
                        help="Forget bias for BasicLSTMCell.")
    parser.add_argument("--dropout", type=float, default=0.2,
                        help="Dropout rate (not keep_prob)")
    parser.add_argument("--max_gradient_norm", type=float, default=5.0,
                        help="Clip gradients to this norm.")
    parser.add_argument("--source_reverse", type="bool", nargs="?", const=True,
                        default=False, help="Reverse source sequence.")
    parser.add_argument("--batch_size", type=int,
                        default=128, help="Batch size.")

    parser.add_argument("--steps_per_stats", type=int, default=100,
                        help=("How many training steps to do per stats logging."
                              "Save checkpoint every 10x steps_per_stats"))
    parser.add_argument("--max_train", type=int, default=0,
                        help="Limit on the size of training data (0: no limit).")
    parser.add_argument("--num_buckets", type=int, default=5,
                        help="Put data into similar-length buckets.")

    # BPE
    parser.add_argument("--bpe_delimiter", type=str, default=None,
                        help="Set to @@ to activate BPE."
                             "Implicitly sets subword_option to 'bpe' when set.")

    # SPM
    parser.add_argument("--subword_option", type=str, default=None,
                        choices=["bpe", "spm"],
                        help="""\
                      Set to bpe or spm to activate subword desegmentation.\
                      """)

    # その他
    parser.add_argument("--num_gpus", type=int, default=1,
                        help="Number of gpus in each worker.")
    parser.add_argument("--log_device_placement", type="bool", nargs="?",
                        const=True, default=False, help="Debug GPU allocation.")
    parser.add_argument("--metrics", type=str, default="bleu",
                        help=("Comma-separated list of evaluations "
                              "metrics (bleu,rouge,accuracy)"))
    parser.add_argument("--steps_per_external_eval", type=int, default=None,
                        help="""\
      How many training steps to do per external evaluation.  Automatically set
      based on data if None.\
      """)
    parser.add_argument("--scope", type=str, default=None,
                        help="scope to put variables under")
    parser.add_argument("--hparams_path", type=str, default=None,
                        help=("Path to standard hparams json file that overrides"
                              "hparams values from FLAGS."))
    parser.add_argument("--random_seed", type=int, default=None,
                        help="Random seed (>0, set a specific seed).")
    parser.add_argument("--override_loaded_hparams", type="bool", nargs="?",
                        const=True, default=False,
                        help="Override loaded hparams with values specified")

    # 推論
    parser.add_argument("--ckpt", type=str, default="",
                        help="Checkpoint file to load a model for inference.")
    parser.add_argument("--inference_input_file", type=str, default=None,
                        help="Set to the text to decode.")
    parser.add_argument("--inference_list", type=str, default=None,
                        help=("A comma-separated list of sentence indices "
                              "(0-based) to decode."))
    parser.add_argument("--infer_batch_size", type=int, default=32,
                        help="Batch size for inference mode.")
    parser.add_argument("--inference_output_file", type=str, default=None,
                        help="Output file to store decoding results.")
    parser.add_argument("--inference_ref_file", type=str, default=None,
                        help=("""\
      Reference file to compute evaluation scores (if provided).\
      """))
    parser.add_argument("--beam_width", type=int, default=0,
                        help=("""\
      beam width when using beam search decoder. If 0 (default), use standard
      decoder with greedy helper.\
      """))
    parser.add_argument("--length_penalty_weight", type=float, default=0.0,
                        help="Length penalty for beam search.")
    parser.add_argument("--num_translations_per_input", type=int, default=1,
                        help=("""\
      Number of translations generated for each sentence. This is only used for
      inference.\
      """))

    # Job info
    parser.add_argument("--jobid", type=int, default=0,
                        help="Task id of the worker.")
    parser.add_argument("--num_workers", type=int, default=1,
                        help="Number of workers (inference only).")


def create_hparams(flags):
    """トレーニングhparamsを作成します。"""
    return tf.contrib.training.HParams(
        # データ
        src=flags.src,
        tgt=flags.tgt,
        train_prefix=flags.train_prefix,
        dev_prefix=flags.dev_prefix,
        test_prefix=flags.test_prefix,
        vocab_prefix=flags.vocab_prefix,
        out_dir=flags.out_dir,

        # ネットワーク
        num_units=flags.num_units,
        num_layers=flags.num_layers,
        dropout=flags.dropout,
        unit_type=flags.unit_type,
        encoder_type=flags.encoder_type,
        residual=flags.residual,
        time_major=flags.time_major,
        num_embeddings_partitions=flags.num_embeddings_partitions,

        # Attentionメカニズム
        attention=flags.attention,
        attention_architecture=flags.attention_architecture,
        pass_hidden_state=flags.pass_hidden_state,

        # 訓練
        optimizer=flags.optimizer,
        num_train_steps=flags.num_train_steps,
        batch_size=flags.batch_size,
        init_op=flags.init_op,
        init_weight=flags.init_weight,
        max_gradient_norm=flags.max_gradient_norm,
        learning_rate=flags.learning_rate,
        learning_rate_warmup_steps=flags.learning_rate_warmup_steps,
        learning_rate_warmup_factor=flags.learning_rate_warmup_factor,
        start_decay_step=flags.start_decay_step,
        decay_factor=flags.decay_factor,
        decay_steps=flags.decay_steps,
        learning_rate_decay_scheme=flags.learning_rate_decay_scheme,
        colocate_gradients_with_ops=flags.colocate_gradients_with_ops,

        # データ制約
        num_buckets=flags.num_buckets,
        max_train=flags.max_train,
        src_max_len=flags.src_max_len,
        tgt_max_len=flags.tgt_max_len,
        source_reverse=flags.source_reverse,

        # 推論
        src_max_len_infer=flags.src_max_len_infer,
        tgt_max_len_infer=flags.tgt_max_len_infer,
        infer_batch_size=flags.infer_batch_size,
        beam_width=flags.beam_width,
        length_penalty_weight=flags.length_penalty_weight,
        num_translations_per_input=flags.num_translations_per_input,

        # Vocab
        sos=flags.sos if flags.sos else vocab_utils.SOS,
        eos=flags.eos if flags.eos else vocab_utils.EOS,
        bpe_delimiter=flags.bpe_delimiter,
        subword_option=flags.subword_option,
        check_special_token=flags.check_special_token,

        # その他
        forget_bias=flags.forget_bias,
        num_gpus=flags.num_gpus,
        epoch_step=0,  # record where we were within an epoch.
        steps_per_stats=flags.steps_per_stats,
        steps_per_external_eval=flags.steps_per_external_eval,
        share_vocab=flags.share_vocab,
        metrics=flags.metrics.split(","),
        log_device_placement=flags.log_device_placement,
        random_seed=flags.random_seed,
        override_loaded_hparams=flags.override_loaded_hparams,
    )


def extend_hparams(hparams):
    """トレーニングhparamsを拡張する。"""
    # Sanity checks
    if hparams.encoder_type == "bi" and hparams.num_layers % 2 != 0:
        raise ValueError("For bi, num_layers %d should be even" %
                         hparams.num_layers)
    if (hparams.attention_architecture in ["gnmt"] and
            hparams.num_layers < 2):
        raise ValueError("For gnmt attention architecture, "
                         "num_layers %d should be >= 2" % hparams.num_layers)

    if hparams.subword_option and hparams.subword_option not in ["spm", "bpe"]:
        raise ValueError("subword option must be either spm, or bpe")
    if hparams.bpe_delimiter and hparams.bpe_delimiter != "@@":
        raise ValueError("BPE delimiter value must be '@@' %s",
                         hparams.bpe_delimiter)
    if hparams.bpe_delimiter == "@@":
        # bpe_delimiterが設定されている場合、subword_optionは自動的にbpeに設定されます
        if hparams.subword_option == "spm":
            raise ValueError("Unable to set the subword option to spm "
                             "if bpe delimiter is set")
        else:
            hparams.subword_option = "bpe"

    # フラグ
    utils.print_out("# hparams:")
    utils.print_out("  src=%s" % hparams.src)
    utils.print_out("  tgt=%s" % hparams.tgt)
    utils.print_out("  train_prefix=%s" % hparams.train_prefix)
    utils.print_out("  dev_prefix=%s" % hparams.dev_prefix)
    utils.print_out("  test_prefix=%s" % hparams.test_prefix)
    utils.print_out("  out_dir=%s" % hparams.out_dir)

    # num_residual_layersを設定する
    if hparams.residual and hparams.num_layers > 1:
        if hparams.encoder_type == "gnmt":
            # GNMTエンコーダの第1の一方向層(双方向層の後)は、
            # 入力がfw_cellとbw_cellの出力の連結であるために残っている接続を持つことができません。
            num_residual_layers = hparams.num_layers - 2
        else:
            num_residual_layers = hparams.num_layers - 1
    else:
        num_residual_layers = 0
    hparams.add_hparam("num_residual_layers", num_residual_layers)

    # Vocab
    # 最初にvocabファイル名を取得する
    if hparams.vocab_prefix:
        src_vocab_file = hparams.vocab_prefix + "." + hparams.src
        tgt_vocab_file = hparams.vocab_prefix + "." + hparams.tgt
    else:
        raise ValueError("hparams.vocab_prefix must be provided.")

    # Source vocab
    src_vocab_size, src_vocab_file = vocab_utils.check_vocab(
        src_vocab_file,
        hparams.out_dir,
        check_special_token=hparams.check_special_token,
        sos=hparams.sos,
        eos=hparams.eos,
        unk=vocab_utils.UNK)

    # Target vocab
    if hparams.share_vocab:
        utils.print_out("  using source vocab for target")
        tgt_vocab_file = src_vocab_file
        tgt_vocab_size = src_vocab_size
    else:
        tgt_vocab_size, tgt_vocab_file = vocab_utils.check_vocab(
            tgt_vocab_file,
            hparams.out_dir,
            check_special_token=hparams.check_special_token,
            sos=hparams.sos,
            eos=hparams.eos,
            unk=vocab_utils.UNK)
    hparams.add_hparam("src_vocab_size", src_vocab_size)
    hparams.add_hparam("tgt_vocab_size", tgt_vocab_size)
    hparams.add_hparam("src_vocab_file", src_vocab_file)
    hparams.add_hparam("tgt_vocab_file", tgt_vocab_file)

    # out_dirをチェック
    if not tf.gfile.Exists(hparams.out_dir):
        utils.print_out("# Creating output directory %s ..." % hparams.out_dir)
        tf.gfile.MakeDirs(hparams.out_dir)

    # 評価
    for metric in hparams.metrics:
        hparams.add_hparam("best_" + metric, 0)  # larger is better
        best_metric_dir = os.path.join(hparams.out_dir, "best_" + metric)
        hparams.add_hparam("best_" + metric + "_dir", best_metric_dir)
        tf.gfile.MakeDirs(best_metric_dir)

    return hparams


def ensure_compatible_hparams(hparams, default_hparams, hparams_path):
    """ロードされたhparamsが新しい変更と互換性があることを確認してください。"""
    default_hparams = utils.maybe_parse_standard_hparams(
        default_hparams, hparams_path)

    # 互換性のある理由から、default_hparamsに新しいフィールドがある場合は、
    # それらを現在のhparamsに追加します
    default_config = default_hparams.values()
    config = hparams.values()
    for key in default_config:
        if key not in config:
            hparams.add_hparam(key, default_config[key])

    # override_loaded_hparams = Trueの場合、すべてのhparamsのキーを更新する
    if default_hparams.override_loaded_hparams:
        for key in default_config:
            if getattr(hparams, key) != default_config[key]:
                utils.print_out("# Updating hparams.%s: %s -> %s" %
                                (key, str(getattr(hparams, key)),
                                 str(default_config[key])))
                setattr(hparams, key, default_config[key])
    return hparams


def create_or_load_hparams(
        out_dir, default_hparams, hparams_path, save_hparams=True):
    """out_dirからhparamsを作成するか、hparamsをロードしてください。"""
    hparams = utils.load_hparams(out_dir)
    if not hparams:
        hparams = default_hparams
        hparams = utils.maybe_parse_standard_hparams(
            hparams, hparams_path)
        hparams = extend_hparams(hparams)
    else:
        hparams = ensure_compatible_hparams(
            hparams, default_hparams, hparams_path)

    # HParamsを保存
    if save_hparams:
        utils.save_hparams(out_dir, hparams)
        for metric in hparams.metrics:
            utils.save_hparams(
                getattr(hparams, "best_" + metric + "_dir"), hparams)

    # HParamsをprint
    utils.print_hparams(hparams)
    return hparams


def run_main(flags, default_hparams, train_fn, inference_fn, target_session=""):
    """メインを実行"""
    # Job
    jobid = flags.jobid
    num_workers = flags.num_workers
    utils.print_out("# Job id %d" % jobid)

    # ランダム
    random_seed = flags.random_seed
    if random_seed is not None and random_seed > 0:
        utils.print_out("# Set random seed to %d" % random_seed)
        random.seed(random_seed + jobid)
        np.random.seed(random_seed + jobid)

    ## 訓練 / デコード
    out_dir = flags.out_dir
    if not tf.gfile.Exists(out_dir):
        tf.gfile.MakeDirs(out_dir)

    # hparamsをロード
    hparams = create_or_load_hparams(
        out_dir, default_hparams, flags.hparams_path, save_hparams=(jobid == 0))

    if flags.inference_input_file:
        # 推論指数
        hparams.inference_indices = None
        if flags.inference_list:
            (hparams.inference_indices) = (
                [int(token) for token in flags.inference_list.split(",")])

        # 推論
        trans_file = flags.inference_output_file
        ckpt = flags.ckpt
        if not ckpt:
            ckpt = tf.train.latest_checkpoint(out_dir)
        inference_fn(ckpt, flags.inference_input_file,
                     trans_file, hparams, num_workers, jobid)

        # 評価
        ref_file = flags.inference_ref_file
        if ref_file and tf.gfile.Exists(trans_file):
            for metric in hparams.metrics:
                score = evaluation_utils.evaluate(
                    ref_file,
                    trans_file,
                    metric,
                    hparams.subword_option)
                utils.print_out("  %s: %.1f" % (metric, score))
    else:
        # 訓練
        train_fn(hparams, target_session=target_session)


def main(unused_argv):
    default_hparams = create_hparams(FLAGS)
    train_fn = train.train
    inference_fn = inference.inference
    run_main(FLAGS, default_hparams, train_fn, inference_fn)


if __name__ == "__main__":
    nmt_parser = argparse.ArgumentParser()
    add_arguments(nmt_parser)
    FLAGS, unparsed = nmt_parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

train.py

"""NMTモデルのトレーニング用"""
from __future__ import print_function

import math
import os
import random
import time

import tensorflow as tf

from . import attention_model
from . import gnmt_model
from . import inference
from . import model as nmt_model
from . import model_helper
from .utils import misc_utils as utils
from .utils import nmt_utils

utils.check_tensorflow_version()

__all__ = [
    "run_sample_decode",
    "run_internal_eval", "run_external_eval", "run_full_eval", "train"
]


def run_sample_decode(infer_model, infer_sess, model_dir, hparams,
                      summary_writer, src_data, tgt_data):
    """サンプルは、src_dataからランダムな文をデコードします。"""
    with infer_model.graph.as_default():
        loaded_infer_model, global_step = model_helper.create_or_load_model(
            infer_model.model, model_dir, infer_sess, "infer")

    _sample_decode(loaded_infer_model, global_step, infer_sess, hparams,
                   infer_model.iterator, src_data, tgt_data,
                   infer_model.src_placeholder,
                   infer_model.batch_size_placeholder, summary_writer)


def run_internal_eval(
        eval_model, eval_sess, model_dir, hparams, summary_writer):
    """dev / test両方の内部評価(perplexity)を計算します。"""
    with eval_model.graph.as_default():
        loaded_eval_model, global_step = model_helper.create_or_load_model(
            eval_model.model, model_dir, eval_sess, "eval")

    dev_src_file = "%s.%s" % (hparams.dev_prefix, hparams.src)
    dev_tgt_file = "%s.%s" % (hparams.dev_prefix, hparams.tgt)
    dev_eval_iterator_feed_dict = {
        eval_model.src_file_placeholder: dev_src_file,
        eval_model.tgt_file_placeholder: dev_tgt_file
    }

    dev_ppl = _internal_eval(loaded_eval_model, global_step, eval_sess,
                             eval_model.iterator, dev_eval_iterator_feed_dict,
                             summary_writer, "dev")
    test_ppl = None
    if hparams.test_prefix:
        test_src_file = "%s.%s" % (hparams.test_prefix, hparams.src)
        test_tgt_file = "%s.%s" % (hparams.test_prefix, hparams.tgt)
        test_eval_iterator_feed_dict = {
            eval_model.src_file_placeholder: test_src_file,
            eval_model.tgt_file_placeholder: test_tgt_file
        }
        test_ppl = _internal_eval(loaded_eval_model, global_step, eval_sess,
                                  eval_model.iterator, test_eval_iterator_feed_dict,
                                  summary_writer, "test")
    return dev_ppl, test_ppl


def run_external_eval(infer_model, infer_sess, model_dir, hparams,
                      summary_writer, save_best_dev=True):
    """dev / testの両方の外部評価(bleu, rouge, など)を計算します。"""
    with infer_model.graph.as_default():
        loaded_infer_model, global_step = model_helper.create_or_load_model(
            infer_model.model, model_dir, infer_sess, "infer")

    dev_src_file = "%s.%s" % (hparams.dev_prefix, hparams.src)
    dev_tgt_file = "%s.%s" % (hparams.dev_prefix, hparams.tgt)
    dev_infer_iterator_feed_dict = {
        infer_model.src_placeholder: inference.load_data(dev_src_file),
        infer_model.batch_size_placeholder: hparams.infer_batch_size,
    }
    dev_scores = _external_eval(
        loaded_infer_model,
        global_step,
        infer_sess,
        hparams,
        infer_model.iterator,
        dev_infer_iterator_feed_dict,
        dev_tgt_file,
        "dev",
        summary_writer,
        save_on_best=save_best_dev)

    test_scores = None
    if hparams.test_prefix:
        test_src_file = "%s.%s" % (hparams.test_prefix, hparams.src)
        test_tgt_file = "%s.%s" % (hparams.test_prefix, hparams.tgt)
        test_infer_iterator_feed_dict = {
            infer_model.src_placeholder: inference.load_data(test_src_file),
            infer_model.batch_size_placeholder: hparams.infer_batch_size,
        }
        test_scores = _external_eval(
            loaded_infer_model,
            global_step,
            infer_sess,
            hparams,
            infer_model.iterator,
            test_infer_iterator_feed_dict,
            test_tgt_file,
            "test",
            summary_writer,
            save_on_best=False)
    return dev_scores, test_scores, global_step


def run_full_eval(model_dir, infer_model, infer_sess, eval_model, eval_sess,
                  hparams, summary_writer, sample_src_data, sample_tgt_data):
    """sample_decode、internal_eval、およびexternal_evalを実行するためのラッパー。"""
    run_sample_decode(infer_model, infer_sess, model_dir, hparams, summary_writer,
                      sample_src_data, sample_tgt_data)
    dev_ppl, test_ppl = run_internal_eval(
        eval_model, eval_sess, model_dir, hparams, summary_writer)
    dev_scores, test_scores, global_step = run_external_eval(
        infer_model, infer_sess, model_dir, hparams, summary_writer)

    result_summary = _format_results(
        "dev", dev_ppl, dev_scores, hparams.metrics)
    if hparams.test_prefix:
        result_summary += ", " + _format_results("test", test_ppl, test_scores,
                                                 hparams.metrics)

    return result_summary, global_step, dev_scores, test_scores, dev_ppl, test_ppl


def train(hparams, scope=None, target_session=""):
    """翻訳モデルを訓練する。"""
    log_device_placement = hparams.log_device_placement
    out_dir = hparams.out_dir
    num_train_steps = hparams.num_train_steps
    steps_per_stats = hparams.steps_per_stats
    steps_per_external_eval = hparams.steps_per_external_eval
    steps_per_eval = 10 * steps_per_stats
    if not steps_per_external_eval:
        steps_per_external_eval = 5 * steps_per_eval

    if not hparams.attention:
        model_creator = nmt_model.Model
    elif hparams.attention_architecture == "standard":
        model_creator = attention_model.AttentionModel
    elif hparams.attention_architecture in ["gnmt", "gnmt_v2"]:
        model_creator = gnmt_model.GNMTModel
    else:
        raise ValueError("Unknown model architecture")

    train_model = model_helper.create_train_model(
        model_creator, hparams, scope)
    eval_model = model_helper.create_eval_model(model_creator, hparams, scope)
    infer_model = model_helper.create_infer_model(
        model_creator, hparams, scope)

    # サンプルのデコード用にデータをプリロードします。
    dev_src_file = "%s.%s" % (hparams.dev_prefix, hparams.src)
    dev_tgt_file = "%s.%s" % (hparams.dev_prefix, hparams.tgt)
    sample_src_data = inference.load_data(dev_src_file)
    sample_tgt_data = inference.load_data(dev_tgt_file)

    summary_name = "train_log"
    model_dir = hparams.out_dir

    # ログファイルと出力ファイル
    log_file = os.path.join(out_dir, "log_%d" % time.time())
    log_f = tf.gfile.GFile(log_file, mode="a")
    utils.print_out("# log_file=%s" % log_file, log_f)

    avg_step_time = 0.0

    # TensorFlowモデル
    config_proto = utils.get_config_proto(
        log_device_placement=log_device_placement)

    train_sess = tf.Session(
        target=target_session, config=config_proto, graph=train_model.graph)
    eval_sess = tf.Session(
        target=target_session, config=config_proto, graph=eval_model.graph)
    infer_sess = tf.Session(
        target=target_session, config=config_proto, graph=infer_model.graph)

    with train_model.graph.as_default():
        loaded_train_model, global_step = model_helper.create_or_load_model(
            train_model.model, model_dir, train_sess, "train")

    # 要約書き出し
    summary_writer = tf.summary.FileWriter(
        os.path.join(out_dir, summary_name), train_model.graph)

    # 最初の評価
    run_full_eval(
        model_dir, infer_model, infer_sess,
        eval_model, eval_sess, hparams,
        summary_writer, sample_src_data,
        sample_tgt_data)

    last_stats_step = global_step
    last_eval_step = global_step
    last_external_eval_step = global_step

    # これはトレーニングループです。
    step_time, checkpoint_loss, checkpoint_predict_count = 0.0, 0.0, 0.0
    checkpoint_total_count = 0.0
    speed, train_ppl = 0.0, 0.0
    start_train_time = time.time()

    utils.print_out(
        "# Start step %d, lr %g, %s" %
        (global_step, loaded_train_model.learning_rate.eval(session=train_sess),
         time.ctime()),
        log_f)

    # すべてのイテレータを初期化する
    skip_count = hparams.batch_size * hparams.epoch_step
    utils.print_out("# Init train iterator, skipping %d elements" % skip_count)
    train_sess.run(
        train_model.iterator.initializer,
        feed_dict={train_model.skip_count_placeholder: skip_count})

    while global_step < num_train_steps:
        ### ステップを実行する ###
        start_time = time.time()
        try:
            step_result = loaded_train_model.train(train_sess)
            (_, step_loss, step_predict_count, step_summary, global_step,
             step_word_count, batch_size) = step_result
            hparams.epoch_step += 1
        except tf.errors.OutOfRangeError:
            # トレーニングデータセットを終了しました。次のエポックに行く。
            hparams.epoch_step = 0
            utils.print_out(
                "# Finished an epoch, step %d. Perform external evaluation" %
                global_step)
            run_sample_decode(infer_model, infer_sess,
                              model_dir, hparams, summary_writer, sample_src_data,
                              sample_tgt_data)
            dev_scores, test_scores, _ = run_external_eval(
                infer_model, infer_sess, model_dir,
                hparams, summary_writer)
            train_sess.run(
                train_model.iterator.initializer,
                feed_dict={train_model.skip_count_placeholder: 0})
            continue

        # ステップサマリーを作成します。
        summary_writer.add_summary(step_summary, global_step)

        # 統計を更新する
        step_time += (time.time() - start_time)

        checkpoint_loss += (step_loss * batch_size)
        checkpoint_predict_count += step_predict_count
        checkpoint_total_count += float(step_word_count)

        # 一度、統計を出力します。
        if global_step - last_stats_step >= steps_per_stats:
            last_stats_step = global_step

            # 前のエポックの統計情報を出力します。
            avg_step_time = step_time / steps_per_stats
            train_ppl = utils.safe_exp(
                checkpoint_loss / checkpoint_predict_count)
            speed = checkpoint_total_count / (1000 * step_time)
            utils.print_out(
                "  global step %d lr %g "
                "step-time %.2fs wps %.2fK ppl %.2f %s" %
                (global_step,
                 loaded_train_model.learning_rate.eval(session=train_sess),
                 avg_step_time, speed, train_ppl, _get_best_results(hparams)),
                log_f)
            if math.isnan(train_ppl):
                break

            # タイマと損失をリセットします。
            step_time, checkpoint_loss, checkpoint_predict_count = 0.0, 0.0, 0.0
            checkpoint_total_count = 0.0

        if global_step - last_eval_step >= steps_per_eval:
            last_eval_step = global_step

            utils.print_out("# Save eval, global step %d" % global_step)
            utils.add_summary(summary_writer, global_step,
                              "train_ppl", train_ppl)

            # チェックポイントを保存する
            loaded_train_model.saver.save(
                train_sess,
                os.path.join(out_dir, "translate.ckpt"),
                global_step=global_step)

            # dev/testの評価
            run_sample_decode(infer_model, infer_sess,
                              model_dir, hparams, summary_writer, sample_src_data,
                              sample_tgt_data)
            dev_ppl, test_ppl = run_internal_eval(
                eval_model, eval_sess, model_dir, hparams, summary_writer)

        if global_step - last_external_eval_step >= steps_per_external_eval:
            last_external_eval_step = global_step

            # チェックポイントを保存する
            loaded_train_model.saver.save(
                train_sess,
                os.path.join(out_dir, "translate.ckpt"),
                global_step=global_step)
            run_sample_decode(infer_model, infer_sess,
                              model_dir, hparams, summary_writer, sample_src_data,
                              sample_tgt_data)
            dev_scores, test_scores, _ = run_external_eval(
                infer_model, infer_sess, model_dir,
                hparams, summary_writer)

    # トレーニングを終えた
    loaded_train_model.saver.save(
        train_sess,
        os.path.join(out_dir, "translate.ckpt"),
        global_step=global_step)

    result_summary, _, dev_scores, test_scores, dev_ppl, test_ppl = run_full_eval(
        model_dir, infer_model, infer_sess,
        eval_model, eval_sess, hparams,
        summary_writer, sample_src_data,
        sample_tgt_data)
    utils.print_out(
        "# Final, step %d lr %g "
        "step-time %.2f wps %.2fK ppl %.2f, %s, %s" %
        (global_step, loaded_train_model.learning_rate.eval(session=train_sess),
         avg_step_time, speed, train_ppl, result_summary, time.ctime()),
        log_f)
    utils.print_time("# Done training!", start_train_time)

    utils.print_out("# Start evaluating saved best models.")
    for metric in hparams.metrics:
        best_model_dir = getattr(hparams, "best_" + metric + "_dir")
        result_summary, best_global_step, _, _, _, _ = run_full_eval(
            best_model_dir, infer_model, infer_sess, eval_model, eval_sess, hparams,
            summary_writer, sample_src_data, sample_tgt_data)
        utils.print_out("# Best %s, step %d "
                        "step-time %.2f wps %.2fK, %s, %s" %
                        (metric, best_global_step, avg_step_time, speed,
                         result_summary, time.ctime()), log_f)

    summary_writer.close()
    return (dev_scores, test_scores, dev_ppl, test_ppl, global_step)


def _format_results(name, ppl, scores, metrics):
    """結果をフォーマットします。"""
    result_str = "%s ppl %.2f" % (name, ppl)
    if scores:
        for metric in metrics:
            result_str += ", %s %s %.1f" % (name, metric, scores[metric])
    return result_str


def _get_best_results(hparams):
    """現在の最良の結果の要約。"""
    tokens = []
    for metric in hparams.metrics:
        tokens.append("%s %.2f" % (metric, getattr(hparams, "best_" + metric)))
    return ", ".join(tokens)


def _internal_eval(model, global_step, sess, iterator, iterator_feed_dict,
                   summary_writer, label):
    """perplexityを計算する。"""
    sess.run(iterator.initializer, feed_dict=iterator_feed_dict)
    ppl = model_helper.compute_perplexity(model, sess, label)
    utils.add_summary(summary_writer, global_step, "%s_ppl" % label, ppl)
    return ppl


def _sample_decode(model, global_step, sess, hparams, iterator, src_data,
                   tgt_data, iterator_src_placeholder,
                   iterator_batch_size_placeholder, summary_writer):
    """文を選んでデコードする。"""
    decode_id = random.randint(0, len(src_data) - 1)
    utils.print_out("  # %d" % decode_id)

    iterator_feed_dict = {
        iterator_src_placeholder: [src_data[decode_id]],
        iterator_batch_size_placeholder: 1,
    }
    sess.run(iterator.initializer, feed_dict=iterator_feed_dict)

    nmt_outputs, attention_summary = model.decode(sess)

    if hparams.beam_width > 0:
        # 一番上の翻訳を取得します。
        nmt_outputs = nmt_outputs[0]

    translation = nmt_utils.get_translation(
        nmt_outputs,
        sent_id=0,
        tgt_eos=hparams.eos,
        subword_option=hparams.subword_option)
    utils.print_out("    src: %s" % src_data[decode_id])
    utils.print_out("    ref: %s" % tgt_data[decode_id])
    utils.print_out(b"    nmt: " + translation)

    # 概要
    if attention_summary is not None:
        summary_writer.add_summary(attention_summary, global_step)


def _external_eval(model, global_step, sess, hparams, iterator,
                   iterator_feed_dict, tgt_file, label, summary_writer,
                   save_on_best):
    """BLEUやROUGEなどの外部評価。"""
    out_dir = hparams.out_dir
    decode = global_step > 0
    if decode:
        utils.print_out("# External evaluation, global step %d" % global_step)

    sess.run(iterator.initializer, feed_dict=iterator_feed_dict)

    output = os.path.join(out_dir, "output_%s" % label)
    scores = nmt_utils.decode_and_evaluate(
        label,
        model,
        sess,
        output,
        ref_file=tgt_file,
        metrics=hparams.metrics,
        subword_option=hparams.subword_option,
        beam_width=hparams.beam_width,
        tgt_eos=hparams.eos,
        decode=decode)
    # 最適な指標を保存
    if decode:
        for metric in hparams.metrics:
            utils.add_summary(summary_writer, global_step, "%s_%s" % (label, metric),
                              scores[metric])
            # metric: 大きい方が良い
            if save_on_best and scores[metric] > getattr(hparams, "best_" + metric):
                setattr(hparams, "best_" + metric, scores[metric])
                model.saver.save(
                    sess,
                    os.path.join(
                        getattr(hparams, "best_" + metric + "_dir"), "translate.ckpt"),
                    global_step=model.global_step)
        utils.save_hparams(out_dir, hparams)
    return scores

inference.py

"""訓練されたモデルを与えられたテスト集合について推論を行う"""
from __future__ import print_function

import codecs
import time

import tensorflow as tf

from . import attention_model
from . import gnmt_model
from . import model as nmt_model
from . import model_helper
from .utils import misc_utils as utils
from .utils import nmt_utils

__all__ = ["load_data", "inference",
           "single_worker_inference", "multi_worker_inference"]


def _decode_inference_indices(model, sess, output_infer,
                              output_infer_summary_prefix,
                              inference_indices,
                              tgt_eos,
                              subword_option):
    """特定の文のセットだけをデコードします。"""
    utils.print_out("  decoding to output %s , num sents %d." %
                    (output_infer, len(inference_indices)))
    start_time = time.time()
    with codecs.getwriter("utf-8")(
            tf.gfile.GFile(output_infer, mode="wb")) as trans_f:
        trans_f.write("")  # ファイルが作成されるように空の文字列を書き込みます。
        for decode_id in inference_indices:
            nmt_outputs, infer_summary = model.decode(sess)

            # テキスト翻訳を得る
            assert nmt_outputs.shape[0] == 1
            translation = nmt_utils.get_translation(
                nmt_outputs,
                sent_id=0,
                tgt_eos=tgt_eos,
                subword_option=subword_option)

            if infer_summary is not None:  # Attentionモデル
                image_file = output_infer_summary_prefix + \
                    str(decode_id) + ".png"
                utils.print_out("  save attention image to %s*" % image_file)
                image_summ = tf.Summary()
                image_summ.ParseFromString(infer_summary)
                with tf.gfile.GFile(image_file, mode="w") as img_f:
                    img_f.write(image_summ.value[0].image.encoded_image_string)

            trans_f.write("%s\n" % translation)
            utils.print_out(translation + b"\n")
    utils.print_time("  done", start_time)


def load_data(inference_input_file, hparams=None):
    """推論データを読み込む。"""
    with codecs.getreader("utf-8")(
            tf.gfile.GFile(inference_input_file, mode="rb")) as f:
        inference_data = f.read().splitlines()

    if hparams and hparams.inference_indices:
        inference_data = [inference_data[i] for i in hparams.inference_indices]

    return inference_data


def inference(ckpt,
              inference_input_file,
              inference_output_file,
              hparams,
              num_workers=1,
              jobid=0,
              scope=None):
    """翻訳を実行します。"""
    if hparams.inference_indices:
        assert num_workers == 1

    if not hparams.attention:
        model_creator = nmt_model.Model
    elif hparams.attention_architecture == "standard":
        model_creator = attention_model.AttentionModel
    elif hparams.attention_architecture in ["gnmt", "gnmt_v2"]:
        model_creator = gnmt_model.GNMTModel
    else:
        raise ValueError("Unknown model architecture")
    infer_model = model_helper.create_infer_model(
        model_creator, hparams, scope)

    if num_workers == 1:
        single_worker_inference(
            infer_model,
            ckpt,
            inference_input_file,
            inference_output_file,
            hparams)
    else:
        multi_worker_inference(
            infer_model,
            ckpt,
            inference_input_file,
            inference_output_file,
            hparams,
            num_workers=num_workers,
            jobid=jobid)


def single_worker_inference(infer_model,
                            ckpt,
                            inference_input_file,
                            inference_output_file,
                            hparams):
    """single workerを推論する。"""
    output_infer = inference_output_file

    # データを読み込む
    infer_data = load_data(inference_input_file, hparams)

    with tf.Session(
            graph=infer_model.graph, config=utils.get_config_proto()) as sess:
        loaded_infer_model = model_helper.load_model(
            infer_model.model, ckpt, sess, "infer")
        sess.run(
            infer_model.iterator.initializer,
            feed_dict={
                infer_model.src_placeholder: infer_data,
                infer_model.batch_size_placeholder: hparams.infer_batch_size
            })
        # デコード
        utils.print_out("# Start decoding")
        if hparams.inference_indices:
            _decode_inference_indices(
                loaded_infer_model,
                sess,
                output_infer=output_infer,
                output_infer_summary_prefix=output_infer,
                inference_indices=hparams.inference_indices,
                tgt_eos=hparams.eos,
                subword_option=hparams.subword_option)
        else:
            nmt_utils.decode_and_evaluate(
                "infer",
                loaded_infer_model,
                sess,
                output_infer,
                ref_file=None,
                metrics=hparams.metrics,
                subword_option=hparams.subword_option,
                beam_width=hparams.beam_width,
                tgt_eos=hparams.eos,
                num_translations_per_input=hparams.num_translations_per_input)


def multi_worker_inference(infer_model,
                           ckpt,
                           inference_input_file,
                           inference_output_file,
                           hparams,
                           num_workers,
                           jobid):
    """multiple workersを用いた推論。"""
    assert num_workers > 1

    final_output_infer = inference_output_file
    output_infer = "%s_%d" % (inference_output_file, jobid)
    output_infer_done = "%s_done_%d" % (inference_output_file, jobid)

    # データを読み込む
    infer_data = load_data(inference_input_file, hparams)

    # データをmultiple workersに分割する
    total_load = len(infer_data)
    load_per_worker = int((total_load - 1) / num_workers) + 1
    start_position = jobid * load_per_worker
    end_position = min(start_position + load_per_worker, total_load)
    infer_data = infer_data[start_position:end_position]

    with tf.Session(
            graph=infer_model.graph, config=utils.get_config_proto()) as sess:
        loaded_infer_model = model_helper.load_model(
            infer_model.model, ckpt, sess, "infer")
        sess.run(infer_model.iterator.initializer,
                 {
                     infer_model.src_placeholder: infer_data,
                     infer_model.batch_size_placeholder: hparams.infer_batch_size
                 })
        # デコード
        utils.print_out("# Start decoding")
        nmt_utils.decode_and_evaluate(
            "infer",
            loaded_infer_model,
            sess,
            output_infer,
            ref_file=None,
            metrics=hparams.metrics,
            subword_option=hparams.subword_option,
            beam_width=hparams.beam_width,
            tgt_eos=hparams.eos,
            num_translations_per_input=hparams.num_translations_per_input)

        # ファイルの書き込みが完了したことを示すファイル名を変更します。
        tf.gfile.Rename(output_infer, output_infer_done, overwrite=True)

        # ジョブ0はクリーンアップを担当します。
        if jobid != 0:
            return

        # すべての翻訳を書いてください
        with codecs.getwriter("utf-8")(
                tf.gfile.GFile(final_output_infer, mode="wb")) as final_f:
            for worker_id in range(num_workers):
                worker_infer_done = "%s_done_%d" % (
                    inference_output_file, worker_id)
                while not tf.gfile.Exists(worker_infer_done):
                    utils.print_out(
                        "  waitting job %d to complete." % worker_id)
                    time.sleep(10)

                with codecs.getreader("utf-8")(
                        tf.gfile.GFile(worker_infer_done, mode="rb")) as f:
                    for translation in f:
                        final_f.write("%s" % translation)

            for worker_id in range(num_workers):
                worker_infer_done = "%s_done_%d" % (
                    inference_output_file, worker_id)
                tf.gfile.Remove(worker_infer_done)

その他

https://github.com/tensorflow/nmt/tree/master/nmt

Large-scale Linear Models with TensorFlow

TensorFlowを使用した大規模な線形モデル

TensorFlow Linear Model Tutorial

TensorFlowリニアモデルチュートリアル
Adult data.png

$ wget https://raw.githubusercontent.com/tensorflow/models/master/official/wide_deep/data_download.py
$ wget https://raw.githubusercontent.com/tensorflow/models/master/official/wide_deep/wide_deep.py
$ virtualenv --system-site-packages -p python3 wide
$ source ~/wide/bin/activate
(wide)$ pip3 install --upgrade tensorflow
(wide)$ python data_download.py
# ワイドモデルの場合
(wide)$ python wide_deep.py --model_type=wide
# ディープモデルの場合
(wide)$ python wide_deep.py --model_type=deep
# accuracy: 0.834592
(wide)$ deactivate
$ rm -r \
    wide \
    data_download.py \
    wide_deep.py \
    /tmp/census_data \
    /tmp/census_model

data_download.py

"""国勢調査所得データセットをダウンロードして清掃します。"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import sys

from six.moves import urllib
import tensorflow as tf

DATA_URL = 'https://archive.ics.uci.edu/ml/machine-learning-databases/adult'
TRAINING_FILE = 'adult.data'
TRAINING_URL = '%s/%s' % (DATA_URL, TRAINING_FILE)
EVAL_FILE = 'adult.test'
EVAL_URL = '%s/%s' % (DATA_URL, EVAL_FILE)

parser = argparse.ArgumentParser()

parser.add_argument(
    '--data_dir', type=str, default='/tmp/census_data',
    help='Directory to download census data')


def _download_and_clean_file(filename, url):
    """URLからデータをダウンロードし、CSV形式に合わせて変更します。"""
    temp_file, _ = urllib.request.urlretrieve(url)
    with tf.gfile.Open(temp_file, 'r') as temp_eval_file:
        with tf.gfile.Open(filename, 'w') as eval_file:
            for line in temp_eval_file:
                line = line.strip()
                line = line.replace(', ', ',')
                if not line or ',' not in line:
                    continue
                if line[-1] == '.':
                    line = line[:-1]
                line += '\n'
                eval_file.write(line)
    tf.gfile.Remove(temp_file)


def main(unused_argv):
    if not tf.gfile.Exists(FLAGS.data_dir):
        tf.gfile.MkDir(FLAGS.data_dir)

    training_file_path = os.path.join(FLAGS.data_dir, TRAINING_FILE)
    _download_and_clean_file(training_file_path, TRAINING_URL)

    eval_file_path = os.path.join(FLAGS.data_dir, EVAL_FILE)
    _download_and_clean_file(eval_file_path, EVAL_URL)


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

wide_deep.py

"""TF.Learn APIを使用したTensorFlow Wide&Deepチュートリアルのサンプルコード。"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import shutil
import sys

import tensorflow as tf

_CSV_COLUMNS = [
    'age', 'workclass', 'fnlwgt', 'education', 'education_num',
    'marital_status', 'occupation', 'relationship', 'race', 'gender',
    'capital_gain', 'capital_loss', 'hours_per_week', 'native_country',
    'income_bracket'
]

_CSV_COLUMN_DEFAULTS = [[0], [''], [0], [''], [0], [''], [''], [''], [''], [''],
                        [0], [0], [0], [''], ['']]

parser = argparse.ArgumentParser()

parser.add_argument(
    '--model_dir', type=str, default='/tmp/census_model',
    help='Base directory for the model.')

parser.add_argument(
    '--model_type', type=str, default='wide_deep',
    help="Valid model types: {'wide', 'deep', 'wide_deep'}.")

parser.add_argument(
    '--train_epochs', type=int, default=40, help='Number of training epochs.')

parser.add_argument(
    '--epochs_per_eval', type=int, default=2,
    help='The number of training epochs to run between evaluations.')

parser.add_argument(
    '--batch_size', type=int, default=40, help='Number of examples per batch.')

parser.add_argument(
    '--train_data', type=str, default='/tmp/census_data/adult.data',
    help='Path to the training data.')

parser.add_argument(
    '--test_data', type=str, default='/tmp/census_data/adult.test',
    help='Path to the test data.')

_NUM_EXAMPLES = {
    'train': 32561,
    'validation': 16281,
}


def build_model_columns():
    """幅広く深い機能の列を作成します。"""
    # 連続カラム
    age = tf.feature_column.numeric_column('age')
    education_num = tf.feature_column.numeric_column('education_num')
    capital_gain = tf.feature_column.numeric_column('capital_gain')
    capital_loss = tf.feature_column.numeric_column('capital_loss')
    hours_per_week = tf.feature_column.numeric_column('hours_per_week')

    education = tf.feature_column.categorical_column_with_vocabulary_list(
        'education', [
            'Bachelors', 'HS-grad', '11th', 'Masters', '9th', 'Some-college',
            'Assoc-acdm', 'Assoc-voc', '7th-8th', 'Doctorate', 'Prof-school',
            '5th-6th', '10th', '1st-4th', 'Preschool', '12th'])

    marital_status = tf.feature_column.categorical_column_with_vocabulary_list(
        'marital_status', [
            'Married-civ-spouse', 'Divorced', 'Married-spouse-absent',
            'Never-married', 'Separated', 'Married-AF-spouse', 'Widowed'])

    relationship = tf.feature_column.categorical_column_with_vocabulary_list(
        'relationship', [
            'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried',
            'Other-relative'])

    workclass = tf.feature_column.categorical_column_with_vocabulary_list(
        'workclass', [
            'Self-emp-not-inc', 'Private', 'State-gov', 'Federal-gov',
            'Local-gov', '?', 'Self-emp-inc', 'Without-pay', 'Never-worked'])

    # ハッシュの例を表示するには:
    occupation = tf.feature_column.categorical_column_with_hash_bucket(
        'occupation', hash_bucket_size=1000)

    # 変換
    age_buckets = tf.feature_column.bucketized_column(
        age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])

    # ワイド列とディープ列
    base_columns = [
        education, marital_status, relationship, workclass, occupation,
        age_buckets,
    ]

    crossed_columns = [
        tf.feature_column.crossed_column(
            ['education', 'occupation'], hash_bucket_size=1000),
        tf.feature_column.crossed_column(
            [age_buckets, 'education', 'occupation'], hash_bucket_size=1000),
    ]

    wide_columns = base_columns + crossed_columns

    deep_columns = [
        age,
        education_num,
        capital_gain,
        capital_loss,
        hours_per_week,
        tf.feature_column.indicator_column(workclass),
        tf.feature_column.indicator_column(education),
        tf.feature_column.indicator_column(marital_status),
        tf.feature_column.indicator_column(relationship),
        # 埋め込みの例を表示するには
        tf.feature_column.embedding_column(occupation, dimension=8),
    ]

    return wide_columns, deep_columns


def build_estimator(model_dir, model_type):
    """指定されたモデルタイプに適した見積もりを作成します。"""
    wide_columns, deep_columns = build_model_columns()
    hidden_units = [100, 75, 50, 25]

    # tf.estimator.RunConfigを作成して、モデルがCPU上で実行されていることを確認します。
    # このモデルでは、このモデルのGPUよりも高速なトレーニングが行われます。
    run_config = tf.estimator.RunConfig().replace(
        session_config=tf.ConfigProto(device_count={'GPU': 0}))

    if model_type == 'wide':
        return tf.estimator.LinearClassifier(
            model_dir=model_dir,
            feature_columns=wide_columns,
            config=run_config)
    elif model_type == 'deep':
        return tf.estimator.DNNClassifier(
            model_dir=model_dir,
            feature_columns=deep_columns,
            hidden_units=hidden_units,
            config=run_config)
    else:
        return tf.estimator.DNNLinearCombinedClassifier(
            model_dir=model_dir,
            linear_feature_columns=wide_columns,
            dnn_feature_columns=deep_columns,
            dnn_hidden_units=hidden_units,
            config=run_config)


def input_fn(data_file, num_epochs, shuffle, batch_size):
    """エスティメータの入力関数を生成します。"""
    assert tf.gfile.Exists(data_file), (
        '%s not found. Please make sure you have either run data_download.py or '
        'set both arguments --train_data and --test_data.' % data_file)

    def parse_csv(value):
        print('Parsing', data_file)
        columns = tf.decode_csv(value, record_defaults=_CSV_COLUMN_DEFAULTS)
        features = dict(zip(_CSV_COLUMNS, columns))
        labels = features.pop('income_bracket')
        return features, tf.equal(labels, '>50K')

    # Dataset APIを使用して入力ファイルから行を抽出します。
    dataset = tf.data.TextLineDataset(data_file)

    if shuffle:
        dataset = dataset.shuffle(buffer_size=_NUM_EXAMPLES['train'])

    dataset = dataset.map(parse_csv, num_parallel_calls=5)

    # 別々のエポックが一緒にブレンドされるのを防ぐために、
    # これまでとは違って、シャッフルしてからrepeatを呼び出します。
    dataset = dataset.repeat(num_epochs)
    dataset = dataset.batch(batch_size)

    iterator = dataset.make_one_shot_iterator()
    features, labels = iterator.get_next()
    return features, labels


def main(unused_argv):
    # 存在する場合、モデルディレクトリをクリーンアップする
    shutil.rmtree(FLAGS.model_dir, ignore_errors=True)
    model = build_estimator(FLAGS.model_dir, FLAGS.model_type)

    # `FLAGS.epochs_per_eval`エポックごとにモデルをトレーニングし、評価してください。
    for n in range(FLAGS.train_epochs // FLAGS.epochs_per_eval):
        model.train(input_fn=lambda: input_fn(
            FLAGS.train_data, FLAGS.epochs_per_eval, True, FLAGS.batch_size))

        results = model.evaluate(input_fn=lambda: input_fn(
            FLAGS.test_data, 1, False, FLAGS.batch_size))

        # 評価指標を表示する
        print('Results at epoch', (n + 1) * FLAGS.epochs_per_eval)
        print('-' * 60)

        for key in sorted(results):
            print('%s: %s' % (key, results[key]))


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

TensorFlow Wide & Deep Learning Tutorial

TensorFlow Wide&Deep Learningチュートリアル

$ wget https://raw.githubusercontent.com/tensorflow/models/master/official/wide_deep/data_download.py
$ wget https://raw.githubusercontent.com/tensorflow/models/master/official/wide_deep/wide_deep.py
$ virtualenv --system-site-packages -p python3 wide_deep
$ source ~/wide_deep/bin/activate
(wide_deep)$ pip3 install --upgrade tensorflow
(wide_deep)$ python data_download.py
# ワイドアンドディープモデルの場合
(wide_deep)$ python wide_deep.py --model_type=wide_deep
# accuracy: 0.857073
(wide_deep)$ deactivate
$ rm -r \
    wide_deep \
    data_download.py \
    wide_deep.py \
    /tmp/census_data \
    /tmp/census_model

Improving Linear Models Using Explicit Kernel Methods

明示的なカーネルメソッドを使用した線形モデルの改善

Simple Audio Recognition

簡単な音声認識
※./configureしないとbazelできない

$ git clone -b r1.4 https://github.com/tensorflow/tensorflow
$ virtualenv --system-site-packages -p python3 audio
$ source ~/audio/bin/activate
(audio)$ pip3 install --upgrade tensorflow
(audio)$ cd tensorflow
(audio)$ python tensorflow/examples/speech_commands/train.py
# 終わらないので設定変更
# Ctrl+C
(audio)$ python tensorflow/examples/speech_commands/train.py \
    --how_many_training_steps=1500,300 \
    --learning_rate=0.001,0.0001
# INFO:tensorflow:Final test accuracy = 57.9% (N=3081) 値は低いが無視
(audio)$ python tensorflow/examples/speech_commands/freeze.py \
    --start_checkpoint=/tmp/speech_commands_train/conv.ckpt-1800 \
    --output_file=/tmp/my_frozen_graph.pb
# Converted 6 variables to const ops.
(audio)$ python tensorflow/examples/speech_commands/label_wav.py \
    --graph=/tmp/my_frozen_graph.pb \
    --labels=/tmp/speech_commands_train/conv_labels.txt \
    --wav=/tmp/speech_dataset/left/a5d485dc_nohash_0.wav
# left (score = 0.22904) 0.8くらい欲しいが無視
(audio)$ ./configure
# Please specify the location of python. [Default is /home/tensorflow/audio/bin/python]: /home/tensorflow/audio/bin/python3.5
# Please input the desired Python library path to use.  Default is [/home/tensorflow/audio/lib/python3.5/site-packages] リターン
# Do you wish to build TensorFlow with jemalloc as malloc support? [Y/n]: n
# Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
# Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
# Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
# Do you wish to build TensorFlow with XLA JIT support? [y/N]: n
# Do you wish to build TensorFlow with GDR support? [y/N]: n
# Do you wish to build TensorFlow with VERBS support? [y/N]: n
# Do you wish to build TensorFlow with OpenCL support? [y/N]: n
# Do you wish to build TensorFlow with CUDA support? [y/N]: n
# Do you wish to build TensorFlow with MPI support? [y/N]: n
# Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: リターン
(audio)$ bazel build tensorflow/examples/wav_to_spectrogram/...
(audio)$ bazel-bin/tensorflow/examples/wav_to_spectrogram/wav_to_spectrogram \
    --input_wav=/tmp/speech_dataset/happy/ab00c4b2_nohash_0.wav \
    --window_size=256 \
    --stride=128 \
    --brightness=64.000000 \
    --output_image=/tmp/spectrogram.png
# tmpディレクトリにspectrogram.pngができる
(audio)$ bazel run tensorflow/examples/speech_commands:generate_streaming_test_wav
# /tmp/speech_commands_trainディレクトリにstreaming_test.wavとstreaming_test_labels.txtができる
(audio)$ bazel run tensorflow/examples/speech_commands:test_streaming_accuracy -- \
    --graph=/tmp/my_frozen_graph.pb \
    --labels=/tmp/speech_commands_train/conv_labels.txt \
    --wav=/tmp/speech_commands_train/streaming_test.wav \
    --ground_truth=/tmp/speech_commands_train/streaming_test_labels.txt \
    --verbose
# 0.0% matched, 0.0% correctly, 0.0% wrongly, 0.0% false positives 0%だけど無視
(audio)$ tensorboard --logdir /tmp/retrain_logs
# ブラウザ http://localhost:6006
# CTRL+C
(audio)$ deactivate
$ cd ~
$ rm -r audio \
    tensorflow \
    /tmp/retrain_logs \
    /tmp/speech_commands_train \
    /tmp/speech_dataset \
    /tmp/my_frozen_graph.pb \
    /tmp/spectrogram.png

Mandelbrot Set

マンデルブロセット
※このチュートリアルはJupyter Notebook用

$ virtualenv --system-site-packages mandelbrot
$ source ~/mandelbrot/bin/activate
(mandelbrot)$ pip install --upgrade tensorflow
(mandelbrot)$ pip install pillow jupyter-console
(mandelbrot)$ gedit mandelbrot.py
# コピーペースト
# シミュレーションのためのライブラリのインポート
import tensorflow as tf
import numpy as np

# 視覚化のためのインポート
import PIL.Image
from io import BytesIO
from IPython.display import Image, display


def DisplayFractal(a, fmt='jpeg'):
    """反復カウントの配列をフラクタルのカラフルな画像として表示します。"""
    a_cyclic = (6.28 * a / 20.0).reshape(list(a.shape) + [1])
    img = np.concatenate([10 + 20 * np.cos(a_cyclic),
                          30 + 50 * np.sin(a_cyclic),
                          155 - 80 * np.cos(a_cyclic)], 2)
    img[a == a.max()] = 0
    a = img
    a = np.uint8(np.clip(a, 0, 255))
    f = BytesIO()
    PIL.Image.fromarray(a).save(f, fmt)
    display(Image(data=f.getvalue()))


sess = tf.InteractiveSession()

# NumPyを使用して複素数の2次元配列を作成する

Y, X = np.mgrid[-1.3:1.3:0.005, -2:1:0.005]
Z = X + 1j * Y

xs = tf.constant(Z.astype(np.complex64))
zs = tf.Variable(xs)
ns = tf.Variable(tf.zeros_like(xs, tf.float32))

tf.global_variables_initializer().run()

# zの新しい値を計算する: z^2 + x
zs_ = zs * zs + xs

# 新しい値で分岐したか?
not_diverged = tf.abs(zs_) < 4

# zsと反復回数を更新する操作。
#
# 注:コンピューティングzは分岐した後も維持されます。
#       これは非常に無駄です!
#       もう少しシンプルであれば、これをやる方が良いでしょう。
#
step = tf.group(
    zs.assign(zs_),
    ns.assign_add(tf.cast(not_diverged, tf.float32))
)

for i in range(200):
    step.run()

DisplayFractal(ns.eval())
(mandelbrot)$ jupyter-console
In [1]: run mandelbrot.py
# Ctrl+D
(mandelbrot)$ deactivate
$ rm -r mandelbrot \
    mandelbrot.py

Partial Differential Equations

部分微分方程式
※このチュートリアルはJupyter Notebook用
※大量の画像が表示されるので注意

$ virtualenv --system-site-packages pdes
$ source ~/pdes/bin/activate
(pdes)$ pip install --upgrade tensorflow
(pdes)$ pip install pillow jupyter-console
(pdes)$ gedit pdes.py
# コピーペースト
# シミュレーションのためのライブラリのインポート
import tensorflow as tf
import numpy as np

# 視覚化のためのインポート
import PIL.Image
from io import BytesIO
from IPython.display import clear_output, Image, display


def DisplayArray(a, fmt='jpeg', rng=[0, 1]):
    """配列を画像として表示します。"""
    a = (a - rng[0]) / float(rng[1] - rng[0]) * 255
    a = np.uint8(np.clip(a, 0, 255))
    f = BytesIO()
    PIL.Image.fromarray(a).save(f, fmt)
    clear_output(wait=True)
    display(Image(data=f.getvalue()))


sess = tf.InteractiveSession()


def make_kernel(a):
    """2D配列を畳み込みカーネルに変換する"""
    a = np.asarray(a)
    a = a.reshape(list(a.shape) + [1, 1])
    return tf.constant(a, dtype=1)


def simple_conv(x, k):
    """簡略化された2D畳み込み演算"""
    x = tf.expand_dims(tf.expand_dims(x, 0), -1)
    y = tf.nn.depthwise_conv2d(x, k, [1, 1, 1, 1], padding='SAME')
    return y[0, :, :, 0]


def laplace(x):
    """配列の2Dラプラシアンを計算する"""
    laplace_k = make_kernel([[0.5, 1.0, 0.5],
                             [1.0, -6., 1.0],
                             [0.5, 1.0, 0.5]])
    return simple_conv(x, laplace_k)


N = 500

# 初期条件 - いくつかの雨滴が池を打つ

# Set everything to zero
u_init = np.zeros([N, N], dtype=np.float32)
ut_init = np.zeros([N, N], dtype=np.float32)

# いくつかの雨滴が偶然に池を打つ
for n in range(40):
    a, b = np.random.randint(0, N, 2)
    u_init[a, b] = np.random.uniform()

DisplayArray(u_init, rng=[-0.1, 0.1])

# パラメーター:
# eps -- 時間分解能
# damping -- ウェーブダンピング
eps = tf.placeholder(tf.float32, shape=())
damping = tf.placeholder(tf.float32, shape=())

# シミュレーション状態の変数を作成する
U = tf.Variable(u_init)
Ut = tf.Variable(ut_init)

# PDE更新ルールの離散化
U_ = U + eps * Ut
Ut_ = Ut + eps * (laplace(U) - damping * Ut)

# 状態を更新する操作
step = tf.group(
    U.assign(U_),
    Ut.assign(Ut_))

# 状態を初期状態に初期化する
tf.global_variables_initializer().run()

# PDEの1000ステップ実行
for i in range(1000):
    # ステップシミュレーション
    step.run({eps: 0.03, damping: 0.04})
    DisplayArray(U.eval(), rng=[-0.1, 0.1])
(pdes)$ jupyter-console
In [1]: run pdes.py
# Ctrl+D
(pdes)$ kill `ps -ef | grep display | awk '{print $2;}'`
(pdes)$ deactivate
$ rm -r pdes \
    pdes.py

Deploy >

Distributed TensorFlow

分散型TensorFlow
Windows10のVirtualBoxでUbuntu16.04/64-bit×4台起動
※本番環境考慮していません。