ホーム » TensorFlow » TensorFlow Eager Execution

TensorFlow Eager Execution

TensorFlow : Eager Execution (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 02/02/2018

* 本ページは、github の tensorflow/contrib/eager の guide.md – TensorFlow Eager Execution を翻訳した上で適宜、補足説明したものです:

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

 

概要

Eager execution は TensorFlow に演算を直ちに実行させる機能です : 後で実行される計算グラフの代わりに、具体的な値が返されます。

その結果、eager execution の有効化は以下を提供します :

  • GPU アクセラレーションと自動微分のためのサポートを持つ数値計算のための NumPy-ライクなライブラリ。
  • 機械学習の研究と実験のための柔軟なプラットフォーム。

【注意】
Eager execution は活発な開発下にあります。このガイドは alpha/preview リリースをウォークスルーします。特に、総ての TensorFlow API が eager execution を有効にした場合に動作するわけではありません、そして eager execution を使用することなしに定義されたモデルと比較して、幾つかのモデルの実行は遅くなるかもしれません、

 

Getting Started

TensorFlow がインストールされていれば、eager execution は単一の呼び出しで有効になります :

import tensorflow as tf

import tensorflow.contrib.eager as tfe

tfe.enable_eager_execution()

eager execution の有効は TensorFlow 関数がどのように振る舞うかを変更します (特に、Tensor オブジェクトは計算グラフのノードへのシンボリック・ハンドルである代わりに具体的な値を参照します)。
結果的に、eager execution はプログラムの最初で有効にされるべきで後になって同じプログラムで無効にすることはできません。

このガイドの残りのコード・サンプルでは eager execution が有効にされていることを仮定します。

 

数値計算のためのライブラリ

TensorFlow API の重要な断片は数値演算から成ります : 算術演算、行列演算、線形代数演算, etc。

eager execution が有効であるとき、これらの演算は Numpy ndarray のように Tensor オブジェクトとして多次元配列を消費して返します。例えば :

# Multiply two 2x2 matrices
x = tf.matmul([[1, 2],
               [3, 4]],
              [[4, 5],
               [6, 7]])
# Add one to each element
# (tf.add supports broadcasting)
y = tf.add(x, 1)

# Create a random random 5x3 matrix
z = tf.random_uniform([5, 3])

print(x)
print(y)
print(z)

出力 :

tf.Tensor(
[[16 19]
 [36 43]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[17 20]
 [37 44]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[ 0.25058532  0.0929395   0.54113817]
 [ 0.3108716   0.93350542  0.84909797]
 [ 0.53081679  0.12788558  0.01767385]
 [ 0.29725885  0.33540785  0.83588314]
 [ 0.38877153  0.39720535  0.78914213]], shape=(5, 3), dtype=float32)

便利のために、これらの演算はまた Tensor オブジェクトのオーバーロードする演算子を通しても引き起こされます。例えば、+ 演算子は tf.add と同値で、- は tf.subtact、* は tf.multiply, 等 :

x = (tf.ones([1], dtype=tf.float32) + 1) * 2 - 1
print(x)

出力 :

tf.Tensor([ 3.], shape=(1,), dtype=float32)

 

Numpy への/からの変換

上述の演算子は (数字のリストのような) Python オブジェクトと NumPy 配列を自動的に Tensor オブジェクトに変換します。Tensor オブジェクトはまた numpy 演算により NumPy 配列としても使用されます。

import numpy as np

x = tf.add(1, 1)                     # tf.Tensor with a value of 2
y = tf.add(np.array(1), np.array(1)) # tf.Tensor with a value of 2
z = np.multiply(x, y)                # numpy.int64 with a value of 4

代わりに、次の例で示されるように、それらは tf.constant を使用して明示的に変換できます。

逆に、Tensor オブジェクトの numpy() メソッドをその NumPy ndarray 値を得るために呼び出すことができます。例えば :

import numpy as np

np_x = np.array(2., dtype=np.float32)
x = tf.constant(np_x)

py_y = 3.
y = tf.constant(py_y)

z = x + y + 1

print(z)
print(z.numpy())

出力 :

tf.Tensor(6.0, shape=(), dtype=float32)
6.0

 

GPU アクセラレーション

多くの TensorFlow 演算は GPU アクセラレーションをサポートします。eager execution が有効であるとき、計算は自動的には GPU にオフロードされません。代わりに、GPU が使用されるべきときには明示的に指定しなければなりません。

これを行なうための最も単純な方法は with tf.device(‘/gpu:0’) ブロックで貴方の計算を囲むことです。また興味深いのは tfe.num_gpus() でこれは利用可能な GPU の数を返します。

例えば、CPU 上で2つの 1000×1000 行列を乗算するための時間を計測するスニペットを考えます :

import time

def measure(x):
  # The very first time a GPU is used by TensorFlow, it is initialized.
  # So exclude the first run from timing.
  tf.matmul(x, x)

  start = time.time()
  for i in range(10):
    tf.matmul(x, x)
  end = time.time()

  return "Took %s seconds to multiply a %s matrix by itself 10 times" % (end - start, x.shape)

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: %s" % measure(tf.random_normal([1000, 1000])))

# If a GPU is available, run on GPU:
if tfe.num_gpus() > 0:
  with tf.device("/gpu:0"):
    print("GPU: %s" % measure(tf.random_normal([1000, 1000])))

出力 (正確な数はハードウェアの特性に依存します) :

 
CPU: Took 0.145531892776 seconds to multiply a (1000, 1000) matrix by itself 10 times
GPU: Took 0.000458955764771 seconds to multiply a (1000, 1000) matrix by itself 10 times

あるいは、Tensor オブジェクト上のメソッドは Tensor を異なるデバイスに明示的にコピーするために使用できます。演算は典型的には入力が置かれたデバイス上で実行されます。例えば :

x = tf.random_normal([10, 10])

x_gpu0 = x.gpu()
x_cpu = x.cpu()

_ = tf.matmul(x_cpu, x_cpu)  # Runs on CPU
_ = tf.matmul(x_gpu0, x_gpu0)  # Runs on GPU:0

if tfe.num_gpus() > 1:
  x_gpu1 = x.gpu(1)
  _ = tf.matmul(x_gpu1, x_gpu1)  # Runs on GPU:1

 

自動微分

自動微分は多くの機械学習アルゴリズムを実装するときに非常に有用です (e.g. ニューラルネットワークを訓練するための backpropagation)。この目的のために、TensorFlow eager execution は自動微分のために autograd-スタイル API を提供します。特に、関数 :

  • tfe.gradients_function(f): Python 関数を返します、これは Python 関数 f のその引数に関して導関数を計算します。f はスカラー値を返さなければなりません。返された関数が起動されたとき、それは Tensor オブジェクトのリストを返します (f の各引数のために一つの要素)。
  • tfe.value_and_gradients_function(f): tfe.gradients_function と類似してます、返された関数が起動されたとき、それは f のその引数に関する導関数のリストに加えて f の値を返す点を除いてです。

これらの関数は自然に高次微分にもまた適用されます :

def f(x):
  return tf.multiply(x, x)  # Or x * x
assert 9 == f(3.).numpy()

df = tfe.gradients_function(f)
assert 6 == df(3.)[0].numpy()

# Second order deriviative.
d2f = tfe.gradients_function(lambda x: df(x)[0])
assert 2 == d2f(3.)[0].numpy()

# Third order derivative.
d3f = tfe.gradients_function(lambda x : d2f(x)[0])
assert 0 == d3f(3.)[0].numpy()

これらの関数はモデルを訓練するために使用できます。例えば、次の単純な線形回帰モデルを考えます :

def prediction(input, weight, bias):
  return input * weight + bias

# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 1000
training_inputs = tf.random_normal([NUM_EXAMPLES])
noise = tf.random_normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# A loss function: Mean-squared error
def loss(weight, bias):
  error = prediction(training_inputs, weight, bias) - training_outputs
  return tf.reduce_mean(tf.square(error))

# Function that returns the derivative of loss with respect to
# weight and bias
grad = tfe.gradients_function(loss)

# Train for 200 steps (starting from some random choice for W and B, on the same
# batch of data).
W = 5.
B = 10.
learning_rate = 0.01
print("Initial loss: %f" % loss(W, B).numpy())
for i in range(200):
  (dW, dB) = grad(W, B)
  W -= dW * learning_rate
  B -= dB * learning_rate
  if i % 20 == 0:
    print("Loss at step %d: %f" % (i, loss(W, B).numpy()))
print("Final loss: %f" % loss(W, B).numpy())
print("W, B = %f, %f" % (W.numpy(), B.numpy()))

出力: (正確な数値はノイズのランダムネスに依存して様々かもしれません。)

Initial loss: 66.730003
Loss at step 0: 64.200096
Loss at step 20: 29.872814
Loss at step 40: 14.233772
Loss at step 60: 7.090570
Loss at step 80: 3.819887
Loss at step 100: 2.318821
Loss at step 120: 1.628385
Loss at step 140: 1.310142
Loss at step 160: 1.163167
Loss at step 180: 1.095162
Final loss: 1.064711
W, B = 3.094944, 2.161383

GPU を利用するためには、with tf.device(“/gpu:0”): ブロック内に上のコードを置きます。

 

勾配をカスタマイズする

演算、または関数のためにカスタム勾配を定義することを望むかもしれません。これは複数の理由で有用かもしれません、演算のシークエンスのためにより効率的あるいはより数値的安定な勾配を提供することを含みます。

例えば、関数 log(1 + e^x) を考えます、これは交差エントロピーと log 尤度の計算で一般に発生します。

def log1pexp(x):
  return tf.log(1 + tf.exp(x))
grad_log1pexp = tfe.gradients_function(log1pexp)

# Works fine at x = 0.
assert 0.5 == float(grad_log1pexp(0.)[0])

# Returns a `nan` at x = 100 due to numerical instability.
import math
assert math.isnan(float(grad_log1pexp(100.)[0]))

上の関数のためにカスタム勾配を定義できます、これは勾配式を解析的に単純化します。

@tfe.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.log(1 + e), grad
grad_log1pexp = tfe.gradients_function(log1pexp)

# Works as before at x = 0.
assert 0.5 == float(grad_log1pexp(0.)[0])

# But now works at x = 100 as well.
assert 1.0 == float(grad_log1pexp(100.)[0])

勾配関数の実装が forward パスの間に計算された式 (tf.exp(x)) どのように再利用するかについてもまた注目してください、このように冗長な計算を回避することにより勾配計算をより効率的にします。

 

モデルを構築して訓練する

実際に、貴方の計算は (導関数を計算することにより) 最適化されるべき多くのパラメータを持つかもしれません。それらを再利用可能なクラス/オブジェクトにカプセル化することは、多くの引数を持つ単一のトップレベル関数を書くことよりも、コードをフォローすることをより容易にします。

実際に、eager execution は tf.layers モジュールで Keras-スタイル “層” クラスの利用を奨励しています。

更に、tf.train.Optimizer 実装のそれらのように、パラメータ更新を計算するためにより洗練されたテクニックを適用することを望むかもしれません。

次のセクションでは、eager execution が有効化された環境で訓練可能な TensorFlow グラフを構築するために使用された同じ Optimizer と層 API を使用してウォークスルーします。

 

Variable と Optimizer

tfe.Variable オブジェクトは、訓練時にアクセス可能な可変な Tensor 値をストアし、自動微分をより容易にします。特に、モデルのパラメータは Python クラスで変数としてカプセル化されます。

先に導入された tfe.gradients_function(f) は f の導関数をその引数について計算します。けれども、それは f の引数となる興味対象である総てのパラメータを必要とします、これは f が巨大な数の訓練可能なパラメータに依存するとき扱いにくいものとなります。

tfe.implicit_gradients は幾つかの有用な特性を持つ代わりとなる関数です :

  • それは f により使用される tfe.Variables の総てに関して f の導関数を計算します。
  • 返された関数が起動されるとき、(勾配値, Variable オブジェクトの) タプルのリストを返します。

tfe.implicit_gradients の使用と一緒にモデルパラメータを Variable オブジェクトとして表わすことは、典型的にはより良いカプセル化になります。例えば、上で記述された線形回帰モデルは次のクラスへと書くことができます :

class Model(object):
  def __init__(self):
    self.W = tfe.Variable(5., name='weight')
    self.B = tfe.Variable(10., name='bias')

  def predict(self, inputs):
    return inputs * self.W + self.B


# The loss function to be optimized
def loss(model, inputs, targets):
  error = model.predict(inputs) - targets
  return tf.reduce_mean(tf.square(error))

# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 1000
training_inputs = tf.random_normal([NUM_EXAMPLES])
noise = tf.random_normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# Define:
# 1. A model
# 2. Derivatives of a loss function with respect to model parameters
# 3. A strategy for updating the variables based on the derivatives
model = Model()
grad = tfe.implicit_gradients(loss)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

# The training loop
print("Initial loss: %f" %
      loss(model, training_inputs, training_outputs).numpy())
for i in range(201):
  optimizer.apply_gradients(grad(model, training_inputs, training_outputs))
  if i % 20 == 0:
    print("Loss at step %d: %f" %
          (i, loss(model, training_inputs, training_outputs).numpy()))
print("Final loss: %f" % loss(model, training_inputs, training_outputs).numpy())
print("W, B = %s, %s" % (model.W.numpy(), model.B.numpy()))

出力:

Initial loss: 69.693184
Loss at step 0: 66.987854
Loss at step 20: 30.553387
Loss at step 40: 14.250237
Loss at step 60: 6.955020
Loss at step 80: 3.690550
Loss at step 100: 2.229739
Loss at step 120: 1.576032
Loss at step 140: 1.283496
Loss at step 160: 1.152584
Loss at step 180: 1.093999
Final loss: 1.067780
W, B = 3.0114281, 2.0865183

implicit_gradients の使用はモデルの訓練可能なパラメータ総てを損失関数への引数として提供する必要性を回避します。

 

Keras と層 API を使用する

Keras はモデル構造を定義するためのポピュラーな API です。tf.keras.layers モジュールはモデルのためのブロックを構築するセットを提供し tf.layers モジュールの tf.layers.Layer サブクラスを使用して実装されています。TensorFlow の eager execution 特徴を使用するときこれらの同じビルディング・ブロックの利用を推奨します。例えば、同じ線形回帰モデルは tf.layers.Dense を使用して構築されます :

class Model(object):
  def __init__(self):
    self.layer = tf.layers.Dense(1)

  def predict(self, inputs):
    return self.layer(inputs)

tf.layers API はより洗練されたモデルを定義することをより使いやすくします。例えば、次は MNIST モデルを訓練します :

class MNISTModel(object):
  def __init__(self, data_format):
    # 'channels_first' is typically faster on GPUs
    # while 'channels_last' is typically faster on CPUs.
    # See: https://www.tensorflow.org/performance/performance_guide#data_formats
    if data_format == 'channels_first':
      self._input_shape = [-1, 1, 28, 28]
    else:
      self._input_shape = [-1, 28, 28, 1]
    self.conv1 = tf.layers.Conv2D(32, 5,
                                  padding='same',
                                  activation=tf.nn.relu,
                                  data_format=data_format)
    self.max_pool2d = tf.layers.MaxPooling2D(
        (2, 2), (2, 2), padding='same', data_format=data_format)
    self.conv2 = tf.layers.Conv2D(64, 5,
                                  padding='same',
                                  activation=tf.nn.relu,
                                  data_format=data_format)
    self.dense1 = tf.layers.Dense(1024, activation=tf.nn.relu)
    self.dropout = tf.layers.Dropout(0.5)
    self.dense2 = tf.layers.Dense(10)

  def predict(self, inputs):
    x = tf.reshape(inputs, self._input_shape)
    x = self.max_pool2d(self.conv1(x))
    x = self.max_pool2d(self.conv2(x))
    x = tf.layers.flatten(x)
    x = self.dropout(self.dense1(x))
    return self.dense2(x)

def loss(model, inputs, targets):
  return tf.reduce_mean(
      tf.nn.softmax_cross_entropy_with_logits(
          logits=model.predict(inputs), labels=targets))


# Load the training and validation data
from tensorflow.examples.tutorials.mnist import input_data
data = input_data.read_data_sets("./mnist_data", one_hot=True)

# Train
device = "gpu:0" if tfe.num_gpus() else "cpu:0"
model = MNISTModel('channels_first' if tfe.num_gpus() else 'channels_last')
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4)
grad = tfe.implicit_gradients(loss)
for i in range(20001):
  with tf.device(device):
    (inputs, targets) = data.train.next_batch(50)
    optimizer.apply_gradients(grad(model, inputs, targets))
    if i % 100 == 0:
      print("Step %d: Loss on training set : %f" %
            (i, loss(model, inputs, targets).numpy()))
print("Loss on test set: %f" % loss(model, data.test.images, data.test.labels).numpy())

より完全なサンプルについては、tensorflow/contrib/eager/python/examples/mnist.py を見てください。

 

訓練 variables をチェックポイントする

TensorFlow Variables (tfe.Variable) は貴方のモデルの共有される、永続的な状態を表現する方法を提供します。tfe.Saver クラス (これは tf.train.Saver クラスの thin ラッパーです) はチェックポイントへ/から variables をセーブしてリストアする方法を提供します。

例えば :

# Create variables.
x = tfe.Variable(10., name='x')
y = tfe.Variable(5., name='y')

# Create a Saver.
saver = tfe.Saver([x, y])

# Assign new values to the variables and save.
x.assign(2.)
saver.save('/tmp/ckpt')

# Change the variable after saving.
x.assign(11.)
assert 16. == (x + y).numpy()  # 11 + 5

# Restore the values in the checkpoint.
saver.restore('/tmp/ckpt')

assert 7. == (x + y).numpy()  # 2 + 5

 

tfe.Network

貴方は、上で定義された MNISTModel クラスのように、クラスを使用してモデルを体系化することをしばしば望むかもしれません。tfe.Network クラスから継承することを推奨します、何故ならばそれは総てのモデル variables を追跡するような便利さとチェックポイントをセーブしてリストアするメソッドを提供するからです。

tfe.Network のサブクラスは self.track_layer() への呼び出しを使用して ( tf.layers, または Keras 層内のクラスのように) 層を登録してそして call() の実装内で計算を定義するかもしれません。

tf.layers.Layer オブジェクトは、最初の入力に出会うとき variables を遅延して作成することに注意してください。

例えば、次の 2 層ニューラルネットワークを考えます :

class TwoLayerNet(tfe.Network):
  def __init__(self):
    super(TwoLayerNet, self).__init__()
    self.layer1 = self.track_layer(
      tf.layers.Dense(2, activation=tf.nn.relu, use_bias=False))
    self.layer2 = self.track_layer(tf.layers.Dense(3, use_bias=False))

  def call(self, x):
    return self.layer2(self.layer1(x))

net = TwoLayerNet()

# No variables created yet
assert 0 == len(net.variables)

# They are created on first input:
inp = tf.constant([[1.]])

# Since input is a 1x1 matrix, net.l1 has 2 units and net.l2 has 3 units,
# the output is the product of a 1x1 matrix with a 1x2 matrix with a 2x3
# matrix.
assert [1, 3] == net(inp).shape.as_list()  # Invoke net; get output shape.
assert 1 == len(net.layer1.variables)
assert 1 == len(net.layer2.variables)
assert 2 == len(net.variables)  # weights for each layer.
assert [1, 2] == net.variables[0].shape.as_list()  # weights of layer1.
assert [2, 3] == net.variables[1].shape.as_list()  # weights of layer2.

tfe.Network クラスはそれ自身が tf.layers.Layer のサブクラスです。これは tfe.Network のインスタンスが他のネットワークに埋め込まれることを可能にします。例えば :

class ThreeLayerNet(tfe.Network):
  def __init__(self):
    super(ThreeLayerNet, self).__init__()
    self.a = self.track_layer(TwoLayerNet())
    self.b = self.track_layer(tf.layers.Dense(4, use_bias=False))

  def call(self, x):
    return self.b(self.a(x))

net = ThreeLayerNet()

assert [1, 4] == net(inp).shape.as_list()
assert 3 == len(net.variables)
assert [1, 2] == net.variables[0].shape.as_list()
assert [2, 3] == net.variables[1].shape.as_list()
assert [3, 4] == net.variables[2].shape.as_list()

tensorflow/contrib/eager/python/examples の更なるサンプルを見てください。

tfe.restore_variables_on_create と組み合わせた tfe.Saver はひとたびチェックポイントが作成されればプログラムの変更なしにチェックポイントをセーブしてロードする便利な方法を提供します。例えば、ネットワークの出力のための目的を設定して、optimizer とチェックポイントのための場所を選択することができます :

objective = tf.constant([[2., 3., 4., 5.]])
optimizer = tf.train.AdamOptimizer(0.01)
checkpoint_directory = '/tmp/tfe_example'
checkpoint_prefix = os.path.join(checkpoint_directory, 'ckpt')
net = ThreeLayerNet()

variables はまだ作成されていないことに注意しましょう。もし存在すれば、チェックポイントからそれらがリストアされることを望みます、そしてそれらを tfe.restore_variables_on_create コンテキスト・マネージャ内に作成します。それから訓練は訓練を開始しても以前のチェックポイントから再開しても同じです :

with tfe.restore_variables_on_create(
    tf.train.latest_checkpoint(checkpoint_directory)):
  global_step = tf.train.get_or_create_global_step()
  for _ in range(100):
    loss_fn = lambda: tf.norm(net(inp) - objective)
    optimizer.minimize(loss_fn, global_step=global_step)
    if tf.equal(global_step % 20, 0):
      print("Step %d, output %s" % (global_step.numpy(),
                                    net(inp).numpy()))
      all_variables = (
          net.variables
          + optimizer.variables()
          + [global_step])
      # Save the checkpoint.
      tfe.Saver(all_variables).save(checkpoint_prefix, global_step=global_step)

最初にそれが実行されるときは、ネットワーク variables はランダムに初期化されます。それから出力は設定した目的に適合するように訓練されます :

Step 20, output [[ 0.03575622  0.29863232  0.03474367  0.24735749]]
Step 40, output [[ 0.40646029  0.9856872   0.46851286  0.95358551]]
Step 60, output [[ 1.74541104  2.800704    1.79055595  2.74783421]]
Step 80, output [[ 2.14977384  3.44340849  3.96120024  5.16242075]]
Step 100, output [[ 1.99943113  3.02364397  3.93500996  4.9610076 ]]

続く反復では、variables は最新のチェックポイントから読まれた値で初期化されます。同じコードを再度実行すれば、中止したところから続行されます :

Step 120, output [[ 1.99234128  3.0271616   3.98732996  4.96401167]]
Step 140, output [[ 2.00133467  3.01270437  4.00616646  5.00406504]]
Step 160, output [[ 1.99647415  2.9956708   3.99064088  4.99632359]]
Step 180, output [[ 2.00699997  3.00904822  4.00706148  5.01193142]]
Step 200, output [[ 1.98334622  2.98249531  3.97375059  4.97123432]]

 

Summaries, メトリクスと TensorBoard

TensorBoard はモデル訓練プロセスを理解し、デバッグし、そして最適化するためにポピュラーなツールです。TensorBoard から提供される可視化から恩恵を受けるためには、プログラムの実行の進行の間に summary events が書かれる必要があります。グラフ構築の間に tf.summary 演算子を含む多くの TensorFlow プログラムを見い出すでしょう。

tf.summary 演算は eager execution と互換ではありませんが、tf.contrib.summary に同値な代替があり、これは eager execution とグラフ構築の両者で互換です。

モデル構築の間に tf.contrib.summary.scalar のような summary 演算を単純に挿入します。これらの演算は、summary writer が有効で writing policy が設定されていない限りはデフォルトでは何もしません。

例えば、100 global ステップ毎に一度 summaries を記録するためには、以下を使用します :

tf.train.get_or_create_global_step()  # Ensuring the global step variable exists
writer = tf.contrib.summary.create_file_writer(logdir)

for _ in range(iterations):
  with writer.as_default():
    with tf.contrib.summary.record_summaries_every_n_global_steps(100):
      # your model code goes here
      tf.contrib.summary.scalar('loss', loss)
      # ...

tf.contrib.summary を使用する完全なモデルのためには tensorflow/contrib/eager/python/examples/mnist の完全な mnist サンプルを見てください。

summaries と同様に、tf.metrics のメトリクスは現在 eager execution と互換ではありません。代わりに tfe.metrics パッケージでオブジェクト指向メトリクスを提供します、これはグラフ構築ともまた互換です。

tfe.metrics.Mean と tfe.Metrics.Accuracy のような、tfe.metrics のメトリクス総ては直感的なオブジェクト指向インターフェイスを実装しています。tfe.metrics.Mean メトリックをどのように使用するかのサンプルがここにあります :

# Metrics are objects, which can be created and destroyed.
my_mean = tfe.metrics.Mean(name='my_mean')
# While a metric is active, you can call it as a function to accumulate into its
# internal state.
my_mean(0.0)
my_mean(10.0)
# Once you've finished updating the metric, you can get its result. In this case
# a simple average over all the calls to it. If a summary writer is active the
# metric will write the appropriate summaries using the metric name.
assert 5.0 == my_mean.result().numpy()

評価のためのメトリクスを使用するモデルの完全なサンプルのためには、tensorflow/contrib/eager/python/examples/mnist の mnist サンプルを見てください。

 

入力パイプライン

上の議論は貴方のモデルで実行される計算回りに中心が置かれていました。tf.data モジュールは単純で、再利用可能なピースから複雑な入力パイプラインを構築する API を提供します。

TensorFlow グラフを構築するとき tf.data.Dataset オブジェクトを構築することに精通していれば、eager execution が有効であるとき同じ API 呼び出しが使用されます。けれども、データセットの要素に渡る反復プロセスは eager execution とグラフ構築の間では異なります。eager execution が有効であるとき、Programmer’s Guiide の make_one_shot_iterator() と get_next() を使用する iterator 作成上の議論は当てはまりません。代わりに、より Pythonic な Iterator クラスが利用可能です。

例えば :

# Create a source Dataset from in-memory numpy arrays.
# For reading from files on disk, you may want to use other Dataset classes
# like the TextLineDataset or the TFRecordDataset.
dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Apply transformations, shuffling, batching etc.
dataset = dataset.map(tf.square).shuffle(2).batch(2)

# Use tfe.Iterator to iterate over the dataset.
for x in tfe.Iterator(dataset):
  print(x)

出力 :

tf.Tensor([4 9], shape=(2,), dtype=int32)
tf.Tensor([16 25], shape=(2,), dtype=int32)
tf.Tensor([36  1], shape=(2,), dtype=int32)

 

グラフとの相互運用

Eager execution は Python でのモデル開発プロセスを改善します ; けれども、それは最初期段階にありますので、モデルをプロダクションで配備するとき (TensorFlow グラフでは利用可能な) 望ましい幾つかの特徴をまだサポートしていません。特に、分散訓練、(他のプログラミング言語、TensorFlow serving そしてモバイル・アプリケーションへの) モデルのエクスポート、そして (TensorFlow dataflow グラフに適用される) 各種のメモリと計算最適化を eager execution はまだサポートしていません。

そうは言っても、モデルを構築するために使用される API は eagerly に実行されてもグラフを構築しても正確に同じです。これは貴方のモデルを eager execution を有効にして反復的に開発可能でそして後で必要であれば、モデルを計算グラフとして表現する恩恵を収穫するために同じコードを利用できることを意味しています。

例えば、mnist.py は eagerly に実行されるモデルを定義します。その同じコードが mnist_graph_test.py でグラフを構築して実行するために使用されます。

examples ディレクトリ の他のモデルもまたこれを示します。

幾つかの違いは注目に値します :

  • eager execution が有効であるとき tf.placeholder や tf.Session の概念はありません。
  • tf.Tensor.name, tf.Tensor.op, tf.Tensor.inputs のような tf.Tensor オブジェクト上の多くのプロパティは eager execution が有効であるとき意味がなく、そしてそれらの使用は AttributeError を上げるべきです。
  • グラフ構築で tfe.implicit_gradients を使用するためには、variables は tf.get_variable() または tf.variable_scope() に提供される [use_resource=True] で作成されなければなりません。
  • (関数型スタイル tf.layers.dense, tf.layers.conv2d のような) 幾つかの API 呼び出しは eager execution と互換ではありません。そのようなメソッドの使用は代替 (e.g., tf.layers.Dense と tf.layers.Conv2D クラス) を示すエラーを上げるべきです。

 
以上



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