第3回 TensorFlow 基礎から最新APIまで (1/4)

技術特集

1_tensorflow_keras1_tit

tit_tensorflow_keras

第3回はTensorFlowの基礎を確認したうえで、最新の高レベルAPIを利用したディープラーニングの実装法をご紹介します。

記事内で必要に応じてPythonのコードを示すことがありますが、Python自体の機能や構文に関する解説は割愛させていただきますのでご了承ください。
なお、この記事にて掲載しているコードはすべてMITライセンスのもと利用を許諾するものとします。

TensorFlow, the TensorFlow logo and any related marks are trademarks of Google Inc.
この記事のTensorFlowロゴ画像を含む図は、CC-BY 3.0ライセンスのもと利用許諾されたTensorFlowの派生物です。

1) TensorFlowの基礎

TensorFlowはGoogle主導で開発されているOSSです。
「AI用ライブラリ」「ディープラーニング用ライブラリ」のように呼ばれることもありますが、
つくりとしては汎用的な数値計算基盤のうえに機械学習やディープラーニング関連の機能が豊富に搭載されているというイメージになっています。

TensorFlowの名前の由来となっているTensor(=テンソル)は数学の用語で、多次元配列を用いて表現できるデータ構造を示します。
TensorFlowを触るうえでは、テンソル ≒ n次元配列と理解しておけば充分です。

この節では、TensorFlowの数値計算基盤としての仕組みについてご紹介します。
能書きはいいからディープラーニングが見たい!という方は次の節までスキップしていただいても良いと思います。

インストール

とにかくまずはTensorFlowを使ってみましょう!
とにかく動けばよいというのであれば、pipコマンド一発でインストールすることができます。

$ pip install tensorflow

(GPUを使いたい場合はインストール対象をtensorflow-gpuにする必要があり、その他追加のシステム条件や手順が必要となります。詳しくは公式サイトをご参照ください)

1 + 2 = 3

以下のPythonスクリプトでは、TensorFlowで1 + 2 = 3を計算しています。

import tensorflow as tf
 
# 計算グラフの定義
x = tf.placeholder(tf.int32, shape=())
two = tf.constant(2)
x_plus_two = x + two
 
# 計算の実行
with tf.Session() as session:
    result_value = session.run(x_plus_two, {x: 1})
 
# 結果出力
print(result_value)
# => 3

「計算グラフの定義」部分では、

  • 任意の整数を指定できるx
  • 固定値2をもつtwo
  • xとtwoを足した値x_plus_two

の3つを定義しています。tf.placeholderは後で任意の値を指定する変数の定義を、tf.constantはその名の通り定数の定義を行います。
これらの値は全てTensorというクラスで表現されます。
実際に入る値としては1つの数字からなるスカラー値ですが、「0次元の配列で表現される値」と解釈すればテンソルと見なすこともできるわけです。

次に「計算の実行」部分においてxを1とした場合にx_plus_twoがどのような値をとるかを計算しています。
このように「まず計算の流れを定義し、その後求めたい値を指定して計算する」というスタイルになっているのがTensorFlowの特色です。

そうは言っても、普通にプログラミングをする場合にも「まずクラスや関数を定義し、その後それを利用してメインの処理を実装する」という手順で実行するかと思います。
たとえば上記の計算はxが引数でx_plus_twoが戻り値の関数を作るのに似ています。
TensorFlowの「計算の流れの定義」がクラスや関数の定義と少し違うのは、TensorFlowの計算は必ずSessionオブジェクトを通して行われるということです。

Sessionとは?

Sessionの機能は主に以下の2つです:

  • TensorFlowの計算を実行する
  • TensorFlowの計算における様々な状態を保持する
計算実行の主体としてのSession
uchideki_3_session_1

この図は、2を足す計算の例を模式的に表したものです。起こることを時系列で並べると、

  1. x_plus_twoの値の計算を要求
  2. x_plus_twoがxとtwoを足したものということを確認
  3. 入力値としてxの中身が1であることを確認
  4. 1 + 2を計算し、結果の3を出力

というイメージになります。
仮にxの値が未指定であった場合、計算結果を導くことができませんのでエラーとなります。

状態を保持する器としてのSession

「様々な状態の保持」に関する例として下記のコードを用いて考えます。

import tensorflow as tf
 
# 計算グラフの定義
x = tf.placeholder(tf.int32, shape=())
accum_var = tf.Variable(0) # accum_varの初期値は0
 
# accum_varの値にxを足して保持する。accumでは足した後の値を取得できる
accum = tf.assign(accum_var, x + accum_var)
 
# 計算の実行
with tf.Session() as session:
    session.run(tf.global_variables_initializer())
    print(session.run(accum, {x: 1}))
    # => 1
    print(session.run(accum, {x: 1}))
    # => 2
    print(session.run(accum, {x: 2}))
    # => 4
    print(session.run(accum, {x: 2}))
    # => 6
 

tf.Variableは、セットした値がSessionの中に保持され、次回以降の計算にも使用される変数を定義します。
xの定義に使用しているplaceholderとVariableはどちらも変数ではありますが、placeholderの値は毎回使い捨てでSessionの中に保存されないという大きな違いがあります。

2を足す計算の例は入力値が同じであれば出力値も同じであったのに対し、今回は入力の累積値が状態として保持され、同じ入力値に対しても異なる値が出力されます。
この処理を模式的に表したのが下の図です。

uchideki_3_session_2

入力の累積値accum_varの中身がSessionの中に保持されており、入力があるごとにその値が更新されていくイメージです。
tf.assignは、第1引数で指定したVariableに第2引数で指定した値をセットしたうえで、第2引数の値を返す処理です。

Variableと機械学習

Variableが想定する主な用途は、ディープラーニングやその他の機械学習におけるモデルのパラメータの保持です。

例えばあるデータの集合を機械学習してy=ax+bという1次関数に落とし込む場合、
xとyの正しい組み合わせを複数用意して、このモデルのパラメータである傾きaと切片bを調整していくということをやります。
具体的には、xの値からax+bの値を計算し、あるべきyの値との誤差を計算したうえで、誤差が小さくなるように傾きaと切片bの値を更新します。
また学習が終われば傾きaと切片bの値は動かさずに定数のように扱います。

uchideki_3_session_3

このように、常にどんな値が来るかわからないxと違い、学習モデルのパラメータであるaおよびbには「学習時には変化させたいが学習が終わったら与えずとも保持しておいて欲しい」という性質があります。
この性質の違いが、毎回使い捨てのplaceholderと、変化はするが保持もされるVariableの役割の違いに表れているのです。

Variableの初期化

機械学習をまっさらな状態からはじめる場合はVariableは初期値のままでよいのですが、学習済みモデルを利用したい場合や、一度中断した学習処理を再開するような場合には、ファイルに保存しておいたモデルの内部状態をVariableに展開する必要があります。

どちらにしても、新しくSessionを作った場合まずVariableを初期化する必要があります。
上記のコードで利用しているtf.global_variables_initializer()はすべてのVariableをまっさらな状態で初期化する処理です。