ホーム » 「TensorFlow Get Started」タグがついた投稿

タグアーカイブ: TensorFlow Get Started

TensorFlow : ML 初心者のための Getting Started

TensorFlow : ML 初心者のための Getting Started (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 02/26/2018

* TensorFlow の Getting Started が再構成され、機械学習初心者のためのドキュメントが追加されましたので新たに翻訳しました。
* 本ページは、TensorFlow の本家サイトの Get Started – Getting Started for ML Beginners
を翻訳した上で適宜、補足説明したものです:

* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

このドキュメントはアイリス花を種 (しゅ) で分類 (カテゴリー分け) するために機械学習をどのように使用するかを説明します。このドキュメントはそれを正確に行なう TensorFlow コードへと深く潜り、その途中で ML 基礎を説明していきます。

もし次のリストが貴方について記述している場合には、貴方は正しい場所にいます :

  • 機械学習について殆ど知らない。
  • どのように TensorFlow プログラムを書くかを学ぶことを望む。
  • Python で (少なくとも少しは) コードが書ける。

 

アイリス分類問題

貴方が植物学者で見つけたアイリス花の各々を分類するための自動化された方法を求めている、と想像してください。機械学習は花を分類する多くの方法を提供します。例えば、洗練された機械学習プログラムは写真を基にして花を分類できるでしょう。私達の野望はより控えめなものです — アイリス花をそれらのがく片 (= sepal) と花弁 (= petal) の長さと幅だけを基にして分類します。アイリス属は約 300 種を伴いますが、私達のプログラムは以下の3つだけを分類します :

  • アイリス・セトサ
  • アイリス・バージカラー
  • アイリス・バージニカ

左から右へ、アイリス・セトサ (by Radomil, CC BY-SA 3.0)、アイリス・バージカラー (by Dlanglois, CC BY-SA 3.0)、そして アイリス・バージニカ (by Frank Mayfield, CC BY-SA 2.0) です。

幸いなことに、がく片と花弁の測定を持つ 120 アイリス花のデータセット を既に誰かが作成しています。このデータセットは機械学習分類問題への規範的なイントロダクションの一つになっています。(MNIST データベース、これは手書き数字を含みます、はもう一つのポピュラーな分類問題です。) アイリス・データセットの最初の 5 エントリは次のように見えます :

がく片長さ

がく片幅

花弁長さ

花弁幅

6.4

2.8

5.6

2.2

2

5.0

2.3

3.3

1.0

1

4.9

2.5

4.5

1.7

2

4.9

3.1

1.5

0.1

0

5.7

3.8

1.7

0.3

0

幾つかの用語を紹介しましょう :

  • 最後のカラム (種) はラベルと呼ばれます ; 最初の4つのカラムは特徴と呼ばれます。特徴はサンプルの特質で、一方でラベルは予測しようとしているものです。
  • サンプルは一つ実例の花のための特徴のセットとラベルから成ります。先のテーブルは 120 サンプルのデータセットからの5つのサンプルを示します。

各ラベルは自然に文字列 (例えば、”setosa”) ですが、機械学習は典型的には数値に依拠します。それ故に、誰かが各文字列を数字にマップしました。表現スキームがここにあります :

  • 0 は「セトサ」を表します。
  • 1 は「バージカラー」を表します。
  • 2 は「バージニカ」を表します。

 

モデルと訓練

モデルは特徴とラベルの間の関係性です。アイリス問題については、モデルはがく片と花弁測定とアイリス種の間の関係性を定義します。ある単純なモデルは代数の 2, 3 行で記述できます ; より複雑な機械学習モデルは数学的に要約することが難しくなるような数学的関数とパラメータの巨大な数の組み合わせを含みます。

貴方は4つの特徴とアイリス種の間の関係性を機械学習を利用することなく決定できますか?つまり、貴方は伝統的なプログラミング技術 (例えば、多くの条件ステートメント) を使用してモデルを作成できますか?多分 (= Maybe)。特定の種へのがく片と花弁測定の正しい関係性を決定するために貴方はデータセットと長時間遊ぶことはできるでしょう。けれども、良い機会学習アプローチは貴方のためにモデルを決定します。つまり、正しい機械学習モデルのタイプに十分な典型的なサンプルを供給すれば、プログラムはがく片、花弁、そして種の関係性を決定するでしょう。

訓練はモデルが徐々に最適化 (学習) されていく機械学習のステージです。アイリス問題は教師あり機械学習のサンプルで、そこではモデルはラベルを含むサンプルから訓練されます。(教師なし機械学習では、サンプルはラベルを含みません。代わりに、モデルは典型的には特徴の中のパターンを見つけます。)

 

サンプル・プログラムを取得する

このドキュメントのサンプル・コードで遊ぶ前に、以下を行なってください :

  1. TensorFlow をインストールします。
  2. virtualenv か Anaconda で TensorFlow をインストールした場合、貴方の TensorFlow 環境を activate します。
  3. 次のコマンドを実行して pandas をインストールまたはアップグレードします :
    pip install pandas
    

サンプル・プログラムを取得するために次のステップを取ります :

  1. TensorFlow Models レポジトリを次のコマンドを入力して github から clone します :
    git clone https://github.com/tensorflow/models
    
  2. そのブランチ内のこのドキュメントで使用するサンプルを含む位置へディレクトリを変更します :
    cd models/samples/core/get_started/
    

その get_started ディレクトリで、premade_estimator.py という名前のプログラムを見つけるでしょう。

 

サンプル・プログラムを実行する

任意の Python プログラムを実行するように TensorFlow プログラムを実行します。従って、premade_estimators.py を実行するためにはコマンドラインから次のコマンドを実行します :

python premade_estimator.py

プログラムの実行は次のような3つの予測行で終わる非常に多くの情報を出力するはずです :

...
Prediction is "Setosa" (99.6%), expected "Setosa"

Prediction is "Versicolor" (99.8%), expected "Versicolor"

Prediction is "Virginica" (97.9%), expected "Virginica"

プログラム予測の代わりにエラーを生成する場合は、次の質問を貴方自身で尋ねてください :

  • TensorFlow を正しくインストールしましたか?
  • TensorFlow の正しいバージョンを使用していますか?premade_estimators.py プログラムは少なくとも TensorFlow v1.4 を必要とします。
  • TensorFlow を virtualenv か Anaconda でインストールした場合、環境を activate しましたか?

 

TensorFlow プログラミング・スタック

次の図が示すように、TensorFlow は複数の API 層から成るプログラミング・スタックを提供します :

TensorFlow プログラミング環境

TensorFlow プログラムを書き始めるとき、次の2つの高位 API に焦点を当てることを強く推奨します :

  • Estimators
  • Datasets

他の API から必要な際の便利関数につかまりはしますが、このドキュメントは上の2つの API に焦点を当てます。

 

プログラムそれ自身

お待たせしました ; コードを調べましょう。premade_estimator.py — そして多くの他の TensorFlow プログラム — の一般的なアウトラインは次のようなものです :

  • データセットをインポートして解析します。
  • データを表わすために特徴カラムを作成します。
  • モデルのタイプを選択します。
  • モデルを訓練します。
  • モデルの有効性を評価します。
  • 訓練されたモデルに予測させます。

以下の副セクションは各パートを詳述します。

 

データセットをインポートして解析する

アイリス・プログラムは次の2つの .csv ファイルからのデータを必要とします :

  • http://download.tensorflow.org/data/iris_training.csv, これは訓練セットを含みます。
  • http://download.tensorflow.org/data/iris_test.csv, これはテストセットを含みます。

訓練セットはモデルを訓練するために使用するサンプルを含みます ; テストセットは訓練されたモデルの有効性を評価するために使用するサンプルを含みます。

訓練セットとテストセットは単一のデータセットとして始まります。それから、誰かがサンプルを分割します、大部分は訓練セットに入りそして残りはテストセットに入ります。訓練セットへのサンプルの追加は通常はより良いモデルを構築します ; けれども、テストセットへの更なるサンプルの追加はモデルの有効性をより良く測定することを可能にします。分割にかかわらず、テストセットのサンプルは訓練セットのサンプルとは別にしなければなりません。そうでなければ、モデルの有効性を正確に決定することはできません。

premade_estimators.py プログラムは訓練セットとテストセットを読み込み解析するために近接する iris_data.py ファイルの load_data 関数に依拠します。関数の数多くコメントされたバージョンがここにあります :

TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"

CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
                    'PetalLength', 'PetalWidth', 'Species']

...

def load_data(label_name='Species'):
    """Parses the csv file in TRAIN_URL and TEST_URL."""

    # Create a local copy of the training set.
    train_path = tf.keras.utils.get_file(fname=TRAIN_URL.split('/')[-1],
                                         origin=TRAIN_URL)
    # train_path now holds the pathname: ~/.keras/datasets/iris_training.csv

    # Parse the local CSV file.
    train = pd.read_csv(filepath_or_buffer=train_path,
                        names=CSV_COLUMN_NAMES,  # list of column names
                        header=0  # ignore the first row of the CSV file.
                       )
    # train now holds a pandas DataFrame, which is data structure
    # analogous to a table.

    # 1. Assign the DataFrame's labels (the right-most column) to train_label.
    # 2. Delete (pop) the labels from the DataFrame.
    # 3. Assign the remainder of the DataFrame to train_features
    train_features, train_label = train, train.pop(label_name)

    # Apply the preceding logic to the test set.
    test_path = tf.keras.utils.get_file(TEST_URL.split('/')[-1], TEST_URL)
    test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
    test_features, test_label = test, test.pop(label_name)

    # Return four DataFrames.
    return (train_features, train_label), (test_features, test_label)

Keras はオープンソースの機械学習ライブラリです ; tf.keras は Keras の TensorFlow 実装です。premade_estimator.py プログラムは一つの tf.keras 関数にアクセスするだけです、すなわち、tf.keras.utils.get_file 便利関数で、これはリモート CSV ファイルをローカルファイルシステムにコピーします。

load_data への呼び出しは訓練とテストセットそれぞれのために2つの (特徴, ラベル) のペアを返します :

    # Call load_data() to parse the CSV file.
    (train_feature, train_label), (test_feature, test_label) = load_data()

pandas は幾つかの TensorFlow 関数で利用されるオープンソースの Python ライブラリです。pandas DataFrame は名前付けられたカラムヘッダと番号付けられた行を持つテーブルです。load_data により返された特徴は DataFrame 内にパックされます。例えば、test_feature DataFrame は次のように見えます :

    SepalLength  SepalWidth  PetalLength  PetalWidth
0           5.9         3.0          4.2         1.5
1           6.9         3.1          5.4         2.1
2           5.1         3.3          1.7         0.5
...
27          6.7         3.1          4.7         1.5
28          6.7         3.3          5.7         2.5
29          6.4         2.9          4.3         1.3

 

データを記述する

特徴カラムは各特徴においてデータをどのように解釈するかを貴方のモデルに教えるデータ構造です。
アイリス問題では、モデルに各特徴のデータをその浮動小数点値リテラルとして解釈することを望みます ; つまり、モデルに 5.4 のような入力値を 5.4 として解釈することを望みます。けれども、他の機械学習問題では、データを文字通りではなく解釈することがしばしば望ましいです。データを解釈するために特徴カラムを使用することはそれに ドキュメント 全体をかけるようなリッチなトピックです。

コードの観点からは、tf.feature_column モジュールからの関数を呼び出して feature_column オブジェクトのリストを構築します。各オブジェクトはモデルへの入力を記述します。モデルにデータを浮動小数点値として解釈するように伝えるためには、@{tf.feature_column.numeric_column) を呼び出します。premade_estimator.py では、4つ総ての特徴は浮動小数点値リテラルとして解釈されるべきですから、特徴カラムを作成するコードは次のようになります :

# Create feature columns for all features.
my_feature_columns = []
for key in train_x.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

エレガントではありませんが、多分よりクリアな、前のブロックをエンコードする他の方法がここにあります :

my_feature_columns = [
    tf.feature_column.numeric_column(key='SepalLength'),
    tf.feature_column.numeric_column(key='SepalWidth'),
    tf.feature_column.numeric_column(key='PetalLength'),
    tf.feature_column.numeric_column(key='PetalWidth')
]

 

モデルのタイプを選択する

訓練されるモデルの種類を選択する必要があります。多くのモデル・タイプがあります ; 理想的なタイプを選択するには経験が必要です。私達はアイリス問題を解くためにニューラルネットワークを選択しました。ニューラルネットワーク は特徴とラベルの間の複雑な関係性を見つけることができます。ニューラルネットワークは高度に構造化されたグラフで、一つまたはそれ以上の 隠れ層 に組織化されています。各隠れ層は一つまたはそれ以上の ニューロン から成ります。ニューラルネットワークの幾つかのカテゴリーがあります。私達は 完全結合ニューラルネットワーク を使用します、これは一つの層のニューロンが前の層の総てのニューロンからの入力を取ることを意味します。例えば、下の図は3つの隠れ層から成る完全結合ニューラルネットワークを示します :

  • 最初の隠れ層は4つのニューロンを含みます。
  • 2番目の隠れ層は3つのニューロンを含みます。
  • 3番目の隠れ層は2つのニューロンを含みます。


3つの隠れ層を持つニューラルネットワーク

モデルのタイプを指定するには、Estimator クラスをインスタンス化します。TensorFlow は Estimator の2つのカテゴリを提供します :

  • pre-made Estimator、これは他の誰かが既に貴方のために書いたものです。
  • カスタム Estimator、これは貴方自身でコードを書かなければなりません、少なくとも部分的には。

ニューラルネットワークを実装するために、premade_estimators.py プログラムは tf.estimator.DNNClassifier という名前の pre-made Estimator を使用します。この Estimator はサンプルを分類するニューラルネットワークを構築します。次の呼び出しは DNNClassifier をインスタンス化します :

    classifier = tf.estimator.DNNClassifier(
        feature_columns=my_feature_columns,
        hidden_units=[10, 10],
        n_classes=3)

ニューラルネットワークの各隠れ層のニューロン数を定義するためには hidden_units パラメータを使用してください。このパラメータにはリストを割り当てます。例えば :

        hidden_units=[10, 10],

hidden_units に割り当てられたリストの長さは隠れ層の数を識別します (この場合は 2 です)。リストの各値は特定の隠れ層のニューロン数を表します (最初の隠れ層が 10 で2番目の隠れ層が 10 です)。隠れ層やニューロンの数を変更するには、単に hidden_units パラメータに異なるリストを割り当てます。

隠れ層とニューロンの理想的な数は問題とデータセットに依存します。機械学習の多くの様相のように、ニューラルネットワークの理想的な shape を選択することは知識と経験のある種の混合を必要とします。経験則では、隠れ層とニューロンの数を増やすことは典型的にはよりパワフルなモデルを作成し、これは効果的に訓練するためにはよりデータを必要とします。

n_classes パラメータはニューラルネットワークが予測可能な起こりうる値の数です。アイリス問題は3つのアイリス種を分類しますので、n_classes を 3 に設定します。

tf.Estimator.DNNClassifier のためのコンストラクタは optimizer という名前のオプションの引数を取ります、これは私達のサンプル・コードでは指定していません。optimizer はモデルがどのように訓練するかを制御します。貴方が機械学習においてより専門技術を身に付けるにつれて、optimizer と learning rate (学習率) は非常に重要になっていくでしょう。

 

モデルを訓練する

tf.Estimator.DNNClassifier のインスタンス化はモデルを学習するためのフレームワークを作成します。基本的には、私達はネットワークを配線しましたがしかしまだデータをそれに通して流していません。ニューラルネットワークを訓練するためには、Estimator オブジェクトの train メソッドを呼び出します。例えば :

    classifier.train(
        input_fn=lambda:train_input_fn(train_feature, train_label, args.batch_size),
        steps=args.train_steps)

steps 引数は指定した反復数後に訓練をやめることを train に伝えます。steps を増やすことはモデルが訓練する時間の総量を増やします。直感に反して、モデルをより長く訓練することはより良いモデルを保証しません。args.train_steps のデフォルト値は 1000 です。訓練するためのステップ数は貴方が調整可能なハイパーパラメータ です。ステップの適正な数を選択することは通常は経験と実験の両者を必要とします。

input_fn パラメータは訓練データを供給する関数を識別します。train メソッドへの呼び出しは train_input_fn 関数が訓練データを供給することを示します。ここにそのメソッドのシグネチャがあります :

def train_input_fn(features, labels, batch_size):

私達は train_input_fn に次の引数を渡しています :

  • train_feature は Python 辞書でそこでは :
    • 各キーは特徴の名前です。
    • 各値は訓練セットの各サンプルのための値を含む配列です。
  • train_label は訓練セットの総てのサンプルのためのラベルの値を含む配列です。
  • args.batch_size は バッチサイズ を定義する整数です。

train_input_fn function は Dataset API に依拠します。これはデータを読みそれを train メソッドが必要とする形式に変換するための高位な TensorFlow API です。次の呼び出しは入力特徴とラベルを tf.data.Dataset オブジェクトに変換します、これは Dataset API の基底クラスです :

    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

tf.dataset クラスは訓練のためのサンプルを用意するために多くの有用な関数を提供します。次の行はこれらの関数の3つを呼び出します :

    dataset = dataset.shuffle(buffer_size=1000).repeat(count=None).batch(batch_size)

訓練サンプルがランダムオーダーにある場合に訓練は最も良く動作します。サンプルをランダム化するためには、tf.data.Dataset.shuffle を呼び出します。buffer_size をサンプル (120) の数よりも大きい値に設定することはデータが上手くシャッフルされることを確実にします。

訓練の間、train メソッドは典型的にはサンプルを複数回処理します。どのような引数も持たない tf.data.Dataset.repeat メソッドの呼び出しは train メソッドが (今はシャッフルされた) 訓練セット・サンプルの無限の供給を持ちます。

train メソッドはサンプルの バッチ を一度に処理します。tf.data.Dataset.batch メソッドは複数のサンプルを鎖状に繋ぐことによりバッチを作成します。プログラムはデフォルトのバッチサイズを 100 に設定します、これは batch メソッドが 100 サンプルのグループを結合していくことを意味します。理想的なバッチサイズは問題に依存します。経験則では、より小さいバッチサイズは通常は (時に) 精度を犠牲にして train メソッドにモデルをより高速に訓練することを可能にします。

次の return ステートメントは呼び出し側 (train メソッド) にサンプルのバッチを返します。

   return dataset.make_one_shot_iterator().get_next()

 

モデルを評価する

評価することはモデルがどのように効果的に予測を行なうかを決定することを意味します。アイリス分類モデルの有効性を決定するために、幾つかのがく片と花弁測定を見てるに渡してそれらがどのアイリス種を表わすかを予測するためにモデルに問い合わせます。それからモデルの予測を実際のラベルに対して比較します。例えば、入力サンプルの半分で正しい種を選択するモデルは 0.5 の 精度 を持つことになります。以下はより効果的なモデルを提示します :

テストセット

特徴

ラベル

予測

5.9

3.0

4.3

1.5

1

1

6.9

3.1

5.4

2.1

2

2

5.1

3.3

1.7

0.5

0

0

6.0

3.4

4.5

1.6

1

2

5.5

2.5

4.0

1.3

1

1


精度 80% のモデル。

モデルの有効性を評価するために、各 Estimator は evaluate メソッドを提供します。premade_estimator.py プログラムは evaluate を次のように呼び出します :

# Evaluate the model.
eval_result = classifier.evaluate(
    input_fn=lambda:eval_input_fn(test_x, test_y, args.batch_size))

print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))

classifier.evaluate への呼び出しは classifier.train への呼び出しと同様です。最大の違いは classifier.evaluate はそのサンプルを訓練セットではなくテストセットから取得しなければならないことです。換言すれば、構成にモデルの有効性にアクセスするためには、モデルを評価するために使用されるサンプルはモデルを訓練するために使用されたサンプルとは異なっていなければなりません。eval_input_fn 関数はテストセットからサンプルのバッチをサーブします。ここに eval_input_fn があります :

def eval_input_fn(features, labels=None, batch_size=None):
    """An input function for evaluation or prediction"""
    if labels is None:
        # No labels, use only features.
        inputs = features
    else:
        inputs = (features, labels)

    # Convert inputs to a tf.dataset object.
    dataset = tf.data.Dataset.from_tensor_slices(inputs)

    # Batch the examples
    assert batch_size is not None, "batch_size must not be None"
    dataset = dataset.batch(batch_size)

    # Return the read end of the pipeline.
    return dataset.make_one_shot_iterator().get_next()

要するに、eval_input_fn は classifier.evaluate から呼び出されたときに次を行ないます :

  1. テストセットからの特徴とラベルを tf.dataset オブジェクトに変換します。
  2. テストセットのサンプルのバッチを作成します。(テストセットのサンプルをシャッフルしたり反復したりする必要性はありません。)
  3. テストセットのサンプルのそのバッチを classifier.evaluate に返します。

コードの実行は次の出力を生成します (あるいはそれに近いもの) :

Test set accuracy: 0.967

精度 0.967 は、私達の訓練されたモデルはテストセットの 30 のアイリス種から 20 を正しく分類したことを包含しています。

 

予測する

さて私達はモデルを訓練してそれはアイリス種を良く分類する – しかし完全ではない – ことが「証明」されました。ラベル付けされていないサンプル 上で幾つか予測を行なうために訓練モデルを使用しましょう ; つまり、特徴を含むけれどもラベルは含まないサンプル上です。

現実には、ラベル付けされていないサンプルは apps、CSV ファイル、そしてデータ供給を含む異なる多くのソースに由来するでしょうが。今は、単純に次の3つのラベル付けされていないサンプルを手動で提供します :

    predict_x = {
        'SepalLength': [5.1, 5.9, 6.9],
        'SepalWidth': [3.3, 3.0, 3.1],
        'PetalLength': [1.7, 4.2, 5.4],
        'PetalWidth': [0.5, 1.5, 2.1],
    }

総ての Estimator は predict メソッドを提供し、これは premade_estimator.py が次のように呼び出します :

predictions = classifier.predict(
    input_fn=lambda:eval_input_fn(predict_x, batch_size=args.batch_size))

evaluate メソッドと同様に、predict メソッドもまた eval_input_fn メソッドからサンプルを集めます。

予測を行なうときは、eval_input_fn にラベルを渡しません。従って、eval_input_fn は次を行ないます :

  1. 作成したばかりの 3-要素のマニュアルセットから特徴を変換します。
  2. マニュアルセットから 3 サンプルのバッチを作成します。
  3. そのサンプルのバッチを classifier.predict に返します。

predict メソッドは python iterable を返し、各サンプルのための予測結果の辞書を生成します。辞書は幾つかのキーを含みます。probabilities キーは3つの浮動小数点値のリストを保持し、各々は入力サンプルが特定のアイリス種である確率を表します。例えば、次の probabilities リストを考えます :

'probabilities': array([  1.19127117e-08,   3.97069454e-02,   9.60292995e-01])

前のリストは次を示しています :

  • アイリスがセトサである可能性は無視できます。
  • アイリスがバージカラーである可能性は 3.97 % です。
  • アイリスがバージニカである可能性は 96.0 % です

class_ids キーは最も可能性のある種を識別する 1-要素配列を保持します。例えば :

'class_ids': array([2])

ナンバー 2 はバージニカに対応します。次のコードは各予測について報告するために返された予測を通してイテレートします :

for pred_dict, expec in zip(predictions, expected):
    template = ('\nPrediction is "{}" ({:.1f}%), expected "{}"')

    class_id = pred_dict['class_ids'][0]
    probability = pred_dict['probabilities'][class_id]
    print(template.format(SPECIES[class_id], 100 * probability, expec))

プログラムの実行は次の出力を生成します :

...
Prediction is "Setosa" (99.6%), expected "Setosa"

Prediction is "Versicolor" (99.8%), expected "Versicolor"

Prediction is "Virginica" (97.9%), expected "Virginica"
 

以上



TensorFlow : Get Started : tf.estimator クイックスタート

TensorFlow : Get Started : tf.estimator クイックスタート (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 09/18/2017

* 本ページは、TensorFlow の本家サイトの Get Started – tf.estimator Quickstart を翻訳した上で
適宜、補足説明したものです

* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

本文

TensorFlow の高位な機械学習 API (tf.estimator) は様々な機械学習モデルを構成し、訓練し、そして評価することを容易にします。このチュートリアルでは、花弁 (petal) / ガク片 (sepal) の形状をもとに花の種を予測するために、tf.estimator を使用して ニューラルネットワーク 分類器を構築しそれを アイリス・データセット で訓練します。コードを書いて次の5つのステップを実行します :

  1. アイリス訓練/テストデータを含む CSV を TensorFlow データセットにロードする
  2. ニューラルネットワーク分類器を構築する
  3. 訓練データを使用してモデルを訓練する
  4. モデルの精度を評価する
  5. 新しいサンプルを分類する

NOTE: このチュートリアルで開始する前に 貴方のマシン上に TensorFlow をインストールする ことを忘れないでください。

 

完全なニューラルネットワーク・ソースコード

ニューラルネットワーク分類器のための完全なコードがここにあります :

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

import os
import urllib

import numpy as np
import tensorflow as tf

# Data sets
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 the training and test sets aren't stored locally, download them.
  if not os.path.exists(IRIS_TRAINING):
    raw = urllib.urlopen(IRIS_TRAINING_URL).read()
    with open(IRIS_TRAINING, "w") as f:
      f.write(raw)

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

  # Load datasets.
  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)

  # Specify that all features have real-value data
  feature_columns = [tf.feature_column.numeric_column("x", shape=[4])]

  # Build 3 layer DNN with 10, 20, 10 units respectively.
  classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                          hidden_units=[10, 20, 10],
                                          n_classes=3,
                                          model_dir="/tmp/iris_model")
  # Define the training inputs
  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)

  # Train model.
  classifier.train(input_fn=train_input_fn, steps=2000)

  # Define the test inputs
  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)

  # Evaluate accuracy.
  accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"]

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

  # Classify two new flower samples.
  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()

次のセクションでコードを詳細に通り抜けます。

 

アイリス CSV データを TensorFlow にロードする

アイリス・データセット は 150 行のデータを含み、3つの関連アイリス種 : アイリス・セトサ (setosa)、アイリス・バージニカ (virginica)、アイリス・バージカラー (versicolor) の各々からの 50 サンプルから成ります。

左から右へ、アイリス・セトサ (by Radomil, CC BY-SA 3.0)、アイリス・バージカラー (by Dlanglois, CC BY-SA 3.0)、そして アイリス・バージニカ (by Frank Mayfield, CC BY-SA 2.0) です。

各行は各花のサンプルのための次のデータを含みます : がく片 (= sepal) 長さ、がく片幅、花弁 (= petal) 長さ、花弁幅、そして花の種。花の種は整数として表され、0 はアイリス・セトサを示し、1 はアイリス・バージカラーを示し、そして 2 はアイリス・バージニカを示します。

がく片長さ

がく片幅

花弁長さ

花弁幅

5.1

3.5

1.4

0.2

0

4.9

3.0

1.4

0.2

0

4.7

3.2

1.3

0.2

0

7.0

3.2

4.7

1.4

1

6.4

3.2

4.5

1.5

1

6.9

3.1

4.9

1.5

1

6.5

3.0

5.2

2.0

2

6.2

3.4

5.4

2.3

2

5.9

3.0

5.1

1.8

2

このチュートリアルのために、アイリス・データはランダム化されて2つの別の CSV に分割されています :

始めるには、最初に全ての必要なモジュールをインポートして、データセットをどこにダウンロードしてストアするかを定義します :

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

import os
import urllib

import tensorflow as tf
import numpy as np

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"

そして、訓練とテストセットがまだローカルにストアされていないならば、それらをダウンロードします。

if not os.path.exists(IRIS_TRAINING):
  raw = urllib.urlopen(IRIS_TRAINING_URL).read()
  with open(IRIS_TRAINING,'w') as f:
    f.write(raw)

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

次に、訓練とテストセットを learn.datasets.base の load_csv_with_header() メソッドを使用してデータセットにロードします。load_csv_with_header() は3つの必要な引数を取ります :

  • filename, これは CSV ファイルへのファイルパスを取ります。
  • target_dtype, これはデータセットの目標値 (= target value) の numpy データ型を取ります。
  • features_dtype, これはデータセットの特徴値 (= feature values) の numpy データ型を取ります。

ここで、目標 (= target, モデルを訓練して予測するための値) は花の種で、これは 0-2 の整数ですから、妥当な numpy データ型は np.int です :

# Load datasets.
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)

tf.contrib.learn のデータセットは named tuples (名前付きタプル) です; データと目標 (target) フィールドを通して特徴データと目標値にアクセスできます。ここで、training_set.data と training_set.target は訓練セットのための特徴データと目標値をそれぞれ含み、そして test_set.data と test_set.target はテストセットのための特徴データと目標値を含みます。

後で、”DNNClassifier をアイリス訓練データにフィットさせる” でモデルを訓練するために training_set.data と training_set.target を使用して、そして “モデル精度を評価する” では test_set.data と test_set.target を使用します。しかしまずは、次のセクションでモデルを構築します。

 

深層ニューラルネットワーク分類器を構築する

tf.estimator は Estimator と呼ばれる、事前定義されたモデルを各種提供しています、これは貴方のデータ上で訓練と評価演算を実行するために “枠にとらわれない (out of the box)” モデルとして使用できます。 ここで、アイリス・データにフィットさせるために深層ニューラルネットワーク分類器モデルを構成します。tf.estimator を使用して、2、3行のコードで tf.estimator.DNNClassifier をインスタンス化できます :

# Specify that all features have real-value data
feature_columns = [tf.feature_column.numeric_column("x", shape=[4])]

# Build 3 layer DNN with 10, 20, 10 units respectively.
classifier = tf.estimator.DNNClassifier(feature_columns=feature_columns,
                                        hidden_units=[10, 20, 10],
                                        n_classes=3,
                                        model_dir="/tmp/iris_model")

上のコードは最初にモデルの特徴カラムを定義します、これはデータセットの特徴のためのデータ型を指定します。全ての特徴データは連続的ですので、特徴カラムを構成するために使用するのに tf.feature_column.numeric_column が適切な関数になります。データセット (ガク片幅、ガク片長さ、花弁幅、花弁高さ) には4つの特徴があり、従って全てのデータを保持するためには shape は [4] に設定されなければなりません。

それから、コードは次の引数を使用して DNNClassifier モデルを作成します :

  • feature_columns=feature_columns. 上で定義された特徴カラムのセット。
  • hidden_units=[10, 20, 10]. 3つの 隠れ層 で、10, 20, そして 10 ニューロンをそれぞれ含みます。
  • n_classes=3。3つの目標クラスで、3つのアイリス種を表します。
  • model_dir=/tmp/iris_model。モデル訓練の間に TensorFlow がチェックポイント・データと TensorBoard 要約をセーブするディレクトリ。

 

訓練入力パイプラインを記述する

tf.estimator API は入力関数を使用し、これはモデルのためのデータを生成する TensorFlow 演算を作成します。入力パイプラインを生成するためには tf.estimator.inputs.numpy_input_fn が使用できます :

# Define the training inputs
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)

 

DNNClassifier をアイリス訓練データにフィットさせる

DNN classifier モデルを構成した今、train メソッドを使用してそれをアイリス訓練データにフィットさせることができます。input_fn として train_input_fn と、訓練のためのステップ数 (ここでは、2000) を渡します :

# Train model.
classifier.train(input_fn=train_input_fn, steps=2000)

モデルの状態は classifier に保持されます、これは望むならば繰り返し訓練できることを意味します。例えば、上は次と同値です :

classifier.train(input_fn=train_input_fn, steps=1000)
classifier.train(input_fn=train_input_fn, steps=1000)

けれども、訓練の間モデルを追跡することに目を向けるならば、代わりにロギング演算を実行するために TensorFlow SessionRunHook を使用することを望むでしょう。

 

モデル精度を評価する

アイリス訓練データで DNNClassifier モデルを訓練しました ; 今、evaluate メソッドを使用してアイリス・テストデータでその精度を確認できます。train のように、evaluate はその入力パイプラインを構築する入力関数を取ります。evaluate は評価結果とともに dict を返します。次のコードはアイリス・テストデータ — test_set.data とtest_set.target — を結果から精度を評価して表示するために渡します :

# Define the test inputs
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)

# Evaluate accuracy.
accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"]

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

Note: numpy_input_fn への num_epochs=1 引数はここでは重要です。test_input_fn はデータに渡り一度だけ反復し、そしてそれから OutOfRangeError をあげます。このエラーは分類器に評価を止めるようにシグナルを送ります、従ってそれは入力について一度だけ評価するでしょう。

 
フル・スクリプトを実行した時、次に近いようなものを出力するでしょう :

Test Accuracy: 0.966667

精度結果は少し様々かもしれませんが、90% より高くなるべきです。比較的小さいデータセットに対しては悪くありません!

 

新しいサンプルを分類する

新しいサンプルを分類するためには estimator の predict() メソッドを使用します。例えば、これら2つの新しい花のサンプルがあるとします :

がく片長さ がく片幅 花弁長 花弁幅
6.4 3.2 4.5 1.5
5.8 3.1 5.0 1.7

predict() メソッドを使用してこれらの種を予測できます。predict は dict の generator を返し、これは簡単にリストに変換されます。次のコードはクラス予測を取得して出力します :

# Classify two new flower samples.
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))

結果は次のように見れるはずです :

New Samples, Class Predictions:    [1 2]

モデルはこうして最初のサンプルはアイリス・バージカラーであることを、そして2つ目のサンプルはアイリス・バージニカであることを予測します。

 

以上

TensorFlow : Get Started : tf.contrib.learn クイックスタート

TensorFlow : Get Started : tf.contrib.learn クイックスタート (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 03/18/2017

* 本ページは、TensorFlow の本家サイトの Get Started – tf.contrib.learn Quickstart を翻訳した上で
適宜、補足説明したものです:
    https://www.tensorflow.org/get_started/tflearn
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

TensorFlow の高位な機械学習 API (tf.contrib.learn) は様々な機械学習モデルを構成し、トレーニングし、そして評価することを容易にします。このチュートリアルでは、花弁 (petal) とガク片 (sepal) の形状をもとに花の種を予測するために、tf.contrib.learn を使用してニューラルネットワーク分類器を構築しそれをアイリス・データセットで訓練します。コードを書いて次の5つのステップを実行します :

  1. アイリス訓練/テストデータを含む CSV を TensorFlow データセットにロードする
  2. ニューラルネットワーク分類器を構築する
  3. 訓練データを使用してモデルを fit する
  4. モデルの精度を評価する
  5. 新しいサンプルを分類する

 

完全なニューラルネットワーク・ソースコード

これがニューラルネットワーク分類器のための full コードです :

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

import os
import urllib

import numpy as np
import tensorflow as tf

# Data sets
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 the training and test sets aren't stored locally, download them.
  if not os.path.exists(IRIS_TRAINING):
    raw = urllib.urlopen(IRIS_TRAINING_URL).read()
    with open(IRIS_TRAINING, "w") as f:
      f.write(raw)

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

  # Load datasets.
  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)

  # Specify that all features have real-value data
  feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]

  # Build 3 layer DNN with 10, 20, 10 units respectively.
  classifier = tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                              hidden_units=[10, 20, 10],
                                              n_classes=3,
                                              model_dir="/tmp/iris_model")
  # Define the training inputs
  def get_train_inputs():
    x = tf.constant(training_set.data)
    y = tf.constant(training_set.target)

    return x, y

  # Fit model.
  classifier.fit(input_fn=get_train_inputs, steps=2000)

  # Define the test inputs
  def get_test_inputs():
    x = tf.constant(test_set.data)
    y = tf.constant(test_set.target)

    return x, y

  # Evaluate accuracy.
  accuracy_score = classifier.evaluate(input_fn=get_test_inputs,
                                       steps=1)["accuracy"]

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

  # Classify two new flower samples.
  def new_samples():
    return np.array(
      [[6.4, 3.2, 4.5, 1.5],
       [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)

  predictions = list(classifier.predict(input_fn=new_samples))

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

if __name__ == "__main__":
    main()

次のセクションでコードを詳細に通り抜けます。

 

アイリス CSV データを TensorFlow にロードする

アイリス・データセットは 150 行のデータを含み、3つの関連アイリス種 : アイリス・セトサ (setosa)、アイリス・バージニカ (virginica)、アイリス・バージカラー (versicolor) のそれぞれから 50 サンプルから成ります。

左から右へ、アイリス・セトサ (by Radomil, CC BY-SA 3.0)、アイリス・バージカラー (by Dlanglois, CC BY-SA 3.0)、そしてアイリス・バージニカ (by Frank Mayfield, CC BY-SA 2.0) です。

各行は各花のサンプルのための次のデータを含みます : がく片長さ、がく片幅、花弁長さ、花弁幅、そして花の種。花の種は整数で表され、0 はアイリス・セトサを示し、1 はアイリス・バージカラーを示し、そして 2 はアイリス・バージニカを示します。

がく片長さ

がく片幅

花弁長さ

花弁幅

5.1

3.5

1.4

0.2

0

4.9

3.0

1.4

0.2

0

4.7

3.2

1.3

0.2

0

7.0

3.2

4.7

1.4

1

6.4

3.2

4.5

1.5

1

6.9

3.1

4.9

1.5

1

6.5

3.0

5.2

2.0

2

6.2

3.4

5.4

2.3

2

5.9

3.0

5.1

1.8

2

このチュートリアルのために、アイリス・データは無作為に2つの別の CSV に分割されます :

始めるには、最初に全ての必要なモジュールをインポートして、データセットをどこにダウンロードしてストアするかを定義します :

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

import os
import urllib

import tensorflow as tf
import numpy as np

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"

そして、訓練とテストセットがまだローカルに保持されていないならば、ダウンロードします。

if not os.path.exists(IRIS_TRAINING):
  raw = urllib.urlopen(IRIS_TRAINING_URL).read()
  with open(IRIS_TRAINING,'w') as f:
    f.write(raw)

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

次に、訓練とテストセットを learn.datasets.base の load_csv_with_header() メソッドを使用してデータセットにロードします。load_csv_with_header() は3つの必要な引数を取ります :

  • filename, これは CSV ファイルへのファイルパスを取ります。
  • target_dtype, これはデータセットの目標値 (target value) の numpy データ型を取ります。
  • features_dtype, これはデータセットの特徴値 (feature values) の numpy データ型を取ります。

ここで、目標 (target, モデルを訓練して予測するための値) は花の種で、これは 0-2 の整数ですから、妥当な numpy データ型は np.int です :

# Load datasets.
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)

tf.contrib.learn のデータセットは named tuples (名前付きタプル) です; データと目標 (target) フィールドを通して特徴データと目標値にアクセスできます。ここで、training_set.data と training_set.target はトレーニングセットのための特徴データと目標値をそれぞれ含み、そして test_set.data と test_set.target はテストセットのための特徴データと目標値を含みます。

後で、”DNNClassifier をアイリス訓練データに fit させる” でモデルを訓練するために training_set.data と training_set.target を使用して、そして “モデル精度を評価する” では test_set.data と test_set.target を使用します。しかしまずは、次のセクションでモデルを構築します。

 

深層ニューラルネットワーク分類器を構築する

tf.contrib.learn は Estimator と呼ばれる、事前定義されたモデルを各種提供しています、これは貴方のデータ上で訓練と評価演算を実行するために “枠にとらわれない (out of the box)” モデルとして使用できます。 ここで、アイリス・データに fit させるために深層ニューラルネットワーク分類器モデルを構成します。tf.contrib.learn を使用して、2、3行のコードで tf.contrib.learn.DNNClassifier をインスタンス化できます :

# Specify that all features have real-value data
feature_columns = [tf.contrib.layers.real_valued_column("", dimension=4)]

# Build 3 layer DNN with 10, 20, 10 units respectively.
classifier = tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                            hidden_units=[10, 20, 10],
                                            n_classes=3,
                                            model_dir="/tmp/iris_model")

上のコードは最初にモデルの特徴カラムを定義します、これはデータセットの特徴のためのデータ型を指定します。全ての特徴データは連続的ですので、特徴カラムを構成するために使用するのに tf.contrib.layers.real_valued_column が適当な関数になります。データセット (ガク片幅、ガク片長さ、花弁幅、花弁高さ (height)) には4つの特徴があり、従って全てのデータを保持するためには次元は 4 でなければなりません。

それから、コードは次の引数を使用して DNNClassifier モデルを作成します :

  • feature_columns=feature_columns. 上で定義された特徴カラムのセット。
  • hidden_units=[10, 20, 10]. 3つの 隠れ層 で、10, 20, そして 10 ニューロンをそれぞれ含みます。
  • n_classes=3. 3つの目標クラスで、3つのアイリス種を表します。
  • model_dir=/tmp/iris_model. モデル訓練の間に TensorFlow が checkpoint データをセーブするディレクトリ。TensorFlow で更にロギングとモニタリングのためには、Logging and Monitoring Basics with tf.contrib.learn を参照してください。

 

訓練入力パイプラインを記述する

tf.contrib.learn API は入力関数を使用し、これはモデルのためのデータを生成する TensorFlow 演算を作成します。この場合は、データは tf.constant TensorFlow 定数にストアできるほどに小さいです。次のコードは最も単純な可能な入力パイプラインを生成します :

# Define the test inputs
def get_train_inputs():
  x = tf.constant(training_set.data)
  y = tf.constant(training_set.target)

  return x, y

 

DNNClassifier をアイリス訓練データに fit させる

DNN classifier モデルを構成した今、fit メソッドを使用してそれをアイリス訓練データに fit させることができます。input_fn として get_train_inputs と、訓練のためのステップ数 (ここでは、2000) を渡します :

# Fit model.
classifier.fit(input_fn=get_train_inputs, steps=2000)

モデルの状態は classifier に保持されます、これは望むならば繰り返し訓練できることを意味します。例えば、上は次と同値です :

classifier.fit(x=training_set.data, y=training_set.target, steps=1000)
classifier.fit(x=training_set.data, y=training_set.target, steps=1000)

けれども、訓練の間モデルを追跡することに目を向けるならば、代わりにロギング演算を実行するために TensorFlow モニタを使用することを望むでしょう。このトピックについての詳細はチュートリアル “Logging and Monitoring Basics with tf.contrib.learn” を参照してください。

 

モデル精度を評価する

アイリス訓練データで DNNClassifier モデルを fit させました ; 今、evaluate メソッドを使用してアイリス・テストデータでその精度を確認できます。fit のように、evaluate は入力パイプラインを構築する入力関数を取ります。evaluate は評価結果とともに dict を返します。次のコードはアイリス・テストデータ —test_set.data とtest_set.target— を結果からの精度を評価して表示するために渡します :

# Define the test inputs
def get_test_inputs():
  x = tf.constant(test_set.data)
  y = tf.constant(test_set.target)

  return x, y

# Evaluate accuracy.
accuracy_score = classifier.evaluate(input_fn=get_test_inputs,
                                     steps=1)["accuracy"]

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

[注意] 評価するための steps 引数はここでは重要です。evaluate は通常は入力の終わりに到達するまで実行されます。ファイルのセットに渡り評価するためにはこれは完璧ですが、ここで使用される constants は期待する OutOfRangeError あるいは StopIteration を決して throw しません。

フル・スクリプトを実行した時、次に近いようなものを出力するでしょう :

Test Accuracy: 0.966667

精度結果は様々かもしれませんが、90% より高くなるべきです。比較的小さいデータセットに対しては悪くありません!

 

新しいサンプルを分類する

新しいサンプルを分類するためには estimator の predict メソッドを使用します。例えば、これら2つの新しい花のサンプルがあるとします :

がく片長さ

がく片幅

花弁長

花弁幅

6.4

3.2

4.5

1.5

5.8

3.1

5.0

1.7

predict() メソッドを使用してこれらの種を予測できます。predict は generator を返し、これは簡単にリストに変換されます。次のコードはクラス予測を取得して出力します :

# Classify two new flower samples.
def new_samples():
  return np.array(
    [[6.4, 3.2, 4.5, 1.5],
     [5.8, 3.1, 5.0, 1.7]], dtype=np.float32)

predictions = list(classifier.predict(input_fn=new_samples))

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

結果は次のように見れるはずです :

New Samples, Class Predictions:    [1 2]

モデルはこうして最初のサンプルはアイリス・バージカラーであることを、そして2つ目のサンプルはアイリス・バージニカであることを予測します。

 

以上

TensorFlow : Get Started : TensorFlow で始めましょう

TensorFlow : Get Started : TensorFlow で始めましょう (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
再検証日時 : 04/13/2017
作成日時 : 03/18/2017

* TensorFlow の Get Started 文書が追加補充され、より分かりやすくなっています。tf.contrib.learn への言及もあります。
* 本ページは、TensorFlow の本家サイトの Get Started – Getting Started With TensorFlow を翻訳した上で適宜、補足説明したものです:
    https://www.tensorflow.org/get_started/get_started
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

このガイドは貴方に TensorFlow によるプログラミングを開始して頂くためのものです。このガイドを使用する前に、TensorFlow をインストールしましょう。このガイドから多くを得るためには、次について知っておくべきです :

  • Python でどのようにプログラムするか。
  • 少なくとも配列について少々。
  • 理想的には機械学習について何某か。けれども、機械学習について殆どあるいは全く知らないとしても、これは依然として読むべき最初のガイドとなるでしょう。

TensorFlow は複数の API を提供します。最も低いレベルの API — TensorFlow Core — は完全なプログラミング制御を貴方に提供します。 機械学習研究者とモデル上の優れた制御レベルを必要とする他の人たちのためには TensorFlow Core を推奨します。より高位の API は TensorFlow Core の上に構築されています。これらの高位 API は典型的には TensorFlow Core よりも学習して使用するのがより簡単です。更に、より高位の API は反復的なタスクをより簡単にして異なるユーザ間で一貫性を保持できます。tf.contrib.learn のような高位 API はデータセット、推定器 (estimator)、トレーニングそして推論を管理する手助けをします。高位 TensorFlow API の2、3 — これらのメソッド名は contrib を含むものです — は依然として開発中であることに注意してください。幾つかの contrib メソッドは後の TensorFlow リリースでは変更されるか廃止される可能性もあります。

このガイドは TensorFlow Core 上のチュートリアルから始めます。後で、同じモデルを tf.contrib.learn でどのように実装するかを示します。TensorFlow Core の原理を知ることは、よりコンパクトな高位 API を使用するときに、どのように物事が内部的に動作するかの偉大なメンタルモデルを与えてくれます。

 

テンソル (Tensors)

TensorFlow におけるデータの中心的なユニットはテンソルです。テンソルは、任意の次元数の配列に形状化されたプリミティブな値のセットから成ります。テンソルのランク (rank) はその次元の数です。テンソルの幾つかの例をここに示します :

3 # a rank 0 tensor; this is a scalar with shape []
[1. ,2., 3.] # a rank 1 tensor; this is a vector with shape [3]
[[1., 2., 3.], [4., 5., 6.]] # a rank 2 tensor; a matrix with shape [2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # a rank 3 tensor with shape [2, 1, 3]

TensorFlow Core チュートリアル

TensorFlow をインポートする

TensorFlow プログラムのための標準的な import ステートメントは次のようなものです :

import tensorflow as tf

これは Python に全ての TensorFlow のクラス、メソッド、そしてシンボルへのアクセスを与えます。殆どのドキュメントは貴方がこれを既に実行していることを仮定しています。

計算グラフ

TensorFlow Core プログラムを2つの個別のセクションから成るものと考えて良いです :

  1. 計算グラフを構築する。
  2. 計算グラフを実行する。

計算グラフはノードのグラフに配列されたTensorFlow 演算の系列です。単純な計算グラフを構築してみましょう。各ノードはゼロまたはそれ以上のテンソルを入力として取り、出力としてテンソルを生成します。ノードの一つの型は constant です。全ての TensorFlow constant のように、それは入力を取らずに、内部的に保持した値を出力します。浮動小数点テンソル node1 と node2 を次のように作成できます :

node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)

最後の print ステートメントは以下を生成します :

Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)

ノードのプリンティングは貴方が期待したような、値 3.0 と 4.0 を出力しないことに注目しましょう。その代わり、それらは評価されたときに 3.0 と 4.0 をそれぞれ生成するノードです。実際にノードを評価するためには、session の中で計算グラフを実行しなければなりません。session は TensorFlow ランタイムの制御と状態をカプセル化します。

次のコードは Session オブジェクトを作成してそして node1 と node2 を評価するために十分な計算グラフを実行するためにその run メソッドを呼び出します。次のように session で計算グラフを実行することにより :

sess = tf.Session()
print(sess.run([node1, node2]))

3.0 と 4.0 の期待した値を見ます :

[3.0, 4.0]

テンソル・ノードを演算 (演算もまたノードです) と結合することでより複雑な計算を構築できます。例えば、2つの constant ノードを加算して新しいグラフを次のように生成できます :

node3 = tf.add(node1, node2)
print("node3: ", node3)
print("sess.run(node3): ",sess.run(node3))

最後の2つの print ステートメントは以下を生成します :

node3:  Tensor("Add_2:0", shape=(), dtype=float32)
sess.run(node3):  7.0

TensorFlow は TensorBoard と呼ばれるユティリティを提供しています、これは計算グラフの図を表示できます。以下は TensorBoard がグラフをどのように可視化するかを示すスクリーンショットです :

そのままでは、このグラフは特に面白くありません、何故ならばこれはいつも定数の結果を生成するからです。

グラフは外部入力を受け取るようにパラメータ化され、これはプレースホルダーとして知られます。プレースホルダーは後で値を提供するという約束 (= promise) です。

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b  # + provides a shortcut for tf.add(a, b)

すぐ前の3行は幾分、関数か lambda のようでそこでは2つの入力パラメータ (a と b) とそしてそれらの上の演算を定義します。これらのプレースホルダーに具体的な値を提供するテンソルを指定するために feed_dict パラメータを使用して、複数の入力でこのグラフを評価できます :

print(sess.run(adder_node, {a: 3, b:4.5}))
print(sess.run(adder_node, {a: [1,3], b: [2, 4]}))

出力は次の結果になります :

7.5
[ 3.  7.]

TensorBoard では、グラフはこのように見えます :

他の演算を追加することで計算グラフをより複雑にできます。例えば :

add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))

は以下の出力を生成します :

22.5

前の計算グラフは TensorBoard では次のように見えるでしょう :

機械学習では典型的には上のように、任意の入力が取れるモデルが望まれます。モデルをトレーニング可能にするためには、同じ入力で新しい出力を得るためにグラフを変更できる必要があります。variable はグラフにトレーニング可能なパラメータを追加することを可能にします。それらは型と初期値で構築されます :

W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b

constant は tf.constant を呼び出したときに初期化されそれらの値は決して変わりません。variable は tf.Variable を呼び出したときに初期化されません。

TensorFlow プログラムで全ての variable を初期化するためには、次のように特殊な演算を明示的に呼び出さなければなりません :

init = tf.global_variables_initializer()
sess.run(init)

init が、全てのグローバル variables を初期化する TensorFlow サブグラフへのハンドルであることを理解することは重要です。sess.run を呼び出すまでは、variables は初期化されないままです。

x はプレースホルダーなので、次のように幾つかの x の値に対して linear_model を同時に評価することができます :

print(sess.run(linear_model, {x:[1,2,3,4]}))

出力は次のように生成されます :

[ 0.          0.30000001  0.60000002  0.90000004]

モデルを作成しましたが、それがどの程度良いかはまだ分かっていません。トレーニング・データ上でモデルを評価するためには、望ましい値を提供する y プレースホルダーが必要で、損失関数を書く必要があります。

損失関数は現在のモデルが提供されたデータからどの程度遠く離れているのかを計測します。線形回帰のための標準的な損失モデルを使用します、これは現在のモデルと提供されたデータの間の delta (差分) の二乗の合計します。linear_model – y はベクトルを作成しこれは各要素が相当するサンプルのエラー delta です。それらのエラーを二乗するために tf.square を呼び出します。それから、tf.reduce_sum を使用して全ての二乗されたエラーを合計して単一のスカラを作成します、これは全てのサンプルのエラーを抽象化します :

y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))

損失値を生成します :

23.66

W と b の値を -1 と 1 という完全な値に再割り当てすることによりこれを手動で改善できるでしょう。variable は tf.Variable に提供された値に初期化されますが tf.assign のような演算子を使用して変更できます。例えば、W=-1 と b=1 はモデルに対しての最適なパラメータです。W と b をそれぞれ変更できます :

fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))

最後の print は今や損失がゼロであることを示します。

0.0

W と b の “完全な” 値を推測しましたが、機械学習の核心は正しいモデルパラメータを自動的に見つけることです。次のセクションでどのようにこれを成し遂げるかを示します。

tf.train API

機械学習の完全な議論はこのチュートリアルの範囲外です。けれども、TensorFlow は損失関数を最小化するために各変数をゆっくりと変更する optimizer を提供します。もっとも単純な optimizer は勾配降下です。それは変数に関する損失の導関数の大きさにしたがって各変数を変更します。一般的に、シンボル型の導関数を手動で計算することは退屈で誤りがちです。結果として、モデルの記述のみが与えられたときに TensorFlow は tf.gradients を使用して自動的に導関数を生成します。単純化のために、optimizer は典型的にはこれを貴方のために行ないます。例えば、

optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range(1000):
  sess.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})

print(sess.run([W, b]))

最終的なモデル・パラメータは :

[array([-0.9999969], dtype=float32), array([ 0.99999082],
 dtype=float32)]

今や実際の機械学習を行ないました! この単純な線形回帰は TensorFlow core コードの多くを必要としませんが、モデルへデータを供給する、より複雑なモデルとメソッドは更なるコードを必要とします。このように TensorFlow は共通のパターン、構造、そして機能のためにより高位の抽象を提供します。次のセクションではこれらの抽象の幾つかをどのように使用するかを学びます。

完全なプログラム

完全なトレーニング可能な線形回帰モデルはこのように示されます :

import numpy as np
import tensorflow as tf

# Model parameters
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x:x_train, y:y_train})

# evaluate training accuracy
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))

実行すると、以下を生成します :

W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11

このより複雑なプログラムは依然として TensorBoard で可視化できます :

tf.contrib.learn

tf.contrib.learn は高位な TensorFlow ライブラリで機械学習の技巧を単純化し、次を含みます :

  • トレーニング・ループを実行する
  • 評価ループを実行する
  • データセットを管理する
  • 供給を管理する

tf.contrib.learn は多くの一般的なモデルを定義します。

基本的な使い方

線形回帰プログラムが tf.contrib.learn でどのくらい単純になるかに注目しましょう :

import tensorflow as tf
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np

# Declare list of features. We only have one real-valued feature. There are many
# other types of columns that are more complicated and useful.
features = [tf.contrib.layers.real_valued_column("x", dimension=1)]

# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# logistic regression, linear classification, logistic classification, and
# many neural network classifiers and regressors. The following code
# provides an estimator that does linear regression.
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)

# TensorFlow provides many helper methods to read and set up data sets.
# Here we use `numpy_input_fn`. We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x = np.array([1., 2., 3., 4.])
y = np.array([0., -1., -2., -3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x}, y, batch_size=4,
                                              num_epochs=1000)

# We can invoke 1000 training steps by invoking the `fit` method and passing the
# training data set.
estimator.fit(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did. In a real example, we would want
# to use a separate validation and testing data set to avoid overfitting.
estimator.evaluate(input_fn=input_fn)

実行時、以下を生成します :

    {'global_step': 1000, 'loss': 1.9650059e-11}

カスタム・モデル

tf.contrib.learn はその事前定義されたモデルに貴方をロックするわけではありません。TensorFlow に組み込まれていないカスタムモデルを作成したいとしましょう。tf.contrib.learn のデータセット、供給、トレーニング等の高位抽象を依然として保持可能です。例示のために、LinearRegressor と同値な私たち自身のモデルをより低位な TensorFlow API の知識を使用してどのように実装するかを示します。

tf.contrib.learn で動作するカスタムモデルを定義するためには、tf.contrib.learn.Estimator を使用する必要があります。tf.contrib.learn.LinearRegressor は実際には tf.contrib.learn.Estimator のサブクラスです。Estimator をサブクラス化する代わりに、tf.contrib.learn にどのように予測、トレーニングステップ、そして損失を評価可能であるかを知らせる関数 model_fn を単純に Estimator に提供します。コードは次のようなものです :

import numpy as np
import tensorflow as tf
# Declare list of features, we only have one real-valued feature
def model(features, labels, mode):
  # Build a linear model and predict values
  W = tf.get_variable("W", [1], dtype=tf.float64)
  b = tf.get_variable("b", [1], dtype=tf.float64)
  y = W*features['x'] + b
  # Loss sub-graph
  loss = tf.reduce_sum(tf.square(y - labels))
  # Training sub-graph
  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))
  # ModelFnOps connects subgraphs we built to the
  # appropriate functionality.
  return tf.contrib.learn.ModelFnOps(
      mode=mode, predictions=y,
      loss=loss,
      train_op=train)

estimator = tf.contrib.learn.Estimator(model_fn=model)
# define our data set
x = np.array([1., 2., 3., 4.])
y = np.array([0., -1., -2., -3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, 4, num_epochs=1000)

# train
estimator.fit(input_fn=input_fn, steps=1000)
# evaluate our model
print(estimator.evaluate(input_fn=input_fn, steps=10))

実行時、以下を生成します :

{'loss': 5.9819476e-11, 'global_step': 1000}

カスタム model() 関数の内容が、どのようにより低位な API からの手動モデルのトレーニング・ループに非常に類似しているかに注意してください。

 

次のステップ

さて今貴方は TensorFlow の基本の実際上の知識を持ちました。更に学ぶために見ることができる幾つかのチュートリアルがあります。もし貴方が機械学習の初心者であるならば ML 初心者向けの MNIST を見てください、そうでなければ 専門家のための深層 MNIST を見てください。

 

以上

TensorFlow : Get Started : 専門家のための深層 MNIST

TensorFlow : Get Started : 専門家のための深層 MNIST(翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
更新日時: 04/26, 03/20/2017
更新日時: 07/28, 07/15, 06/26/2016
作成日時 : 02/14/2016

* 本家サイトのドキュメント構成の変更に伴い、本ページは以下のページをベースにするよう変更し、
また原文の加筆や変更に合わせて翻訳文も更新しました (03/20/2017) :
https://www.tensorflow.org/get_started/mnist/pros
* (obsolete) 本ページは、TensorFlow の本家サイトの Tutorials – Deep MNIST for Experts を翻訳した上で
適宜、補足説明したものです:
(リンク切れ) https://www.tensorflow.org/versions/master/tutorials/mnist/pros/index.html#deep-mnist-for-experts
* サンプルコードの動作確認はしておりますが、適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

TensorFlow は大規模な数値計算を行なうためのパワフルなライブラリです。優れているタスクの一つは深層ニューラルネットワークを実装し訓練することです。このチュートリアルでは TensorFlow モデルの基本的なビルディング・ブロックを学ぶ一方で、深層畳み込み MNIST 分類器を構築します。

このイントロはニューラルネットワークと MNIST データセットに馴染みがあることを仮定しています。もし貴方がそれらの背景がないのであれば、初心者向けのイントロ をチェックしてください。

 

このチュートリアルについて

このチュートリアルの最初のパートは mnist_softmax.py コードで何が起きているのかを説明します、これは TensorFlow モデルの基本的な実装です。2番目のパートは精度を改善するための幾つかの方法を示します。

貴方はこのチュートリアルから各コード・スニペットを Python 環境にコピー & ペーストすることができますし、あるいはコードを読み通すだけという選択もできます。

このチュートリアルで達成することは :

  • 画像の全てのピクセルを見ることを元に、数字を認識するためのモデルである softmax 回帰関数を作成します。
  • 数千のサンプルを “見させる” ことで数字を認識するように TensorFlow を使ってモデルをトレーニングします (そしてそれを行なうように最初の TensorFlow session を実行します)。
  • テストデータでモデル精度をチェックします。
  • 結果を改善するために多層畳込みニューラルネットワークを構築し、トレーニングし、そしてテストします。
 

セットアップ

我々のモデルを作成する前に、最初に MNIST データセットをロードし、そして TensorFlow セッションを開始します。

MNIST データのロード

もし貴方がこのチュートリアルからのコードにおいてコピー&ペーストしているならば、データを自動的にダウンロードして読み込むこの2行のコードから始めましょう :

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

ここで mnist は軽量のクラスで、訓練、検証そしてテスト・セットを NumPy 配列としてストアしています。これはまたデータ・ミニバッチを通して反復するための関数も提供し、これは下で使います。

TensorFlow InteractiveSession を開始する

TensorFlow は計算を行なうために高度に効率的な C++ バックエンドに頼っています。このバックエンドへの接続はセッションと呼ばれています。TensorFlow プログラムの共通する利用法は最初にグラフを作成してそしてセッションの中に launch することです。

ここでは代わりに便利な InteractiveSession クラスを使います、これはどのようにコードを構成するかについて TensorFlow をより柔軟にします。これはグラフを実行する演算とともに 計算グラフ を構築する不連続な操作を可能にします。これは IPython のような対話的なコンテキストで作業する時に特に便利です。もし InteractiveSession を使わないのであれば、セッションを開始して グラフを launch する前に全体の計算グラフを構築すべきです。

import tensorflow as tf
sess = tf.InteractiveSession()

計算グラフ

Python で効率的な数値計算を行なうために、私たちは典型的には NumPy のようなライブラリを用います。これらは他の言語で実装された高度に効率的なコードを用い、Python の外で行列乗算のような高価な演算を行ないます。不幸なことに全ての演算について Python へのスイッチバックから依然として多くのオーバヘッドがあります。これらのオーバヘッドは、データ転送に高いコストが存在し得る GPU 上や分散マナーでの計算を実行したい場合は特に悪いです。

TensorFlow もまた Python の外へ重い持ち出しをしますが、このオーバーヘッドを避けるためにもう一歩先に進んでいます。Python から独立的に単独の高価な演算を実行する代わりに、TensorFlow は Python の外で完全に動作する、相互に作用する演算のグラフを記述することを可能にします。このアプローチは Theano や Torch で使われているものと類似のものです。

従って Python コードの役割は、この外部計算グラフを構築し、そして計算グラフのどのパートが実行されるべきかを命じることにあります。より詳細は 基本的な使い方 の計算グラフのセクションを見てください。

 

Softmax 回帰モデルを構築する

このセクションでは単一の線形層で softmax 回帰モデルを構築します。次のセクションでは、これを多層の畳み込みネットワークで softmax 回帰の例に拡張します。

プレースホルダー

入力画像と目的出力クラスのためのノードを作成することにより計算グラフの組み立てを開始します。

x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])

ここで x と y_ は特定の値ではありません。むしろ、個別のプレースホルダーです — TensorFlow に計算を実行することを依頼する時に入力する値です。

入力画像 x は浮動小数点の 2d テンソルからなります。ここで shape [None, 784] を割り当てます、784 は一つの平坦化した MNIST 画像の次元数で、None は、バッチサイズに相当する最初の次元が任意のサイズを取りうることを示しています。目的出力クラス y_ はまた 2d テンソルからなり、各行は one-ホット 10-次元ベクタで該当の MNIST 画像がどの数字クラス (0 から9 まで) に属するかを示しています。

プレースホルダーへの shape (形状)引数はオプションですが、しかしそれは TensorFlow が矛盾するテンソル形状に由来するバグを自動的に捉えることを可能にします。

変数

今私たちのモデルのために重み W とバイアス b を定義します。これらを追加入力のように扱うことも考えられますが、TensorFlow はこれらを扱うよりもより良い方法持ちます : 変数です。変数は TensorFlow の計算グラフで生存する値です。計算により使用できて修正さえ可能です。機械学習アプリケーションにおいて、一般に持つモデル・パラメータは変数となります。

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

tf.Variable への呼び出しで各パラメータに初期値を渡します。この場合、W と b を全て 0 のテンソルとして初期化します。W は 784 x 10 行列(何故なら 784 入力特徴と 10 出力を持つから)で b は 10-次元ベクタ(何故なら 10 クラスあるから)です。

変数がセッションで使用可能になる前に、これらはそのセッションを使って初期化されなければなりません。このステップは既に指定されている初期値(この場合はテンソルは全て 0)を取り、そして各変数にそれらを割り当てます。これは全ての変数について一度で行なわれます。

sess.run(tf.global_variables_initializer())

予測クラスとコスト関数

今我々の回帰モデルが実装できます。わずか1行だけです! ベクタ化された入力画像 x を重み行列 W で乗算し、バイアス b を加算します。

y = tf.matmul(x,W) + b

損失関数は簡単に指定できます。損失は単一のサンプル上でモデルの予測がどの程度悪いかを示します; 全てのサンプルに渡りトレーニングの間にそれを最小化しよとします。ここで、損失関数はターゲットとモデルの予測に適用される softmax 活性化関数の間のクロス・エントロピーです。初心者チュートリアル内のように、安定した式を使用します :

cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

tf.nn.softmax_cross_entropy_with_logits は内部的にはモデルの正規化されていないモデル予測上で softmax を適用して全てのクラスに渡り合計し、そして tf.reduce_mean がそれらの合計の平均を取ります。

 

モデルを訓練する

我々のモデルと訓練するコスト関数を定義した今、TensorFlow を使って訓練するだけです。TensorFlow は全体の計算グラフを知っているので、各変数に関連してコストの勾配を見つけるために自動微分が使用できます。TensorFlow は様々な 組み込みの最適化アルゴリズム を持ちます。この例では、交差エントロピーを降るために 0.5 のステップ長で最急勾配降下を用います。

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

TensorFlow がその単一の行で実際に行なったことは計算グラフに新しい演算を追加したことです。これらの演算は勾配を計算し、パラメータ更新ステップを計算して更新ステップをパラメータに適用するためのものを含みます。

戻り値の演算 train_step は、実行時、勾配降下更新をパラメータに適用します。モデルの訓練は従って train_step を繰り返し実行することにより達成されます。

for _ in range(1000):
  batch = mnist.train.next_batch(100)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

各訓練反復で 100 訓練サンプルをロードします。そして プレースホルダー・テンソル x と y_ を訓練サンプルで置き換えるために feed_dict を用いて train_step 演算を実行します。feed_dict を用いて計算グラフの任意のテンソルを置き換えられることに注意してください — プレースホルダーのみに制限されているわけではありません。

モデルを評価する

我々のモデルはどの程度上手くやれたでしょうか?

最初にどこで正しいラベルを予測したかをはっきりさせましょう。tf.argmax は非常に有用な関数である軸に沿ってテンソルのもっとも高いエントリのインデックスを与えます。例えば、tf.argmax(y,1) が各入力に対して我々のモデルがもっともそれらしいと考えるラベルで、一方で tf.argmax(y_,1) は真のラベルです。予測が真の値にマッチしているか確認するためには tf.equal が使用できます。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

それはブール値のリストを与えます。どの程度の分数が正しいか決定するために、浮動小数点数値にキャストしてから平均を取ります。例えば、[True, False, True, True] は [1,0,1,1] となりこれは 0.75 となります。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

最後に、テストデータ上の精度を評価できます。これは約 92% 正しくなるはずです。

print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
 

多層畳み込みネットワークを構築する

MNIST 上の 92 % の精度の取得は悪いです。ほとんど当惑するほど悪いです。このセクションでは、これを解決します、非常に簡単なモデルから適度に洗練されたもの: 小さい畳み込みニューラルネットワークへとジャンプします。これは 99.2% 程度の精度へ導いてくれます — 最先端のものではありませんが、立派なものです。

重みの初期化

このモデルを作成するためには、多くの重みとバイアスを作成していく必要があります。一般に対称性の破れのため、そして 0 の勾配を防ぐために、微量のノイズとともに重みを初期化すべきです。ReLU ニューロンを使用していますので、”死んだニューロン” を回避するためにわずかに正の初期バイアスでそれらを初期化することは良い実践です。モデルを構築する間に繰り返しこれを行なう代わりに、それを行なう2つの便利な関数を作成しましょう。

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)

*訳注 : tf.truncated_normal は、切断正規分布から乱数値を出力します。

畳み込みとプーリング

TensorFlow はまた、畳み込みとプーリング処理について多くの柔軟性を与えてくれます。境界をどのように処理しましょうか? ストライドの間隔はどのくらい?この例では、我々はいつも普通の版を選択していきます。我々の畳み込みは 1 のストライドを用い、0 でパディングされますので出力は入力と同じサイズになります。プーリングは 2×2 ブロックの分かりやすい古典的な最大プーリングです。コードをきれいに保つため、これらの演算もまた関数に抽象化しましょう。

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')

第1畳み込み層

今私たちは第1層の実装ができます。畳み込み(層)と、それに続く最大プーリング(層)から成り立ちます。畳み込みは各 5×5 パッチのために 32 の特徴を計算します。その重みテンソルは [5, 5, 1, 32] の形状を持ちます。最初の2次元はパッチ・サイズで、次が入力チャネルの数、そして最後が出力チャネルの数です。各出力チャネルのための成分を持つバイアス・ベクタをまた持ちます。

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

この層を適用するために、第2と3の次元は画像の幅と高さに相当し、そして最後の次元はカラー・チャネル数に相当するように、(入力)x を 4d テンソルに最初に reshape します。

x_image = tf.reshape(x, [-1,28,28,1])

そして x_image を重みテンソルで畳み込み、バイアスを加算し、ReLU 関数を適用し、そして最後に最大プールします。

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

第2畳み込み層

深層ネットワークを構築するために、このタイプの幾つかの層を積み重ねます。第2層は各 5×5 パッチに対して 64 の特徴を持ちます。

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)
h_pool2 = max_pool_2x2(h_conv2)

密結合された層(Densely Connected Layer, 全結合層)

画像サイズが 7×7 まで減じられた今、画像全体の処理を可能にするために 1024 ニューロンの全結合層を追加します。プーリング層からのテンソルをベクタのバッチに reshape し、重み行列を乗算し、バイアスを加算し、ReLU を適用します。

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)

ドロップアウト

過学習を減じるために、読み出し層 (readout layer) の前にドロップアウトを適用します。確率のためにプレースホルダーを作成します、これはニューロンの出力をドロップアウトの間保持するものです。これは訓練の間はドロップアウトを有効にし、テストの間には無効にすることを可能にしてくれます。TensorFlow の tf.nn.dropout OP はニューロン出力のマスクに加えてスケーリングを自動的に処理します、ドロップアウトは追加のスケーリングなしに動作します。(注釈 1)

keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

読み出し層 (Readout Layer)

最後に、上述の softmax 回帰の一つの層のように、softmax 層を追加します。

W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

モデルを訓練し評価する

このモデルはどの程度上手くやるでしょう? それを訓練し評価するために上述の簡単な単層 SoftMax ネットワークのものとほぼ同一のコードを用います。

違いは次のようなものです :

  • 最急勾配降下オプティマイザーをより洗練された ADAM オプティマイザーで置き換えます。
  • ドロップアウト率を制御するために feed_dict の追加パラメータ keep_prob を含めます。
  • 訓練プロセスにおいて 100 番目の反復毎にロギングを追加します。

続けてこのコードを実行してください、しかしそれは 20,000 訓練反復を行ない、
貴方のプロセッサに依存して、しばらくの時間がかかるでしょう (おそらく半時間まで)。

cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
sess.run(tf.global_variables_initializer())
for i in range(20000):
  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}))

このコードを実行した後の最終的なテストセットの精度は約 99.2 % になるでしょう。

訳注: 実際に丁度 99.2 % の精度になりました。

我々は TensorFlow を使って、どのように素早く簡単にかなり洗練された深層学習モデルを構築し、訓練しそして評価するかを学びました。

注釈 1: この小さな畳込みネットワークに対しては、性能は実際には dropout があってもなくても殆ど同じです。dropout はしばしば過学習を減じるのに有効ですが、それは非常に巨大なニューラルネットワークをトレーニングするときに最も有用です。

 

以上

TensorFlow : Get Started : ML 初心者向けの MNIST

TensorFlow : Get Started : ML 初心者向けの MNIST (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
更新日時: 04/13, 03/19/2017; 07/14, 06/26/2016
作成日時 : 01/26/2016

* 本家サイトのドキュメント構成の変更に伴い、本ページは以下のページをベースにするよう変更し、
また原文の加筆や変更に合わせて翻訳文も更新しました (03/19/2017) :
https://www.tensorflow.org/get_started/mnist/beginners
* (obsolete) 本ページは、TensorFlow の本家サイトの Tutorials – MNIST For ML Beginners を翻訳した上で
適宜、補足説明したものです:
(リンク切れ) https://www.tensorflow.org/versions/master/tutorials/mnist/beginners/index.html#mnist-for-ml-beginners
* サンプルコードの動作確認はしておりますが、適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

このチュートリアルは機械学習と TensorFlow の初心者である読者を想定しています。もし貴方が MNIST が何であるか、そして softmax(多項ロジスティック)回帰が何であるか既に知っているのであれば、より 早いペースのチュートリアル が良いかもしれません。

どのようにプログラムをするか学ぶ時、最初に行なうことは “Hello World.” をプリントするという慣例があります。プログラミングに “Hello World” があるように、機械学習には “MNIST” があります。

MNIST は簡単なコンピュータ・ビジョンのデータセットで、このような手書き数字の画像から成ります :

データセットはまた、どの数字かを教えてくれる各画像へのラベルを含みます。例えば、上の画像へのラベルは 5, 0, 4 そして 1 です。

このチュートリアルでは、画像を見てどの数字であるか予測できるようにモデルを訓練していきます。我々の目的は最先端のパフォーマンスを達成できるような本当に手の込んだモデルを訓練することではありません — 後でそれを行なうコードを与えますが! — しかしそれよりも TensorFlow の利用に足を踏み入れることです。そういったわけで、非常に簡単なモデルから始めます、これは Softmax 回帰と呼ばれます。

このチュートリアルの実際のコードは非常に短く、全ての興味深いことはわずか3行の内に発生します。しかし、背後のアイデアを理解することは非常に重要です: どのように TensorFlow が動作するか、そして中心的な機械学習の概念です。それ故に、注意深くコードに取り組んでいきます。

 

このチュートリアルについて

このチュートリアルは mnist_softmax.py コードにおいて何が起きているのかの、1行ずつの説明です。

このチュートリアルを2、3の異なった方法で利用可能です、それは :

  • 各行の説明を読み通したら各コード・スニペットを1行ずつ python 環境にコピー&ペーストします。
  • 説明を通読する前なり後で mnist_softmax.py Python ファイル全体を実行し、そしてこのチュートリアルを貴方にとってクリアでないコードの行を理解するために使用します。

このチュートリアルで達成することは :

  • MNIST データと softmax 回帰について学習します。
  • 画像の全てのピクセルを見ることを基に、数字を認識するためのモデルである関数を作成します。
  • 数千のサンプルを “見させる” ことで数字を認識するように TensorFlow を使ってモデルをトレーニングします (そしてそれを行なうように最初の TensorFlow session を実行します)。
  • テストデータでモデル精度をチェックします。
 

MNIST データ

MNIST データは Yann LeCun’s website にホストされています。もし貴方がこのチュートリアルからのコードにおいてコピー&ペーストしているならば、データを自動的にダウンロードして読み込むこの2行のコードから始めましょう :

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

ダウンロードされたデータは3つのパートに分かれます、訓練データの 55,000 データ・ポイント (mnist.train)、テスト・データの 10,000 ポイント (mnist.test) そして検証データの 5,000 ポイント (mnist.validation) です。この分割は非常に重要です : 機械学習において学習には使わない隔離データを持つことは本質的です。これにより学習したものが実際に一般化されていることを確かなものにできます!

先に言及したように、全ての MNIST データポイントは2つのパートを持ちます : 手書き数字の画像と該当ラベルです。画像を “x” そしてラベルを “y” と呼ぶことにします。訓練セットとテストセットは画像と該当するラベルを含みます; 例えば訓練イメージは mnist.train.images で訓練ラベルは mnist.train.labels です。

各画像は 28 ピクセル x 28 ピクセルです。これは数値の大きな配列と解釈することができます。

この配列を 28 x 28 = 784 数値のベクタに平坦化できます。画像間で一貫していればどのように配列を平坦化するかは問題ではありません、この見地からは、MNIST 画像は very rich structure (訳注: 計算集約型視覚化)を持つ、784-次元のベクタ空間のたくさんのポイントになります。

データの平坦化は画像の 2D 構造についての情報を捨てています。これはまずくないでしょうか? そうですね、ベストなコンピュータ・ビジョンの方法ではこの構造を利用しますので、後のチュートリアルでそうしましょう。しかしここで使う単純な方法 – softmax 回帰 – では利用しません。

結果は mnist.train.images は [55000, 784] の shape(形状)を持つテンソルになります。最初の次元は画像へのインデックスで2つめの次元は各画像のピクセルへのインデックスです。テンソルの各要素は特定の画像の特定のピクセルのための 0 と 1 の間のピクセル濃度です。

MNIST の該当するラベルは 0 から 9 の間の数字で、与えられた画像がどの数字であるかを示します。

このチュートリアルの目的のためにはラベルは “one-hot ベクタ” であることを望みます。one-hot ベクタはほとんどの次元で 0 で、一つの次元で 1 であるベクタです。この場合、n 番目の数字は n 番目の次元が 1 のベクタとして表されます。例えば、3 は [0,0,0,1,0,0,0,0,0,0] になります。結果的に、mnist.train.labels は float の [55000, 10] 配列になります。

今、我々のモデルを実際に作成する準備ができました!

 

Softmax 回帰

MNIST の全ての画像が、それが 0 であろうが 9 であろうが、数字であることを我々は知っています。我々は画像を見て(その画像に)各々の数字である確率を与えることができるようにしたいのです。例えば、我々のモデルは 9 の画像を見て、その画像が 9 であることが 80 % 確かであり、しかし((数字の形状の)上部のループゆえに) 8 である 5 % の可能性を与え、そして確信が持てないために全ての他の数字にも少しの可能性を与えます。

これは softmax 回帰が自然で簡単なモデルとなる古典的なケースです。幾つかの異なるものの一つであるオブジェクトに確率を割り当てたいならば、softmax がこれを行なってくれます。何故ならば softmax が(合計すると 1 になる) 0 と 1 の間の値のリストを与えてくれるからです。後に、より洗練されたモデルを訓練する時にさえも、最終ステップは softmax 層になります。

softmax 回帰は2つのステップを持ちます : 一つは、入力の、確かと考えるクラスに属するための証拠 (evidence) を集計すること、そして証拠を確率に変換します。

与えられた画像がある特定のクラスに属す証拠を計算するために、ピクセル強度の加重和(重みつき和)を取ります。高い強度を持つピクセルが画像があるクラスに属することへの反証となるのであれば重みはネガティブ(負値)です。そして補強する証拠であればポジティブ(正値)です。

次の図は一つのモデルがこれらのクラスについて学習した重みを示しています。赤色はネガティブな重みを表し、青色はポジティブな重みを表しています。

 
更に、バイアスと呼ばれる、特別な証拠も追加します。基本的に、入力からは独立的にある事象が起きやすいと言いたいがためです。結果的に入力 \(x\) が与えられた時のクラス \(i\) の証拠は :

\[\text{evidence}_i = \sum_j W_{i,~ j} x_j + b_i\]

ここで \(W_i\) は重みで \(b_i\) はクラス \(i\) のためのバイアス、そして \(j\) は入力画像 \(x\) のピクセルについて集計するためのインデックスです。そして証拠の合計を “softmax” 関数を使って予測確率 \(y\) に変換します :

\[y = \text{softmax}(\text{evidence})\]

ここで softmax は “活性化” あるいは “リンク” 関数として機能し、線形関数の出力を望ましい形式に整形します – この場合は 10 ケースの確率分布です。これは証拠の合計を、入力が各クラスに属する確率に変換するものとして考えることができます。次のように定義されます :

\[\text{softmax}(x) = \text{normalize}(\exp(x))\]

この式を展開すれば、次を得ます :

\[\text{softmax}(x)_i = \frac{\exp(x_i)}{\sum_j \exp(x_j)}\]

しかし softmax を最初の方法で考えることはしばしば有用です : 入力のべき乗(指数関数)を求めて正規化します。べき乗は、証拠の更なる1単位が任意の仮説に与えられた重みを乗法的に増加することを意味します。逆に、証拠の1単位の減少は、仮説に以前の重みのわずかな減少を与えられることを意味します。どの仮説も 0 や負の重みは決して持ちません。Softmax はそしてこれらの重みを正規化し、その結果、総計は 1 になり、有効な確率分布を形成します。(softmax 関数についてより直感的な知識を得たいのであれば、対話的な視覚化を完備する、Michael Nieslen の本のそれについての セクション を詳細に参照してください。)

softmax 回帰は次のような感じで図示できます、より多くの x を持ちますが。各出力に対して、x の重み合計を計算し、バイアスを加え、そして softmax を適用します。

数式で書くならば、以下を得ます :

この手続きは、行列の乗算とベクタの加算に変換することにより “ベクタ化” できます。これは計算効率のために有用です。(考えるにもまた良い方法です。)

よりコンパクトに単に :

\[y = \text{softmax}(Wx + b)\]

と書けます。

さてこれを TensorFlow が利用できるようなものにしましょう。

 

回帰を実装する

Python における効率的な数値計算を行なうためには、通常は NumPy のようなライブラリを用います。これらは他の言語で実装された高く効率化されたコードを用い、Python の外で行列の乗算のようなコスト高な演算を実行します。不運なことに、全ての演算において依然として Python へのスイッチバックからたくさんのオーバーヘッドがあります。このオーバーヘッドは、データ転送に高いコストがかかる、GPU 上や分散手法で計算を実行することを望む場合、特に悪いです。

TensorFlow もまた重たい演算を Python の外に持ち出しますが、このオーバーヘッドを回避するために物事を一歩先に進めています。Python から独立的に単一の高価な演算を実行する代わりに、TensorFlow は Python の外で完全に走る相互作用する演算のグラフの記述を可能にします。(このようなアプローチは2、3の機械学習ライブラリで見られます。)

TensorFlow を使うためには、import する必要があります。

import tensorflow as tf

シンボリックな変数を操作することによりこれらの相互作用する演算を記述します。一つ作成してみましょう :

x = tf.placeholder(tf.float32, [None, 784])

x は特定な値ではありません。これはプレースホルダーです。TensorFlow に計算の実行を依頼する時に入力する値です。我々は各々 784-次元ベクタに平坦化された MNIST 画像の任意の個数を入力できることを望みます。これを shape [None, 784] を持つ浮動小数点数値の 2-D テンソルとして表します。(ここでは None は次元が任意の長さを取りうることを意味しています。)

我々のモデルには重みとバイアスもまた必要です。これらを追加の入力のように扱うことも考えられますが、TensorFlow はそれを処理するにより良い方法を持っています : 変数 (Variable) です。変数は変更可能なテンソルで、相互作用の演算の TensorFlow のグラフの中で有効です。計算により利用可能で変更可能でさえもあります。機械学習のアプリケーションは、一般に、モデルパラメータを変数として持ちます。

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

変数の初期値を tf.Variable に与えることによってこれらの変数を作成します : この場合、全てゼロのテンソルとして W も b も初期化します。W と b を学習しますので、最初にどのような値であるかはそれほど重要ではありません。

W は [784, 10] の shape(形状)を持つことに注意してください。何故なら、それを 784-次元画像ベクタに乗算することによって異なるクラスのための証拠の 10-次元ベクタを生成することになるからです。b は [10] の shape を持ち、出力に加算できます。

ここにおいて我々のモデルが実装可能です。それを定義するためにわずか1行だけしかかかりません!

y = tf.nn.softmax(tf.matmul(x, W) + b)

最初に tf.matmul(x, W) という式で x に W を乗算します。この式では、\(Wx\) であった、先の我々の式でそれらを乗算した時とは(順序が)ひっくり返されていますが、これは x を複数の入力をもつ 2D テンソルとして扱うための小さなトリックです。それから b を加算し、最後に tf.nn.softmax を適用します。

これで全部です。短い数行のセットアップ後、我々のモデルを定義するのに1行しかかかりません。これは、TensorFlow が softmax 回帰を特に簡単にするように設計されているからではありません : 機械学習モデルから物理シミュレーションまで、数値計算の多くの種類を記述するに柔軟だからです。そして一度定義されれば、我々のモデルは異なるデバイスで実行されます : 貴方のコンピュータの CPU、GPU そしてスマホでさえもです!

 

訓練

我々のモデルを訓練するためには、モデルが良いとは何を意味するかを定義する必要があります。実際には、機械学習ではモデルが悪いとは何を意味するかを通常は定義します。これをコスト、あるいは損失と呼び、そしてそれは私たちのモデルが望ましい結果からどの程度遠く離れているかを表しています。エラーを最小化しようとします、そしてエラー・マージンが小さくなればモデルもより良くなります。

非常に一般的で良いコスト関数の一つは “交差(クロス)エントロピー”です。交差エントロピーは情報理論において情報圧縮コード (information compressing codes) について考えることから発生しています。しかし、それはギャンブルから機械学習まで、幅広い領域で重要なアイデアとなる結果になっています。それは以下で定義されます :

\[H_{y'}(y) = -\sum_i y'_i \log(y_i)\]

ここで \(y\) は我々が予測した確率分布で、\(y'\) は(入力する one-hot ベクタの)真の分布です。大雑把な意味では、交差エントロピー我々の予測が真実 (truth) を記述するにどのくらい非効率であるかをを計測します。交差エントロピーについてより詳細に踏み込むのはこのチュートリアルの範囲を超えていますが、理解する 価値は十分にあります。

交差エントロピーを実装するには、正解を入力するための新しいプレースホルダーの追加が最初に必要です :

y_ = tf.placeholder(tf.float32, [None, 10])

これにより交差エントロピー \(-\sum y'\log(y)\) が実装できます :

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

最初に、tf.log は y の各要素の対数を計算します。次に、_y の各要素と tf.log(y) の該当する要素を乗算します。それから tf.reduce_sum が reduction_indices=[1] パラメータによって、y の2番目の次元における要素を加算します。最後に、tf.reduce_mean がバッチの全てのサンプルに渡り mean を計算します。

これは一つの予測と正解の交差エントロピーではなく、我々が見ていた全ての画像のための交差エントロピーの合計である点に注意してください。この例で言えば、各バッチに 100 の画像を持ちます : 100 のデータポイント上でどの程度上手くやっているかは、一つのデータポイントよりも、我々のモデルがどの程度良いかを表すはるかに良い記述となります。

ソースコードで、この式を使っていないことに注意してください、何故ならばそれは数値的に不安定だからです。代わりに、正規化されていないロジット上で tf.nn.softmax_cross_entropy_with_logits を適用しています (e.g., tf.matmul(x, W) + b 上で softmax_cross_entropy_with_logits を呼び出します)、何故ならばこの数値的により安定的な関数が内部的に softmax 活性を計算するからです。貴方のコードでは、代わりに tf.nn.softmax_cross_entropy_with_logits を使用することを考えましょう。

我々のモデルに何をすることを望むかを知った今、TensorFlow にそれをするために訓練させることは非常に容易です。TensorFlow は貴方の計算のグラフの全体を知っていますので、変数がどのように(最小化したい)コストに影響を与えるか効率的に決定するために、自動的に バックプロパゲーション・アルゴリズム を使用することができます。そして最適化アルゴリズムの貴方の選択を適用して変数を変更しコストを減じます。

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

この例では、0.01 の学習率で勾配降下法アルゴリズムを使って TensorFlow に交差エントロピーを最小化させることを依頼します。勾配降下法は単純な手続きで、ここでは TensorFlow はコストを減少させる方向に各変数をほんの少し単にシフトします。しかし、TensorFlow はまた 多くの他の最適化アルゴリズム を提供しています : 一つを使用することは一行調整する程度に簡単です。

ここで TensorFlow が裏で実際に行なうことは、バックプロパゲーションと勾配降下法をを実装する新しい演算をグラフに追加することです。そして TensorFlow は一つの演算を返します。これは、実行時に、勾配降下訓練のステップを行ない、コストを減少させるために変数を微調整するものです。

これで InteractiveSession でモデルを launch できます :

sess = tf.InteractiveSession()

最初に作成した変数を初期化するための演算を作成しなければなりません :

tf.global_variables_initializer().run()

訓練しましょう — 訓練ステップ 1000 回を実行します!

for _ in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

ループの各ステップで、訓練セットから 100 のランダムなデータポイントの “バッチ” を取得します。プレースフォルダーを置き換えるバッチデータを供給 (feed) して train_step を実行します。

ランダム・データの小さなバッチを使用することを確率的訓練 – この例では、確率的勾配降下法と呼称します。理想的には、訓練の全てのステップで全てのデータを使用したいのです。何故ならそれは何をなすべきかのより良いセンスを与えてくれるからです。しかしこれは高くつきます。そこで代わりに、毎回異なるサブセットを使用します。これを行なうのは安価で、かつ同様な多くの恩恵があります。

 

モデルを評価する

我々のモデルはどの程度上手くやるでしょうか?

そうですね、最初に正解のラベルを予測した場所を把握しましょうか。tf.argmax は非常に有用な関数である軸に沿ったテンソルのもっとも高い要素のインデックスを与えます。例えば、tf.argmax(y,1) はモデルが各入力に対して最も尤もらしい(= 一番ありそう)と考えるラベルで、一方で tf.argmax(y_,1) は正解のラベルです。予測が正解と合っているか確認するためには tf.equal が利用できます。

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

これはブール値のリストを与えます。どのくらいの割合が正しいか決定するために、浮動小数点数値にキャストして平均を取ります。例えば、[True, False, True, True] は [1,0,1,1] となり、これは 0.75 となります。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

最後に、テストデータ上で精度を求めます。

print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

これは約 92 % になるでしょう。

これは良いでしょうか?う~ん、そうでもないですね。事実、これはかなり悪いです。これは我々が非常に単純なモデルを使っているからです。幾つかの小さな変更で、97% にまで到達できます。ベストなモデルは 99.7% を超えた精度に到達可能です!(更なる情報は、結果のリスト を見てください。)

重要なのはこのモデルから学んだことです。依然として、これら結果について少しがっかりしているのであれば、次のチュートリアル をチェックしてください。ここでは多くの改良を行ない、TensorFlow を使ったより洗練されたモデルを構築する方法を学びます!

 

以上

TensorFlow : Get Started : TensorFlow 技法 101

TensorFlow : Get Started : TensorFlow 技法 101 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 09/12/2017; 07/29/2016
作成日時 : 01/23/2016

* 本ページは、TensorFlow 本家サイトの Get Started – TensorFlow Mechanics 101 を翻訳した上で
適宜、補足説明したものです:

* (obsolete, リンク切れ) 本ページは、TensorFlow の本家サイトの Tutorials – TensorFlow Mechanics 101 を翻訳した上で
適宜、補足説明したものです:

  • https://www.tensorflow.org/versions/master/tutorials/mnist/tf/index.html

* サンプルコードの動作確認はしておりますが、適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 
本文

コード : tensorflow/examples/tutorials/mnist/

このチュートリアルの目的は、(古典的な)MNIST データセットを利用した手書き数字分類のための単純な feed-forward(順伝播型)ニューラルネットワークを学習させて評価するためにどのように TensorFlow を利用するかを示すことです。このチュートリアルの想定読者は TensorFlow を利用することに興味がある、機械学習の経験があるユーザです。

これらのチュートリアルは機械学習一般を教えることは意図していません。

 

チュートリアルのファイル

このチュートリアルでは次のファイルを参照します :

(ファイル : 目的)
mnist.py : このコードは full-connected(全結合)な MNIST モデルを構築します。

fully_connected_feed.py : 構築された MNIST モデルをダウンロードしたデータセットに対して feed 辞書を使って学習させるためのメイン・コードです。

学習を始めるには fully_connected_feed.py ファイルを単に直接実行するだけです :

$ python fully_connected_feed.py
 

データの準備

MNIST は機械学習の古典的な問題です。手書き数字のグレースケールの 28 x 28 ピクセル画像を見て画像が 0 から 9 までのどの数字を表しているかを決定する問題です。

より詳細な情報は、Yann LeCun’s MNIST page または Chris Olah’s visualizations of MNIST を参照してください。

ダウンロード

run_training() メソッドの冒頭では、input_data.read_data_sets() 関数が正しいデータがローカル学習フォルダにダウンロードされたかを保証し、それからデータセットのインスタンスの辞書を返すためにデータを取り出します。

data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)

注意: fake_data フラグはユニットテスト目的で使われますので reader で無視しても安全です。

データセット

目的

data_sets.train :

55000 イメージとラベル、主な学習用。

data_sets.validation :

5000 イメージとラベル、学習中の正確さの反復 (iterative) バリデーション(検証)のため。

data_sets.test :

10000 イメージとラベル、学習した正確性の最終的なテストのため。

データについての更なる情報は、MNIST データ・ダウンロード チュートリアルを読んでください。

入力とプレースホルダー

placeholder_inputs() 関数は残りのグラフに対して batch_size を含む入力の shape(形状)を定義する、2つの tf.placeholder OP を作成します。そしてそこに実際の学習サンプルが供給 (feed) されます。

images_placeholder = tf.placeholder(tf.float32, shape=(batch_size, IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))

更に(コードを)進むと、学習ループの中で、全体の画像とラベルのデータセットは各ステップのために batch_size に適合するようにスライスされ、これらのプレースホルダー OP に合わせられ、そして feed_dict パラメータを使って sess.run() 関数の中に渡されます。

 

グラフの構築

データのためのプレースホルダーを作成した後、3-ステージ・パターン : inference()、loss() そして training() に従って mnisty.py からグラフが構築されます。

  1. inference()(= 推論) – 予測するためにネットワークを前向きに実行するために必要な限り(推論)グラフを構築する。
  2. loss() – 推論グラフに損失を生成するために必要な OP を追加する。
  3. training() – 勾配を計算して適用するために必要な OP を損失グラフに追加する。

Inference(推論)

inference() 関数は出力予測を含むテンソルを返す必要がある限りグラフを構築します。

(inference() は)画像プレースフォルダーを入力として取り、そのトップに ReLu 活性化(関数)とともに全結合層のペアを、続いて出力ロジット(対数オッズ)を示す 10 ノードの線形層を構築します。

各層は、scope 内で作成された項目のプレフィックスとして作用するユニークな tf.name_scope の下で作成されます。

with tf.name_scope('hidden1') as scope:

定義されたスコープ内で、これらの層の個々に使用される weights(重み)と biases(バイアス)は希望する shape(形状)で tf.Variable インスタンス内に生成されます :

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 スコープの下で作成された時は、weights 変数にはユニークな名前が与えられ “hidden1/weights” となります。

各変数は生成の一部として initializer OP に与えられます。

この最も一般的なケースでは weights は tf.truncated_normal で初期化され、2-D テンソルの shape が与えられます。最初の次元は weights の接続元の層のユニット数を表し、2つめの次元は weights の接続先の層のユニット数を表します。
hidden1 と命名された最初の層では、次元は [IMAGE_PIXELS, hidden1_units] です。何故なら weights は画像入力を hidden1 層に接続しているからです。tf.truncated_normal initializer は与えられた平均値と標準偏差でランダム分布を生成します。

それから biases は全てゼロ値で始まることを保証するために tf.zeros で初期化されます。shape は単に接続先の層のユニット数です。

そしてグラフの3つの主要な OP — 隠れ層のための tf.matmul をラッピングした2つの tf.nn.relu OP とロジットのための1つの特別な tf.matmul OP — がそれぞれ順番に、入力プレースホルダーか前の層の出力テンソルに接続される、分離した tf.Variable インスタンスと共に作成されます。

hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)

hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)

logits = tf.matmul(hidden2, weights) + biases

最終的に、出力を含むロジット・テンソルが返されます。
訳注 : 通常はロジットは対数オッズのことです。

Loss(損失)

loss() 関数は必要な loss(損失) OP を追加することでグラフを更に構築します。

最初に、labels_placeholder からの値はワン・ホット (1-hot) 値のテンソルとしてエンコードされます。例えば、クラス識別子が ‘3’ であるならば値は次のように変換されます :
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

batch_size = tf.size(labels)
labels = tf.expand_dims(labels, 1)
indices = tf.expand_dims(tf.range(0, batch_size, 1), 1)
concated = tf.concat(1, [indices, labels])
onehot_labels = tf.sparse_to_dense(
    concated, tf.pack([batch_size, NUM_CLASSES]), 1.0, 0.0)

そして tf.nn.softmax_cross_entropy_with_logits OP が inference() からの出力ロジットと 1-hot ラベルを比較するために追加されます。

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits,
                                                        onehot_labels,
                                                        name='xentropy')

そして損失の総計としてバッチ次元(最初の次元)に渡る交差エントロピー値の平均を取るために tf.reduce_mean を 使用します。

loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')

[注意]
交差エントロピー (Cross-entropy) は情報理論からのアイデアです。これは、実際にどれがが真であるかを与えられるとして、ニューラルネットワークの予測を信じるにはどの程度悪いかを表現することを可能にします。
更なる情報は、ブログポスト Visual Information Theory を読んでください。

Training(訓練)

training() 関数は勾配降下法によって損失を最小化するために必要な OP を追加します。

最初に、loss() 関数からの loss テンソルを取りそしてそれを tf.scalar_summary に渡します。この OP は SummaryWriter(後述)とともに使用される時はイベントファイルに要約値を生成します。
この場合、要約が書き出されるたびに損失のスナップショット値を吐きます。

tf.scalar_summary(loss.op.name, loss)

次に、要求された学習率で勾配法を適用する責を負う tf.train.GradientDescentOptimizer をインスタンス化します。

optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)

そしてグローバルな学習ステップのためのカウンターを含む一つの変数を生成して、minimize() OP がシステムの訓練可能な weights(重み)の更新とグローバルステップの繰り上げの両方のために使用されます。

これは慣習的に train_op として知られ、(この OP は)一つの学習の完全なステップを引き起こすために TensorFlow セッションにより実行されなければなりません。(後述)

global_step = tf.Variable(0, name='global_step', trainable=False)
train_op = optimizer.minimize(loss, global_step=global_step)

学習 OP の出力を含むテンソルが返されます。

 

モデルを訓練する

ひとたびグラフが構築されれば、fully_connected_feed.py のユーザコードにより制御されたループの中で反復的に訓練され評価されます。

グラフ

run_training() 関数の冒頭は、全ての構築された OP はデフォルトのグローバルな tf.Graph インスタンスと関連づけらることを示す python コマンドです。

with tf.Graph().as_default():

tf.Graph はグループとして一緒に実行可能な OP のコレクションです。多くの TensorFlow の利用では一つのデフォルトのグラフに依拠することだけが必要でしょう。

複数のグラフを伴うより複雑な利用法も可能ですが、この簡単なチュートリアルの範囲を超えています。

セッション

全ての構築準備が完了し、全ての必要な OP が生成されたら、グラフを実行するために tf.Session が作成されます。

sess = tf.Session()

あるいは、スコープのために with ブロック内に Session が生成されます。

with tf.Session() as sess:

session への空パラメータは、このコードがデフォルトのローカル・セッションにアタッチする(あるいはもし未作成ならば作成する)ことを示しています。

セッションを作成したら直ちに、initialization OP で sess.run() を呼び出すことにより全ての tf.Variable インスタンスが初期化されます。

init = tf.initialize_all_variables()
sess.run(init)

sess.run() メソッドは、パラメータとして渡された OP に対応するグラフの完全な部分集合を実行します。この最初の呼び出しで、init OP は変数への initializer だけを含む tf.group です。グラフの残りはここでは実行されません; それは下記の学習ループで発生します。

訓練ループ

セッションで変数を初期化した後、学習が始められます。

ユーザコードはステップ毎に学習を制御し、そして有用な学習を行なうことが可能な最も単純なループは :

for step in xrange(max_steps):
    sess.run(train_op)

です。

けれども、このチュートリアルは、先に生成されたプレースホルダーに適合させるためにステップ毎の入力データスライスしなければならないという点で少しばかりより複雑です。

グラフに供給する

各ステップで、コードは feed 辞書を生成します。これはステップの学習をするサンプルのセットを含み、それらが表すプレースホルダー OP をキーとします。

fill_feed_dict() 関数では、与えられたデータセットに batch_size の次の画像とラベルのセットが問い合わせされます。そしてプレースホルダーにマッチするテンソルには次の画像とラベルを含むように設定されます。

images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size)

それから、プレースホルダーをキーとし、それを表す feed テンソルを値として持つ、python 辞書オブジェクトが生成されます。

feed_dict = {
    images_placeholder: images_feed,
    labels_placeholder: labels_feed,
}

これは学習のこのステップのための入力例を提供するために、sess.run() 関数の feed_dict パラメータに渡されます。

ステータスのチェック

コードは run 呼び出しで取得するための2つの値を指定します : [train_op, loss]

for step in xrange(FLAGS.max_steps):
    feed_dict = fill_feed_dict(data_sets.train,
                               images_placeholder,
                               labels_placeholder)
    _, loss_value = sess.run([train_op, loss],
                             feed_dict=feed_dict)

取得する2つの値があるので、sess.run() は2つの要素のタプルを返します。取得する値のリストの中の各テンソルは返されたタプルの中の numpy 配列に相当し、学習のこのステップにおけるそのテンソルの値が設定されています。train_op は出力値なしの OP ですから、返されたタプルの中の相当する要素は None であり、それゆえに棄てられます。しかし loss テンソルの値は学習中にモデルが発散 (diverge) した場合、NaN になるかもしれません。よって、これらの値は捕えてロギングします。

NaN なしに学習がきれいに走ると仮定すれば、学習ループはまた、ユーザに学習状況を知らせるために簡単なステータス・テキストを 100 ステップ毎に表示します。

if step % 100 == 0:
    print 'Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration)

ステータスの視覚化

TensorBoard で使用されるイベントファイルを出力するために、全ての要約(この場合は一つ)はグラフ構築フェイズで一つの OP に集められます。

summary_op = tf.merge_all_summaries()

そしてそれから、セッションが作成されると、tf.train.SummaryWriter はグラフ自身と要約の値の両方を含むイベントファイルを書くためにインスタンス化されます。

summary_writer = tf.train.SummaryWriter(FLAGS.train_dir,
                                        graph_def=sess.graph_def)

最終的に、summary_op が実行されて writer の add_summary() 関数に出力が渡されるたびにイベントファイルは新しい要約値で更新されます。

summary_str = sess.run(summary_op, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)

イベントファイルが書かかれた時、要約からの値を表示するために TensorBoard が学習フォルダに対して実行されます。

[注意]
Tensorboard をどのように構築して実行するかについての更なる情報は添付のチュートリアル Tensorboard: 学習を視覚化する を参照してください。

チェックポイントの保存

更なる学習や評価のために後でモデルを復元するために使用される、チェックポイント・ファイルを出力するためには tf.train.Saver をインスタンス化します。

saver = tf.train.Saver()

学習ループでは、チェックポイントファイルを学習ディレクトリに書くために、saver.save() メソッドが全ての学習可能な変数の現在値とともに定期的に呼び出されます。

saver.save(sess, FLAGS.train_dir, global_step=step)

先々どこか後のポイントで、モデル・パラメータをリロードするために saver.restore() メソッドを使うことにより学習を再開することもあり得ます。

saver.restore(sess, FLAGS.train_dir)
 

モデルを評価する

1000 ステップ毎に、コードは学習用とテスト用のデータセットの両方についてモデルの評価を試みます。学習、検証そしてテスト用のデータセットのために do_eval() 関数が3度呼ばれます。

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)

[注意]
より複雑な利用方法では通常は data_sets.test をハイパー・パラメータの主要な量のチューニングの後でのみチェックする目的で隔離しておく点に注意してください。しかし簡単で小さな MNIST 問題のために全てのデータに対して評価します。

評価 (Eval) グラフの構築

デフォルト・グラフをオープンする前に、テスト・データセットを掴むためにセットされたパラメータとともに get_data(train=False) 関数を呼び出すことによりテストデータが取得されるべきです。

test_all_images, test_all_labels = get_data(train=False)

学習ループに入る前に、loss() 関数と同様のロジット/ラベル・パラメータとともに mnist.py から evaluation() 関数を呼び出すことにより、評価 (Eval) OP が構築されているべきです。

eval_correct = mnist.evaluation(logits, labels_placeholder)

evaluation() 関数は、真のラベルがもっともそれらしい予測 K 個の中で見つかる場合、自動的に各モデルの出力を正しいとスコアできる tf.nn.in_top_k OP を単に生成します。今回の場合は、真のラベルの場合のみ予測が正しいと考えることにして K の値を 1 に設定します。

出力を評価する

そして与えられたデータセット上でモデルを評価するために feed_dict を埋めて eval_corrent OP に対して sess.run() を呼び出すループが作成できます。

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)

true_count 変数は in_top_k OP が正しいと決定した予測の全てを集計するだけです。ここから、正確性は単にサンプルの総数で除算することで計算されます。

precision = float(true_count) / float(num_examples)
print '  Num examples: %d  Num correct: %d  Precision @ 1: %0.02f' % (
    num_examples, true_count, precision)
 

以上

AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com