ホーム » TensorFlow Eager Execution

TensorFlow Eager Execution」カテゴリーアーカイブ

ClassCat® Eager-Brains : 画像処理 :- 電子顕微鏡写真のセグメンテーション

作成者 :(株)クラスキャット セールスインフォメーション
作成日 : 05/04/2019

 

ClassCat® Eager-Brains とは

「ClassCat® Eager-Brains」はクラスキャットが提供する人工知能コレクションです。
深層学習フレームワークのデファクトスタンダードである TensorFlow の新実行モード Eager Execution に対応しています。[詳細]

「ClassCat® Eager-Brains」で提供される人工知能はクラスキャットが検証の上で仕様を公開致しますので、ユーザ企業は様々なタスクに対応する人工知能コレクションの中から要件に適合する人工知能を選択することが可能です。カスタマイズや再調整から導入支援までワンストップなサポートサービスも併せて提供致します。

本ページでは人工知能の画像処理の例として 電子顕微鏡写真のセグメンテーション タスクへの応用例を紹介致します。

 

 

画像処理 :- 電子顕微鏡写真のセグメンテーション

セマンティック・セグメンテーションとは

セマンティック・セグメンテーションは簡単に言えば、画像の各ピクセルをクラス分類するタスクです。
風景写真のように物体オブジェクトが分離しやすい画像では (表面的には) 物体検出とそれほど違わない結果を得ますが、今回取り上げるような生物医学的なタスクではセマンティック・セグメンテーションが目的に良く適合することが多々あります。

 

データセット

次の電子顕微鏡写真のデータセットを題材とします :

訓練データは、ショウジョウバエ 1 齢幼虫の腹部神経索 (VNC, ventral nerve cord) の serial section 透過電子顕微鏡 (ssTEM) データセットからの 30 セクションのセットです。提供される二値ラベルは、セグメントされた物体のピクセルのために白、残りのピクセル (殆どは膜組織に相当) のために黒で与えられます。

以下は訓練データセットのサンプルで、左側が電子顕微鏡写真で右側が正解ラベルです :

 

U-Net

セマンティック・セグメンテーションのために数多くの人工知能が考案されています。

FCN (Fully Convolutional Network), U-Net, SegNet, PSPNet 等がポピュラーですが、今回はその中から U-Net と呼称される人工知能を使用します。U-Net はオートエンコーダを改良したもので、その評価尺度 (メトリクス) としては集合の類似度を表わす Dice係数 (= Coefficient) が良く利用されます。

以下は U-Net 訓練時の損失と精度のグラフです :

 

 

予測

以下は訓練後の U-Net の適用結果です。
評価尺度として Dice 係数だけでなく、通常の二値分類も比較のために利用しました。

左側がテスト画像、中央が二値分類により訓練した U-Net による予測結果、そして右側が Dice 係数による U-Net の予測結果です :

 

 
このデータセットではテストデータに対する正解は提供されていませんが、目視が容易ですのでどちらも概ね正しく予測されていることが分かります。また、目視した限りでは二値分類でも Dice 係数でも明確な優劣はついていません。

他にも幾つか予想結果を掲載しておきます :

 

 

以上






TensorFlow : Tutorials : Eager : カスタム層

TensorFlow : Tutorials : Eager : カスタム層 (翻訳/解説)

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

* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Custom layers を
翻訳した上で適宜、補足説明したものです:

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

 

ニューラルネットワークを構築するための高位レベル API として tf.keras の使用を推奨します。とは言え、殆どの TensorFlow API は eager execution とともに利用可能です。

import tensorflow as tf
tfe = tf.contrib.eager

tf.enable_eager_execution()

 

層: 有用な演算の一般的なセット

大抵の場合、機械学習モデルのためのコードを書くとき個々の演算や個々の変数の操作よりも抽象化のより高いレベルで演算することを望むでしょう。多くの機械学習モデルは比較的単純な層の組み立てやスタックとして表現できます、そして TensorFlow は多くの一般的な層のセットとともに、スクラッチからあるいは既存の層の組み立てとして貴方自身のアプリケーション固有の層を書く簡単な方法の両者を提供します。

TensorFlow は tf.keras パッケージにフル Keras API を含み、そして Keras 層は貴方自身のモデルを構築するとき非常に有用です。

# In the tf.keras.layers package, layers are objects. To construct a layer,# In th 
# simply construct the object. Most layers take as a first argument the number
# of output dimensions / channels.
layer = tf.keras.layers.Dense(100)
# The number of input dimensions is often unnecessary, as it can be inferred
# the first time the layer is used, but it can be provided if you want to 
# specify it manually, which is useful in some complex models.
layer = tf.keras.layers.Dense(10, input_shape=(None, 5))

事前に存在する層の完全なリストは ドキュメント で見つかります。それは Dense (完全結合層), Conv2D, LSTM, BatchNormalization, Dropout, そしてその他多くを含みます。

# To use a layer, simply call it.
layer(tf.zeros([10, 5]))

Out:

<tf.Tensor: id=30, shape=(10, 10), dtype=float32, numpy=
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]], dtype=float32)>
# Layers have many useful methods. For example, you can inspect all variables
# in a layer by calling layer.variables. In this case a fully-connected layer
# will have variables for weights and biases.
layer.variables
[<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[-0.21914625,  0.0990991 ,  0.18261564,  0.40257913,  0.34072709,
         -0.0625487 , -0.24020803, -0.12010807,  0.40558523, -0.03303367],
        [ 0.08877724, -0.40127528, -0.57334077,  0.10226113, -0.27305049,
         -0.29159862, -0.58058709, -0.60042459, -0.36712468, -0.22455806],
        [-0.2126697 , -0.15910214,  0.12656337,  0.44269663,  0.57688957,
          0.18262208, -0.41651565, -0.33097616,  0.51486522,  0.57214183],
        [ 0.21742707,  0.23269236,  0.56807464, -0.6096639 ,  0.25128335,
         -0.12213349,  0.21207756, -0.05127466,  0.02161229,  0.42359179],
        [-0.53448963,  0.55796593,  0.20331413, -0.5741179 , -0.10637027,
         -0.05225825, -0.4186154 , -0.51762027, -0.24687892, -0.08826667]], dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.], dtype=float32)>]
# The variables are also accessible through nice accessors
layer.kernel, layer.bias
(<tf.Variable 'dense_1/kernel:0' shape=(5, 10) dtype=float32, numpy=
 array([[-0.21914625,  0.0990991 ,  0.18261564,  0.40257913,  0.34072709,
         -0.0625487 , -0.24020803, -0.12010807,  0.40558523, -0.03303367],
        [ 0.08877724, -0.40127528, -0.57334077,  0.10226113, -0.27305049,
         -0.29159862, -0.58058709, -0.60042459, -0.36712468, -0.22455806],
        [-0.2126697 , -0.15910214,  0.12656337,  0.44269663,  0.57688957,
          0.18262208, -0.41651565, -0.33097616,  0.51486522,  0.57214183],
        [ 0.21742707,  0.23269236,  0.56807464, -0.6096639 ,  0.25128335,
         -0.12213349,  0.21207756, -0.05127466,  0.02161229,  0.42359179],
        [-0.53448963,  0.55796593,  0.20331413, -0.5741179 , -0.10637027,
         -0.05225825, -0.4186154 , -0.51762027, -0.24687892, -0.08826667]], dtype=float32)>,
 <tf.Variable 'dense_1/bias:0' shape=(10,) dtype=float32, numpy=array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.], dtype=float32)>)

 

カスタム層を実装する

貴方自身の層を実装するベストな方法は tf.keras.Layer クラスを拡張して次を実装することです :

  • __init__, そこでは総ての入力独立な初期化を行なうことができます。
  • build, そこでは入力 tensor の shape を知り初期化の残りを行なうことができます。
  • call, そこでは forward 計算を行ないます。

変数を作成するために build が呼び出されるまで待つ必要はないことに注意してください、それらを __init__ 内でも作成できます。けれども、それらを build で作成する優位点はそれが (層がその上で作用する) 入力の shape に基づいて遅延 (= late) variable 作成を可能にすることです。その一方で、variable を __init__ で作成することは variable を作成するために必要な shape が明示的に指定される必要があることを意味します。

class MyDenseLayer(tf.keras.layers.Layer):
  def __init__(self, num_outputs):
    super(MyDenseLayer, self).__init__()
    self.num_outputs = num_outputs
    
  def build(self, input_shape):
    self.kernel = self.add_variable("kernel", 
                                    shape=[input_shape[-1].value, 
                                           self.num_outputs])
    
  def call(self, input):
    return tf.matmul(input, self.kernel)
  
layer = MyDenseLayer(10)
print(layer(tf.zeros([10, 5])))
print(layer.variables)
tf.Tensor(
[[ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]], shape=(10, 10), dtype=float32)
[<tf.Variable 'my_dense_layer/kernel:0' shape=(5, 10) dtype=float32, numpy=
array([[-0.24975419, -0.33780435,  0.17131561,  0.28679961, -0.27856019,
        -0.38586116, -0.19720221,  0.25158852, -0.61064029, -0.35856512],
       [ 0.52740663,  0.26937109, -0.61597472,  0.53265864, -0.05881637,
        -0.02134347,  0.59274155, -0.11058015, -0.22670561,  0.34645844],
       [ 0.41161889, -0.40521431, -0.49620956,  0.62973171, -0.20672497,
         0.55795223, -0.29845288,  0.30644548,  0.26540279,  0.27750438],
       [ 0.54720205, -0.14807495, -0.18610999, -0.00718719,  0.23697406,
        -0.30066797,  0.34169638,  0.43261009, -0.08473277, -0.30719322],
       [-0.45203799, -0.57771409, -0.06893957,  0.62330216,  0.43259674,
        -0.15227216, -0.15664744, -0.32023922,  0.32174361,  0.3802709 ]], dtype=float32)>]

コード全体はそれが (可能なときはいつでも) 標準的な層を使用すれば読みやすく維持しやすいです、何故ならば他の読者は標準的な層の挙動に精通しているからです。

 

モデル: 層を構成する

機械学習モデルの多くの興味深い層ライクなものは既存の層を組み立てることにより実装されます。例えば、resnet の各残差ブロックは畳み込み、バッチ正規化、そしてショートカットの合成です。

他の層を含む層ライクなものを作成するとき使用される主要なクラスは tf.keras.Model です。一つの実装は tf.keras.Model から継承することで成されます。

class ResnetIdentityBlock(tf.keras.Model):
  def __init__(self, kernel_size, filters):
    super(ResnetIdentityBlock, self).__init__(name='')
    filters1, filters2, filters3 = filters

    self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1))
    self.bn2a = tf.keras.layers.BatchNormalization()

    self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same')
    self.bn2b = tf.keras.layers.BatchNormalization()

    self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1))
    self.bn2c = tf.keras.layers.BatchNormalization()

  def call(self, input_tensor, training=False):
    x = self.conv2a(input_tensor)
    x = self.bn2a(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2b(x)
    x = self.bn2b(x, training=training)
    x = tf.nn.relu(x)

    x = self.conv2c(x)
    x = self.bn2c(x, training=training)

    x += input_tensor
    return tf.nn.relu(x)

    
block = ResnetIdentityBlock(1, [1, 2, 3])
print(block(tf.zeros([1, 2, 3, 3])))
print([x.name for x in block.variables])

Out:

tf.Tensor(
[[[[ 0.  0.  0.]
   [ 0.  0.  0.]
   [ 0.  0.  0.]]

  [[ 0.  0.  0.]
   [ 0.  0.  0.]
   [ 0.  0.  0.]]]], shape=(1, 2, 3, 3), dtype=float32)
[
'resnet_identity_block/conv2d/kernel:0', 'resnet_identity_block/conv2d/bias:0', 
'resnet_identity_block/batch_normalization/gamma:0', 
'resnet_identity_block/batch_normalization/beta:0', 'resnet_identity_block/conv2d_1/kernel:0', 
'resnet_identity_block/conv2d_1/bias:0', 'resnet_identity_block/batch_normalization_1/gamma:0',
'resnet_identity_block/batch_normalization_1/beta:0', 'resnet_identity_block/conv2d_2/kernel:0',
'resnet_identity_block/conv2d_2/bias:0', 'resnet_identity_block/batch_normalization_2/gamma:0',
'resnet_identity_block/batch_normalization_2/beta:0', 
'resnet_identity_block/batch_normalization/moving_mean:0', 'resnet_identity_block/batch_normalization/moving_variance:0',
'resnet_identity_block/batch_normalization_1/moving_mean:0',
'resnet_identity_block/batch_normalization_1/moving_variance:0',
'resnet_identity_block/batch_normalization_2/moving_mean:0',
'resnet_identity_block/batch_normalization_2/moving_variance:0'
]

けれでも大抵の場合、多くの層を構成するモデルは単に一つの層を他の層に続いて呼び出すだけです。これは tf.keras.Sequential を使用して非常に小さいコードで成されます。

my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1)),
                               tf.keras.layers.BatchNormalization(),
                               tf.keras.layers.Conv2D(2, 1, 
                                                      padding='same'),
                               tf.keras.layers.BatchNormalization(),
                               tf.keras.layers.Conv2D(3, (1, 1)),
                               tf.keras.layers.BatchNormalization()])
my_seq(tf.zeros([1, 2, 3, 3]))
<tf.Tensor: id=503, shape=(1, 2, 3, 3), dtype=float32, numpy=
array([[[[ 0.,  0.,  0.],
         [ 0.,  0.,  0.],
         [ 0.,  0.,  0.]],

        [[ 0.,  0.,  0.],
         [ 0.,  0.,  0.],
         [ 0.,  0.,  0.]]]], dtype=float32)>

 
以上






TensorFlow : Tutorials : Eager : カスタム訓練: 基本

TensorFlow : Tutorials : Eager : カスタム訓練: 基本 (翻訳/解説)

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

* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Custom training: basics を翻訳した上で適宜、補足説明したものです:

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

 

前のチュートリアルでは自動微分のための TensorFlow API をカバーしました、機械学習のための基本的なビルディングブロックです。このチュートリアルでは前のチュートリアルで紹介された TensorFlow プリミティブを使用して何某かの単純な機械学習を行ないます。

TensorFlow はまた高位ニューラルネットワーク API (tf.keras) を含み、これはボイラープレートを削減するために有用な抽象を提供します。ニューラルネットワークで作業する人々のためにこれらの高位 API を強く推奨します。けれども、この短いチュートリアルでは最初の原理から強固な基礎を築くまでのニューラルネットワーク訓練をカバーします。

 

セットアップ

import tensorflow as tf
tfe = tf.contrib.eager # Shorthand for some symbols

tf.enable_eager_execution()

 

Variable

TensorFlow の Tensor はイミュータブル・ステートレス・オブジェクトです。けれども機械学習モデルは変化する状態を持つ必要があります : モデルの訓練につれて、予測を計算するための同じコードが時間とともに異なる挙動をするはずです (できればより小さい損失で!)。計算の進行に渡り変化する必要があるこの状態を表わすために、Python はステートフルなプログラミング言語であるという事実に頼ることを選択できます :

# Using python state
x = tf.zeros([10, 10])
x += 2  # This is equivalent to x = x + 2, which does not mutate the original
        # value of x
print(x)

Out:

tf.Tensor(
[[ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.  2.]], shape=(10, 10), dtype=float32)

 
けれども TensorFlow はステートフルな組み込み演算を持ち、これらは状態の低レベル Python 表現よりもしばしば使用するに快適です。例えばモデルの重みを表現するには、TensorFlow variable を使用するのがしばしば便利で効率的です。

Variable は値をストアするオブジェクトで、TensorFlow 計算で使用されるときはこのストアされた値から暗黙的に読み出されます。TensorFlow variable にストアされた値を操作する演算 (tf.assign_sub, tf.scatter_update, etc) があります。

v = tfe.Variable(1.0)
assert v.numpy() == 1.0

# Re-assign the value
v.assign(3.0)
assert v.numpy() == 3.0

# Use `v` in a TensorFlow operation like tf.square() and reassign
v.assign(tf.square(v))
assert v.numpy() == 9.0

Variable を使用する計算は勾配を計算するとき自動的に追跡されます。埋め込みを表わす Variable については TensorFlow はデフォルトでスパース更新を行ない、これはより多くの計算がかかりメモリ効率的です。

Variable の使用はまたコードの読者にこの状態のピースがミュータブルであることを速やかに知らせる方法でもあります。

 

例題: 線形モデルをフィットさせる

さてここまでに持つ幾つかの概念を並べますと — Tensor, GradientTape, Variable — 単純なモデルを構築して訓練するためにです。これは典型的には幾つかのステップを伴います :

  • モデルを定義する。
  • 損失関数を定義する。
  • 訓練データを取得する。
  • 訓練データを通して実行してデータにフィットするように variable を調整するために “optimizer” を使用します。

このチュートリアルでは、単純な線形モデル: f(x) = x * W + b (これは 2 つの variable – W と b を持ちます) という自明な例題を歩き通します。更に、良く訓練されたモデルが W = 3.0 と b = 2.0 を持つようなデータを合成します。

 

モデルを定義する

variable と計算をカプセル化するために単純なクラスを定義しましょう。

class Model(object):
  def __init__(self):
    # Initialize variable to (5.0, 0.0)
    # In practice, these should be initialized to random values.
    self.W = tfe.Variable(5.0)
    self.b = tfe.Variable(0.0)
    
  def __call__(self, x):
    return self.W * x + self.b
  
model = Model()

assert model(3.0).numpy() == 15.0

 

損失関数を定義する

損失関数は与えられた入力に対するモデルの出力がどのくらい上手く望ましい出力に適合しているかを測定します。標準的な L2 損失を使用しましょう。

def loss(predicted_y, desired_y):
  return tf.reduce_mean(tf.square(predicted_y - desired_y))

 

訓練データを得る

何某かのノイズを持つ訓練データを合成しましょう。

TRUE_W = 3.0
TRUE_b = 2.0
NUM_EXAMPLES = 1000

inputs  = tf.random_normal(shape=[NUM_EXAMPLES])
noise   = tf.random_normal(shape=[NUM_EXAMPLES])
outputs = inputs * TRUE_W + TRUE_b + noise

モデルを訓練する前に現時点でモデルがどこに在るかを可視化しましょう。モデルの予測を赤色で訓練データを青色でプロットします。

import matplotlib.pyplot as plt

plt.scatter(inputs, outputs, c='b')
plt.scatter(inputs, model(inputs), c='r')
plt.show()

print('Current loss: '),
print(loss(model(inputs), outputs).numpy())

 

訓練ループを定義する

今、ネットワークと訓練データを持ちました。それを訓練しましょう、i.e. 勾配降下 を使用して損失が下がるようにモデルの variable (W と b) を更新するために訓練データを使用します。tf.train.Optimizer 実装に含まれる多くの勾配降下スキームの変種があります。それらの実装の使用を強く推奨しますが、最初の原理から構築するという精神で、この特別な例では基本的な数学を私達自身で実装します。

def train(model, inputs, outputs, learning_rate):
  with tf.GradientTape() as t:
    current_loss = loss(model(inputs), outputs)
  dW, db = t.gradient(current_loss, [model.W, model.b])
  model.W.assign_sub(learning_rate * dW)
  model.b.assign_sub(learning_rate * db)

最後に、訓練データを通して繰り返し実行して W と b がどのように展開するか見てみましょう。

model = Model()

# Collect the history of W-values and b-values to plot later
Ws, bs = [], []
epochs = range(10)
for epoch in epochs:
  Ws.append(model.W.numpy())
  bs.append(model.b.numpy())
  current_loss = loss(model(inputs), outputs)

  train(model, inputs, outputs, learning_rate=0.1)
  print('Epoch %2d: W=%1.2f b=%1.2f, loss=%2.5f' %
        (epoch, Ws[-1], bs[-1], current_loss))

# Let's plot it all
plt.plot(epochs, Ws, 'r',
         epochs, bs, 'b')
plt.plot([TRUE_W] * len(epochs), 'r--',
         [TRUE_b] * len(epochs), 'b--')
plt.legend(['W', 'b', 'true W', 'true_b'])
plt.show()

 
以上






TensorFlow : Tutorials : Eager : 自動微分と gradient tape

TensorFlow : Tutorials : Eager : 自動微分と gradient tape (翻訳/解説)

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

* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Automatic differentiation and gradient tape を翻訳した上で適宜、補足説明したものです:

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

 

前のチュートリアル では Tensor とそれらの上の演算を紹介しました。このチュートリアルでは 自動微分 をカバーします、機械学習モデルを最適化するための主要なテクニックです。

 

セットアップ

import tensorflow as tf
tf.enable_eager_execution()

tfe = tf.contrib.eager # Shorthand for some symbols

 

関数の導関数

TensorFlow は自動微分のための API を提供します – 関数の導関数を計算します。数学をより密接に模倣する方法は Python 関数、例えば f、の計算をカプセル化して f のその引数に関する導関数を計算する関数を作成するために tfe.gradients_function を使用します。もし numpy 関数を微分するために autograd に精通しているのであれば、これは馴染みがあるでしょう。例えば :

from math import pi

def f(x):
  return tf.square(tf.sin(x))

assert f(pi/2).numpy() == 1.0

# grad_f は f のその引数に関する導関数のリストを返します。
# f() は単一の引数持ちますので
# grad_f は単一の要素を持つリストを返します。
grad_f = tfe.gradients_function(f)
assert tf.abs(grad_f(pi/2)[0]).numpy() < 1e-7

 

高次勾配

同じ API を望む回数微分するために使用できます :

def f(x):
  return tf.square(tf.sin(x))

def grad(f):
  return lambda x: tfe.gradients_function(f)(x)[0]

x = tf.lin_space(-2*pi, 2*pi, 100)  # 100 points between -2π and +2π

import matplotlib.pyplot as plt

plt.plot(x, f(x), label="f")
plt.plot(x, grad(f)(x), label="first derivative")
plt.plot(x, grad(grad(f))(x), label="second derivative")
plt.plot(x, grad(grad(grad(f)))(x), label="third derivative")
plt.legend()
plt.show()

 

Gradient tape

総ての微分可能な TensorFlow 演算は関連する勾配関数を持ちます。例えば、tf.square(x) の勾配関数は 2.0 * x を返す関数です。(上の例の f(x) のような) ユーザ定義関数の勾配を計算するために、TensorFlow は関数の出力を計算するために適用された総ての演算を最初に「記録」します。この記録を「テーブ」と呼びます。それからそれは reverse モード微分 を使用してユーザ定義関数の勾配を計算するためにそのテープと各プリミティブ演算に関連する勾配関数を使用します。

演算はそれらが実行されるにつれて記録されますので、Python 制御フロー (例えば if と while の使用) は自然に処理されます :

def f(x, y):
  output = 1
  for i in range(y):
    output = tf.multiply(output, x)
  return output

def g(x, y):
  # Return the gradient of `f` with respect to it's first parameter
  return tfe.gradients_function(f)(x, y)[0]

assert f(3.0, 2).numpy() == 9.0   # f(x, 2) is essentially x * x
assert g(3.0, 2).numpy() == 6.0   # And its gradient will be 2 * x
assert f(4.0, 3).numpy() == 64.0  # f(x, 3) is essentially x * x * x
assert g(4.0, 3).numpy() == 48.0  # And its gradient will be 3 * x * x

関心のある計算を関数にカプセル化することは時には不便かもしれません。例えば、関数で計算される出力の中間値に関する勾配を望む場合です。そのような場合には、僅かばかり少し冗長ですが明示的な tf.GradientTape コンテキストは有用です。tf.GradientTape のコンテキストの内側の計算総ては「記録」されます。

例えば :

x = tf.ones((2, 2))
  
# TODO(b/78880779): Remove the 'persistent=True' argument and use
# a single t.gradient() call when the bug is resolved.
with tf.GradientTape(persistent=True) as t:
  # TODO(ashankar): Explain with "watch" argument better?
  t.watch(x)
  y = tf.reduce_sum(x)
  z = tf.multiply(y, y)

# Use the same tape to compute the derivative of z with respect to the
# intermediate value y.
dz_dy = t.gradient(z, y)
assert dz_dy.numpy() == 8.0

# Derivative of z with respect to the original input tensor x
dz_dx = t.gradient(z, x)
for i in [0, 1]:
  for j in [0, 1]:
    assert dz_dx[i][j].numpy() == 8.0

 

高次勾配

GradientTape コンテキスト・マネージャーの内側の演算は自動微分のために記録されます。そのコンテキストで勾配が計算されれば、勾配計算もまた記録されます。結果的に、高次勾配に対してもまた正確に同じ API が動作します。例えば :

# TODO(ashankar): Should we use the persistent tape here instead? Follow up on Tom and Alex's discussion

x = tf.constant(1.0)  # Convert the Python 1.0 to a Tensor object

with tf.GradientTape() as t:
  with tf.GradientTape() as t2:
    t2.watch(x)
    y = x * x * x
  # Compute the gradient inside the 't' context manager
  # which means the gradient computation is differentiable as well.
  dy_dx = t2.gradient(y, x)
d2y_dx2 = t.gradient(dy_dx, x)

assert dy_dx.numpy() == 3.0
assert d2y_dx2.numpy() == 6.0

 
以上






TensorFlow : Tutorials : Eager : Eager execution 基本

TensorFlow : Tutorials : Eager : Eager execution 基本 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 04/11/2019
作成日時 : 07/16/2018

* TensorFlow 1.9 でドキュメント構成が変わり新規にチュートリアル・ページも追加されました。
* 本ページは、TensorFlow 本家サイトの Tutorials – Research and Experimentation – Eager execution basics を
翻訳した上で適宜、補足説明したものです:

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

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

これは TensorFlow を (eager execution を有効にして) 使用するための初歩的なチュートリアルです。以下をカバーします :

  • 必要なパッケージをインポートする。
  • Tensor を作成して使用する。
  • GPU アクセラレーション。
  • データセット。

 

Import TensorFlow

始めるためには、tensorflow モジュールをインポートして Eager execution を有効にします。Eager execution は TensorFlow により対話的なフロントエンドを可能にします。

import tensorflow as tf

tf.enable_eager_execution()

 

Tensor

Tensor は多次元配列です。NumPy ndarray オブジェクトと同様に、Tensor オブジェクトはデータ型と shape を持ちます。更に、Tensor は (GPU のような) アクセラレータ・メモリ内に常駐できます。TensorFlow は Tensor を消費して生成する演算 (tf.add, tf.matmul, tf.linalg.inv etc.) のリッチなライブラリを提供します。これらの演算は native Python 型を自動的に変換します。例えば :

print(tf.add(1, 2))
print(tf.add([1, 2], [3, 4]))
print(tf.square(5))
print(tf.reduce_sum([1, 2, 3]))
print(tf.encode_base64("hello world"))

# Operator overloading is also supported
print(tf.square(2) + tf.square(3))

Out:

tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(b'aGVsbG8gd29ybGQ', shape=(), dtype=string)
tf.Tensor(13, shape=(), dtype=int32)

各 Tensor は shape とデータ型を持ちます。

x = tf.matmul([[1]], [[2, 3]])
print(x.shape)
print(x.dtype)

Out:

(1, 2)
<dtype: 'int32'>

NumPy 配列と TensorFlow Tensor の間の最も明白な違いは :

  1. Tensor は (GPU, TPU のような) アクセラレータ・メモリで支援可能です。
  2. Tensors はイミュータブルです。

 

NumPy 互換性

TensorFlow Tensor と NumPy ndarray の間の変換は次のように非常に単純です :

  • TensorFlow 演算は NumPy ndarray を Tensor に自動的に変換します
  • NumPy 演算は Tensor を NumPy ndarray に自動的に変換します

Tensor はそれらの上で .numpy() メソッドを呼び出すことで NumPy ndarray に明示的に変換できます。これらの変換は典型的には安上がりです、何故ならば array と Tensor は可能であれば基礎的なメモリ表現を共有するからです。けれども、基礎的な表現は常に可能であるとは限りません、何故ならば Tensor は GPU メモリ内にホストされるかもしれず、その一方で NumPy 配列は常にホストメモリで支援されるからで、そのため変換は GPU からホストメモリへのコピーを呼び起こします。

import numpy as np

ndarray = np.ones([3, 3])

print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.multiply(ndarray, 42)
print(tensor)


print("And NumPy operations convert Tensors to numpy arrays automatically")
print(np.add(tensor, 1))

print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())

Out:

TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor(
[[ 42.  42.  42.]
 [ 42.  42.  42.]
 [ 42.  42.  42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to numpy arrays automatically
[[ 43.  43.  43.]
 [ 43.  43.  43.]
 [ 43.  43.  43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[ 42.  42.  42.]
 [ 42.  42.  42.]
 [ 42.  42.  42.]]

 

GPU アクセラレーション

多くの TensorFlow 演算は計算のために GPU を使用することによりアクセラレートできます。どのようなアノテーションもなければ、TensorFlow は演算のために GPU か CPU を使用するかを自動的に決定します (そして必要であれば CPU と GPU メモリ間で tensor をコピーします)。演算により生成される tensor は典型的には (その上で演算が実行される) デバイスのメモリにより支援されます。例えば :

x = tf.random_uniform([3, 3])

print("Is there a GPU available: "),
print(tf.test.is_gpu_available())

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))

Out: (CPU 環境の場合)

Is there a GPU available: 
False
Is the Tensor on GPU #0:  
False

 

デバイス名

Tensor.device プロパティは Tensor のコンテンツをホスティングするデバイスの完全修飾文字列名を提供します。この名前は (その上でプログラムが動作する) ホストのネットワーク・アドレスの識別子とホスト内のデバイスのような多くの詳細をエンコードします。これは TensorFlow プログラムの分散実行のために必要ですが、当面はそれをスキップします。tensor がホスト上の N-th GPU 上に置かれる場合には文字列は GPU:<N> で終わります。

 

明示的なデバイスへの配置

TensorFlow での用語「配置 (= placement)」は個々の演算が実行のためにどのようにデバイス上割り当てられるか (置かれるか) を指し示します。上で言及したように、提供される明示的なガイダンスがないときには、TensorFlow は演算を実行するためのデバイスを自動的に決定して必要であれば Tensor をそのデバイスにコピーします。けれども、TensorFlow 演算はtf.device コンテキスト・マネージャを使用して特定のデバイスに明示的に置かれることができます。例えば :

def time_matmul(x):
  %timeit tf.matmul(x, x)

# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
  x = tf.random_uniform([1000, 1000])
  assert x.device.endswith("CPU:0")
  time_matmul(x)

# Force execution on GPU #0 if available
if tf.test.is_gpu_available():
  with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
    x = tf.random_uniform([1000, 1000])
    assert x.device.endswith("GPU:0")
    time_matmul(x)
On CPU:
10.5 ms ± 38.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

 

データセット

このセクションはモデルにデータを供給するためのパイプラインを構築するために tf.data.Dataset API の使用方法を示します。それは次をカバーします :

  • データセットを作成する。
  • eager execution が有効である際にデータセットに渡り iterate する。

モデルの訓練と評価ループに供給する単純で、再利用可能なピースから高性能で、複雑な入力パイプラインを構築するために Dataset API を使用することを推奨します。

TensorFlow グラフに精通しているのであれば、eager execution が有効であるとき Dataset オブジェクトを構築するための API は正確に同じままですが、データセットの要素に渡り iterate するプロセスは少しだけ単純ですtf.data.Dataset オブジェクトに渡り Python iteration を使用できて tf.data.Iterator オブジェクトを明示的に作成する必要がありません結果的に、TensorFlow ガイドiterator の議論は eager execution が有効であるときには関係ありません

 

ソース Dataset を作成する

ソース dataset は、(Dataset.from_tensors, Dataset.from_tensor_slices のような) factory 関数の一つを使用するか、(TextLineDatasetTFRecordDataset のような) ファイルから読むオブジェクトを使用して作成します。更なる情報のためには TensorFlow ガイド の “入力データを読む” を見てください。

ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp()

with open(filename, 'w') as f:
  f.write("""Line 1
Line 2
Line 3
  """)

ds_file = tf.data.TextLineDataset(filename)

 

変換を適用する

dataset のレコードに変換を適用するために map, batch, shuffle etc. のような変換関数を使用します。詳細については tf.data.Dataset のための API ドキュメント を見てください。

ds_tensors = ds_tensors.map(tf.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

 

Iterate

eager execution が有効であるとき Dataset オブジェクトは iteration をサポートします。TensorFlow グラフの Dataset の使用に精通している場合、Dataset.make_one_shot_iterator() または get_next() コールへの呼び出しの必要はないことに注意してください

print('Elements of ds_tensors:')
for x in ds_tensors:
  print(x)

print('\nElements in ds_file:')
for x in ds_file:
  print(x)

Out:

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

Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)

 
以上






TensorFlow : Guide : 高位 API : Eager Execution

TensorFlow : Guide : 高位 API : Eager Execution (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 04/11/2019 (1.13.1); 07/14/2018 (1.9.0)
作成日時 : 04/08/2018

* TensorFlow 1.9 でドキュメント構成が変わりましたので調整しました。また本ページは改訂されましたので再翻訳しました。
* 本ページは、TensorFlow 本家サイトの Guide – Hight Level APIs – Eager Execution を翻訳した上で
適宜、補足説明したものです:

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

 

本文

TensorFlow の eager execution は命令型プログラミング環境で、グラフを構築することなく演算を直ちに評価します : 演算は後で実行する計算グラフを構築する代わりに具体的な値を返します。これは TensorFlow を始めてモデルをデバッグすることを容易にして、そしてまたそれはボイラープレートを削減します。このガイドに沿ってフォローするためには、対話的 python インタープリタで下のコード・サンプルを実行してください。

Eager execution は研究や実験のための柔軟な機械学習プラットフォームで、以下を提供します :

  • 直感的なインターフェイス — 貴方のコードを自然に構造化して Python データ構造を使用します。小さなモデルと小さなデータ上で迅速に反復します。
  • より簡単なデバッギング — 実行中のモデルを調査して変更をテストするために ops を直接的に呼び出します。即時のエラー報告のために標準的な Python デバッギング・ツールを使用します。
  • 自然な制御フロー — グラフ制御フローの代わりに Python 制御フローを使用し、動的モデルの仕様を単純化します。

Eager execution は殆どの TensorFlow 演算と GPU アクセラレーションをサポートします。eager execution で動作するサンプルのコレクションについては: tensorflow/contrib/eager/python/examples を見てください。

Note: 幾つかのモデルでは eager execution が有効であると増大したオーバーヘッドを経験するかもしれません。パフォーマンス改善は進行中ですが、問題が見つかる場合にはバグをファイルしてベンチマークを共有してください。

 

セットアップと基本的な使用方法

TensorFlow の最新版にアップグレードします :

$ pip install --upgrade tensorflow

eager execution を開始するには、プログラムかコンソール・セッションの最初で tf.enable_eager_execution() を追加します。この演算をプログラムが呼び出す他のモジュールには追加しないでください。

from __future__ import absolute_import, division, print_function

import tensorflow as tf

tf.enable_eager_execution()

今では貴方は TensorFlow 演算を実行できて結果は直ちに返ります :

tf.executing_eagerly()        # => True

x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))  # => "hello, [[4.]]"

eager execution を有効にすると TensorFlow 演算がどのように挙動するかを変更します — 今ではそれらは即時に評価して値を Python に返します。tf.Tensor オブジェクトは計算グラフのノードへのシンボリックなハンドルの代わりに具体的な値を参照します。セッション内で構築して後で実行する計算グラフはありませんので、print() やデバッガーを使用して結果を調査することは容易です。tensor 値の評価、プリンティング、そしてチェックは勾配を計算するためのフローを壊しません。

Eager execution は NumPy と共に素晴らしく動作します。NumPy 演算は tf.Tensor 引数を受け取ります。TensorFlow 数学演算 は Python オブジェクトと NumPy 配列を tf.Tensor オブジェクトに変換します。tf.Tensor.numpy メソッドはオブジェクトの値を NumPy ndarray として返します。

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)
# => tf.Tensor([[1 2]
#               [3 4]], shape=(2, 2), dtype=int32)

# Broadcasting support
b = tf.add(a, 1)
print(b)
# => tf.Tensor([[2 3]
#               [4 5]], shape=(2, 2), dtype=int32)

# Operator overloading is supported
print(a * b)
# => tf.Tensor([[ 2  6]
#               [12 20]], shape=(2, 2), dtype=int32)

# Use NumPy values
import numpy as np

c = np.multiply(a, b)
print(c)
# => [[ 2  6]
#     [12 20]]

# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]

tf.contrib.eager モジュールは eager とグラフ実行環境の両者で利用可能なシンボルを含みそしてグラフと一緒に動作するコードを書く (訳注: 後述) ために有用です :

tfe = tf.contrib.eager

 

動的制御フロー

eager execution の主なメリットはモデルが実行されているときにホスト言語の総ての機能が利用可能であることです。そのため例えば、fizzbuzz を書くことも容易です :

def fizzbuzz(max_num):
  counter = tf.constant(0)
  max_num = tf.convert_to_tensor(max_num)
  for num in range(max_num.numpy()):
    num = tf.constant(num)
    if int(num % 3) == 0 and int(num % 5) == 0:
      print('FizzBuzz')
    elif int(num % 3) == 0:
      print('Fizz')
    elif int(num % 5) == 0:
      print('Buzz')
    else:
      print(num)
    counter += 1
  return counter

これは tensor 値に依拠する条件節を持ちこれらの値を実行時にプリントします。

 

モデルを構築する

多くの機械学習モデルは構成する層により表わされます。TensorFlow を eager execution とともに使用するとき貴方自身の層を書くか tf.keras.layers パッケージで提供される層を使用することができます。

層を表わすために任意の Python オブジェクトを使用できる一方で、TensorFlow は便利な基底クラスとして tf.keras.layers.Layer を持ちます。貴方自身の層を実装するためにそれから継承してください :

class MySimpleLayer(tf.keras.layers.Layer):
  def __init__(self, output_units):
    super(MySimpleLayer, self).__init__()
    self.output_units = output_units

  def build(self, input_shape):
    # The build method gets called the first time your layer is used.
    # Creating variables on build() allows you to make their shape depend
    # on the input shape and hence removes the need for the user to specify
    # full shapes. It is possible to create variables during __init__() if
    # you already know their full shapes.
    self.kernel = self.add_variable(
      "kernel", [input_shape[-1], self.output_units])

  def call(self, input):
    # Override call() instead of __call__ so we can perform some bookkeeping.
    return tf.matmul(input, self.kernel)

上の MySimpleLayer の代わりに tf.keras.layers.Dense 層を使用します、何故ならばそれはその機能のスーパーセットを持つからです (それはまたバイアスを加算します)。

層をモデルに構成するときモデルを表わすために層の線形スタックである tf.keras.Sequential を使用することができます。基本モデルのために使用することは容易です :

model = tf.keras.Sequential([
  tf.keras.layers.Dense(10, input_shape=(784,)),  # must declare input shape
  tf.keras.layers.Dense(10)
])

他の方法として、tf.keras.Model から継承することによりクラスでモデルを体系化します。これは層のためのコンテナでそれ自身が層で、tf.keras.Model オブジェクトが他の tf.keras.Model オブジェクトを含むことを可能にします。

次のサンプルは標準的な MNIST 手書き数字を分類する多層モデルを作成します。それは eager execution 環境で訓練可能なグラフを構築する optimizer と層 API を示します。

class MNISTModel(tf.keras.Model):
  def __init__(self):
    super(MNISTModel, self).__init__()
    self.dense1 = tf.keras.layers.Dense(units=10)
    self.dense2 = tf.keras.layers.Dense(units=10)

  def call(self, input):
    """Run the model."""
    result = self.dense1(input)
    result = self.dense2(result)
    result = self.dense2(result)  # reuse variables from dense2 layer
    return result

model = MNISTModel()

tf.keras.Model クラスのために入力 shape を設定する必要はありません、何故ならば最初に入力が層に渡されるときにパラメータが設定されるからです

tf.keras.layers クラスはそれら自身のモデル変数を作成して含み、それらは層オブジェクトのライフタイムに結び付けられます。層変数を共有するためには、それらのオブジェクトを共有します。

 

Eager 訓練

勾配を計算する

自動微分 はニューラルネットワークを訓練するための バックプロパゲーション のような機械学習アルゴリズムを実装するために有用です。eager execution の間は、後で勾配を計算するための演算を追跡するために tf.GradientTape を使用します。

tfe.GradientTape は追跡しないとき最大限のパフォーマンスを提供するためのオプトインな機能です。異なる演算が各呼び出しの間に発生しますので、総ての forward パス演算は「テープ」に記録されます。勾配を計算するために、テープを反対に再生してから破棄します。特定の一つの tf.GradientTape は 1 つの勾配を計算するだけです ; 続く呼び出しはランタイム・エラーを投げます。

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

 

モデルを訓練する

次のサンプルは標準的な MNIST 手書き数字を分類する多層モデルを作成します。それは eager execution 環境で訓練可能なグラフを構築するために optimizer と層 API を実演します。

# Fetch and format the mnist data
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
   tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
# Build the model
mnist_model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])

訓練なしでさえも、eager executeion でモデルを呼び出して出力を調査してください :

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[-0.00147692 -0.02905408  0.04325635  0.03817059 -0.02543205 -0.01521162
   0.02900162 -0.03181015  0.05013638  0.07374214]]

keras モデルが (fit メソッドを使用する) 訓練ループを持つ一方で、貴方は時には更なるカスタマイズを必要とします。ここに、eager で実装された訓練ループのサンプルがあります :

optimizer = tf.train.AdamOptimizer()

loss_history = []
for (batch, (images, labels)) in enumerate(dataset.take(400)):
  if batch % 10 == 0:
    print('.', end='')
  with tf.GradientTape() as tape:
    logits = mnist_model(images, training=True)
    loss_value = tf.losses.sparse_softmax_cross_entropy(labels, logits)

  loss_history.append(loss_value.numpy())
  grads = tape.gradient(loss_value, mnist_model.trainable_variables)
  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables),
                            global_step=tf.train.get_or_create_global_step())
........................................
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')

 

Variable と optimizer

tf.Variable オブジェクトは、自動微分をより容易にするために訓練の間にアクセスされるミュータブルな tf.Tensor 値をストアします。モデルのパラメータはクラス内に変数としてカプセル化できます。

モデル・パラメータは tf.Variable を tf.GradientTape と共に使用することでより良くカプセル化できます。例えば、上の自動微分サンプルは次のように書き換えることができます :

class Model(tf.keras.Model):
  def __init__(self):
    super(Model, self).__init__()
    self.W = tf.Variable(5., name='weight')
    self.B = tf.Variable(10., name='bias')
  def call(self, inputs):
    return inputs * self.W + self.B

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

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

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return tape.gradient(loss_value, [model.W, model.B])

# 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()
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

# Training loop
for i in range(300):
  grads = grad(model, training_inputs, training_outputs)
  optimizer.apply_gradients(zip(grads, [model.W, model.B]),
                            global_step=tf.train.get_or_create_global_step())
  if i % 20 == 0:
    print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))

print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
Initial loss: 68.132
Loss at step 000: 65.523
Loss at step 020: 30.228
Loss at step 040: 14.266
Loss at step 060: 7.039
Loss at step 080: 3.763
Loss at step 100: 2.276
Loss at step 120: 1.600
Loss at step 140: 1.293
Loss at step 160: 1.153
Loss at step 180: 1.089
Loss at step 200: 1.060
Loss at step 220: 1.047
Loss at step 240: 1.041
Loss at step 260: 1.038
Loss at step 280: 1.037
Final loss: 1.036
W = 3.0057950019836426, B = 1.9924943447113037

 

eager execution の間に状態のためにオブジェクトを使用する

グラフ実行では、(変数のような) プログラム状態はグローバルなコレクションにストアされてそれらのライフタイムは tf.Session オブジェクトで管理されます。対照的に、eager execuction の間は状態オブジェクトのライフタイムはそれらの対応する Python オブジェクトのライフタイムにより決定されます。

 

Variables はオブジェクト

eager execution の間、variable はオブジェクトへの最後の参照が除去されるまで存続し、それから削除されます。

if tf.test.is_gpu_available():
  with tf.device("gpu:0"):
    v = tf.Variable(tf.random_normal([1000, 1000]))
    v = None  # v no longer takes up GPU memory

 

オブジェクト・ベースのセービング

tf.train.Checkpoint は tf.Variable をチェックポイントへ/からセーブしてリストアできます :

x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
x.assign(2.)   # Assign a new value to the variables and save.
checkpoint_path = './ckpt/'
checkpoint.save('./ckpt/')
'./ckpt/-1'
x.assign(11.)  # Change the variable after saving.

# Restore values from the checkpoint
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))

print(x)  # => 2.0
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>

モデルをセーブしてロードするためには、隠れ変数を必要とすることなく、tf.train.Checkpoint がオブジェクトの内部状態をストアします、モデル、optimizer, そしてグローバルステップの状態を記録するためには、それらを tf.train.Checkpoint に渡します :

import os
import tempfile

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])
optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
checkpoint_dir = tempfile.mkdtemp()
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
                           model=model,
                           optimizer_step=tf.train.get_or_create_global_step())

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.checkpointable.util.CheckpointLoadStatus at 0x7fe652194198>

 

オブジェクト指向メトリクス

tfe.metrics はオブジェクトとしてストアされます。新しいデータを callable に渡すことでメトリクスを更新して、そして tfe.metrics.result メソッドを使用して結果を取得します、例えば :

m = tfe.metrics.Mean("loss")
m(0)
m(5)
m.result()  # => 2.5
m([8, 9])
m.result()  # => 5.5
<tf.Tensor: id=68185, shape=(), dtype=float64, numpy=5.5>

 

Summaries と TensorBoard

TensorBoard はモデル訓練プロセスを理解し、デバッグして最適化するための可視化ツールです。それはプログラムを実行する間に書かれる要約イベントを使用します。

tf.contrib.summary は eager とグラフ実行環境の両者で互換です。tf.contrib.summary.scalar のような要約演算はモデル構築の間に挿入されます。例えば、 100 グローバル・ステップ毎に一度要約を記録するためには :

writer = tf.contrib.summary.create_file_writer(logdir)
global_step=tf.train.get_or_create_global_step()  # return global step var

writer.set_as_default()

for _ in range(iterations):
  global_step.assign_add(1)
  # Must include a record_summaries method
  with tf.contrib.summary.record_summaries_every_n_global_steps(100):
    # your model code goes here
    tf.contrib.summary.scalar('loss', loss)
     ...

 

上級者のための自動微分トピック

動的モデル

tfe.GradientTape はまた動的モデルでも利用できます。バックトラックする直線探索 (= line search) アルゴリズムのこのサンプルは、複雑な制御フローにもかかわらず、普通の NumPy コードのように見えます。勾配があり微分可能であることを除けばです :

def line_search_step(fn, init_x, rate=1.0):
  with tf.GradientTape() as tape:
    # Variables are automatically recorded, but manually watch a tensor
    tape.watch(init_x)
    value = fn(init_x)
  grad = tape.gradient(value, init_x)
  grad_norm = tf.reduce_sum(grad * grad)
  init_value = value
  while value > init_value - rate * grad_norm:
    x = init_x - rate * grad
    value = fn(x)
    rate /= 2.0
  return x, value

 

勾配を計算するための追加の関数

tfe.GradientTape は勾配を計算するためのパワフルなインターフェイスですが、自動微分のために利用可能なもう一つの Autograd-スタイル API があります。これらの関数は tfe.Variable なしで tensor と勾配関数だけで、数学コードを書く場合に有用です :

  • tfe.gradients_function — 入力関数パラメータのその引数に関する導関数を計算する関数を返します。入力関数パラメータはスカラー値を返さなければなりません。返された関数が呼び起こされたとき、それは tf.Tensor オブジェクトのリストを返します : 入力関数の各引数のために一つの要素です。興味のある任意のものは関数パラメータとして渡されなければなりませんので、これはもし多くの訓練可能なパラメータへの依存がある場合にはこれは扱いにくくなります。
  • tfe.value_and_gradients_function — tfe.gradients_function と同様ですが、返された関数が呼び起こされるとき、それは入力関数のその引数に関する導関数のリストに加えて入力関数からの値を返します。

次のサンプルでは、tfe.gradients_function は引数として square 関数を取り square のその入力に関する偏微分を計算する関数を返します。square の 3 における導関数を計算するために、grad(3.0) は 6 を返します。

def square(x):
  return tf.multiply(x, x)

grad = tfe.gradients_function(square)

square(3.)  # => 9.0
grad(3.)    # => [6.0]

# The second-order derivative of square:
gradgrad = tfe.gradients_function(lambda x: grad(x)[0])
gradgrad(3.)  # => [2.0]

# The third-order derivative is None:
gradgradgrad = tfe.gradients_function(lambda x: gradgrad(x)[0])
gradgradgrad(3.)  # => [None]


# With flow control:
def abs(x):
  return x if x > 0. else -x

grad = tfe.gradients_function(abs)

grad(3.)   # => [1.0]
grad(-3.)  # => [-1.0]

 

カスタム勾配

カスタム勾配は eager とグラフ実行で勾配を override するための簡単な方法です。forward 関数内では、勾配は入力、出力、または中間結果に関する勾配を定義します。例えば、backward パスで勾配のノルムをクリップするための簡単な方法がここにあります :

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
  y = tf.identity(x)
  def grad_fn(dresult):
    return [tf.clip_by_norm(dresult, norm), None]
  return y, grad_fn

カスタム勾配は演算のシークエンスのための数値的安定な勾配を提供するために一般に使用されます :

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

# The gradient computation works fine at x = 0.
grad_log1pexp(0.)  # => [0.5]

# However, x = 100 fails because of numerical instability.
grad_log1pexp(100.)  # => [nan]

ここで、log1pexp 関数はカスタム勾配で解析的に単純化できます。下の実装は forward パスで計算された tf.exp(x) のための値を再利用しています — 冗長な計算を除去することでそれをより効率的にしています :

@tf.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)

# As before, the gradient computation works fine at x = 0.
grad_log1pexp(0.)  # => [0.5]

# And the gradient computation also works at x = 100.
grad_log1pexp(100.)  # => [1.0]

 

パフォーマンス

eager execution の間は計算は GPU へと自動的にはオフロードされません。計算が動作する位置について制御することを望む場合にはそれを tf.device(‘/gpu:0’) ブロックで囲むことができます (または CPU の同等のもの) :

import time

def measure(x, steps):
  # TensorFlow initializes a GPU the first time it's used, exclude from timing.
  tf.matmul(x, x)
  start = time.time()
  for i in range(steps):
    x = tf.matmul(x, x)
    _ = x.numpy()  # Make sure to execute op and not just enqueue it
  end = time.time()
  return end - start

shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: {} secs".format(measure(tf.random_normal(shape), steps)))

# Run on GPU, if available:
if tfe.num_gpus() > 0:
  with tf.device("/gpu:0"):
    print("GPU: {} secs".format(measure(tf.random_normal(shape), steps)))
else:
  print("GPU: not found")

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

Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 4.614904403686523 secs
GPU: 0.5581181049346924 secs

tf.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

 

ベンチマーク

GPU 上の ResNet50 訓練のような計算が重いモデルについては、eager execution パフォーマンスはグラフ実行に匹敵します。しかしこのギャップはより少ない計算を持つモデルのためにはより大きくなって多くの小さい演算を持つモデルのためにホットコード・パスを最適化するために行われなければならないワークがあります。

 

グラフで作業する

eager execution は開発とデバッギングをより対話的にする一方で、TensorFlow グラフ実行は分散訓練、パフォーマンス最適化、そしてプロダクション配備のための優位点があります。けれども、グラフコードを書くことは標準的な Python コードを書くこととは異なり、デバッグすることがより困難に感じるかもしれません。

グラフ構築モデルをビルドして訓練するためには、Python プログラムは最初に計算を表わすグラフをビルドして、それから C++ ベースのランタイム上で実行のためのグラフを送るために Session.run を呼び起こします。これは以下を提供します :

  • 静的 autodiff を使用する自動微分。
  • プラットフォーム独立なサーバへの単純な配備。
  • グラフ・ベースの最適化 (共通部分式除去, 定数畳み込み, etc.)。
  • コンパイルとカーネル・フュージョン。
  • 自動的な分散とレプリケーション (ノードを分散システム上に配置)。

eager execution のために書かれるコードの配備はより困難です : モデルからグラフを生成するにせよ、あるいは Python ランタイムとコードをサーバ上で直接的に実行するにせよです。

 

互換コードを書く

eager execution のために書かれた同じコードはまたグラフ実行の間にはグラフを構築するでしょう。単純に同じコードを新しい Python セッションで実行することでこれを遂行します、そこでは eager execution は有効ではありません。

殆どの TensorFlow 演算は eager execution の間に動作しますが、しかし留意すべき幾つかのことはあります :

  • 入力前処理のために queue の代わりに tf.data を使用します。それはより高速で簡単です。
  • オブジェクト指向層 API を使用します — tf.keras.layers と tf.keras.Model のような — 何故ならばそれらは変数のためのストレージを明示的に持つからです。
  • 殆どのモデル・コードは eager とグラフ実行の間で同じに動作しますが、例外があります。(例えば、入力に基づく計算を変更する Python 制御フローを使用する動的モデル。)
  • ひとたび tf.enable_eager_execution で eager execution が有効にされれば、それは無効にはできません。グラフ実行に戻るためには新しい Python セッションを開始します。

eager execution とグラフ実行の両者のためにコードを書くのが最善です。これは、グラフ実行の分散パフォーマンスの恩恵とともに eager の対話的実験とデバッグしやすさを貴方に与えます。

eager execution で書き、デバッグし、そして反復し、それからプロダクション配備のためにモデルグラフをインポートします。モデル変数をセーブしてリストアするためには tfe.Checkpoint を使用します、これは eager とグラフ実行環境の間での移動を可能にします。tensorflow/contrib/eager/python/examples のサンプルを見てください。

 

グラフ環境で eager execution を使用する

選択的に TensorFlow グラフ環境で tfe.py_func を使用して eager execution を有効にします。これは tf.enable_eager_execution() が呼び出されていないときに使用されます。

def my_py_func(x):
  x = tf.matmul(x, x)  # You can use tf ops
  print(x)  # but it's eager!
  return x

with tf.Session() as sess:
  x = tf.placeholder(dtype=tf.float32)
  # Call eager function in graph!
  pf = tfe.py_func(my_py_func, [x], tf.float32)
  sess.run(pf, feed_dict={x: [[2.0]]})  # [[4.0]]

 
以上



TensorFlow : Tutorials : Eager : カスタム訓練: ウォークスルー

TensorFlow : Tutorials : Eager : カスタム訓練: ウォークスルー (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
更新日時 : 07/18, 07/17/2018
作成日時 : 04/07/2018

* TensorFlow 1.9 でドキュメント構成が変わりましたので調整しました。また内容も改訂されているので再翻訳しました。
* 本ページは、TensorFlow の本家サイトの Tutorials – Research and Experimentation – Custom training: walkthrough を翻訳した上で適宜、補足説明したものです:

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

 

 

このガイドはアイリス花を種で分類するために機械学習を使用します。それは TensorFlow の eager execution を次のために使用します : 1. モデルを構築する, 2. サンプルデータ上でこのモデルを訓練する, そして 3. 未知のデータ上について予測を行なうためにモデルを使用する。

 

TensorFlow プログラミング

このガイドはこれらの高位 TensorFlow 概念を使用します :

このチュートリアルは多くの TensorFlow プログラムのように構造化されています :

  1. データセットをインポートして解析します。
  2. モデルのタイプを選択します。
  3. モデルを訓練します。
  4. モデルの有効性を評価します。
  5. 予測を行なうために訓練されたモデルを使用します。

 

プログラムのセットアップ

インポートと eager execution を configure する

TensorFlow を含む必要な Python モジュールをインポートして、このプログラムのために eager execution を有効にします。Eager execution は TensorFlow に演算を直ちに評価させて、後で実行される 計算グラフ を作成する代わりに具体的な値を返します。もし貴方が REPL か python インタラクティブ・コンソールに慣れているのであれば、これは馴染むかもしれません。Eager execution は Tensorlow >=1.8 で利用可能です。

ひとたび eager execution が有効にされれば、同じプログラム内ではそれは無効にはできません。より詳細は eager execution ガイド を見てください。

from __future__ import absolute_import, division, print_function

import os
import matplotlib.pyplot as plt

import tensorflow as tf
import tensorflow.contrib.eager as tfe

tf.enable_eager_execution()

print("TensorFlow version: {}".format(tf.VERSION))
print("Eager execution: {}".format(tf.executing_eagerly()))
TensorFlow version: 1.9.0
Eager execution: True

 

アイリス分類問題

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

アイリス属は約 300 種を伴いますが、私達のプログラムは以下の3つだけを分類します :

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

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

幸いなことに、がく片と花弁の測定を持つ 120 アイリス花のデータセット を既に誰かが作成しています。これは初心者の機械学習分類問題に対してポピュラーである古典的なデータセットです。

 

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

私達はデータセット・ファイルをダウンロードしてそれをこの Python プログラムで使用できる構造に変換する必要があります。

データセットをダウンロードする

tf.keras.utils.get_file 関数を使用して訓練データセット・フアイルをダウンロードします。これはダウンロードされたファイルのファイルパスを返します。

train_dataset_url = "http://download.tensorflow.org/data/iris_training.csv"

train_dataset_fp = tf.keras.utils.get_file(fname=os.path.basename(train_dataset_url),
                                           origin=train_dataset_url)

print("Local copy of the dataset file: {}".format(train_dataset_fp))
    Downloading data from http://download.tensorflow.org/data/iris_training.csv
    16384/2194 [================================================================================================================================================================================================================================] - 0s 0us/step
    Local copy of the dataset file: /root/.keras/datasets/iris_training.csv

 

データを調べる

このデータセット, iris_training.csv, はプレーンテキスト・ファイルで CSV としてデータフォーマットされた表をストアしています。最初の 5 エントリを見るために head -n5 コマンドを使用します :

!head -n5 {train_dataset_fp}
    120,4,setosa,versicolor,virginica
    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

データセットのこのビューから、次のことに気がつきます :

  1. 最初の行はデータセットについての情報を含むヘッダです :
    • 総計で 120 サンプルがあります。各サンプルは4つの特徴と3つの可能なラベル名の1つを持ちます。
  2. 続く行はデータレコードで、行毎に1つの サンプル で、そこでは :
    • 最初の4つのフィールドは 特徴 です : これらはサンプルの特質です。ここで、フィールドは花の測定を表わす浮動小数点数を保持しています。
    • 最後のカラムは ラベル です : これは予測することを望む値です。このデータセットのためには、それは花の名前に相当する 0, 1, または 2 の整数値です。

それをコードに書き出しましょう :

# column order in CSV file
column_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species']

feature_names = column_names[:-1]
label_name = column_names[-1]

print("Features: {}".format(feature_names))
print("Label: {}".format(label_name))
Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
Label: species

各ラベルは文字列名 (例えば、”setosa”) に関連しますが、機械学習は典型的には数値に依拠します。ラベル名は命名された表現にマップされます、次のように :

  • 0: アイリス・セトサ
  • 1: アイリス・バージカラー
  • 2: アイリス・バージニカ
class_names = ['Iris setosa', 'Iris versicolor', 'Iris virginica']

 

tf.data.Dataset を作成する

TensorFlow の Dataset API はデータをモデルにロードするための多くの一般的なケースを処理します。これはデータを読みそしてそれを訓練のために使用される形式に変換するための高位 API です。更なる情報のためには Dataset クイックスタート・ガイド を見てください。

データセットは CSV フォーマットのテキストファイルですので、データを適切なフォーマットに解析する (= parse) ために make_csv_dataset 関数を使用します。この関数は訓練モデルのためのデータを生成しますので、デフォルトの挙動はデータをシャッフルして (shuffle=True, shuffle_buffer_size=10000)、データセットを永久に繰り返します (num_epochs=None)。batch_size パラメータもまた設定します。

batch_size = 32

train_dataset = tf.contrib.data.make_csv_dataset(
    train_dataset_fp,
    batch_size, 
    column_names=column_names,
    label_name=label_name,
    num_epochs=1)

make_csv_dataset は (features, label) ペアの tf.data.Dataset を返します、ここで features は辞書: {‘feature_name’: 値} です。

eager execution が有効であるとき、これらの Dataset オブジェクトは iterable です。features のバッチを見てみましょう :

features, labels = next(iter(train_dataset))

features
OrderedDict([('sepal_length',
              <tf.Tensor: id=44, shape=(32,), dtype=float32, numpy=
              array([6.7, 4.9, 6. , 4.4, 6.5, 7.2, 6.3, 5.8, 4.9, 4.9, 5.7, 6.3, 7.4,
                     6. , 6.3, 6.5, 5.1, 5.4, 6.3, 6.4, 6.5, 5.2, 5.8, 5.8, 5.6, 6.8,
                     5. , 4.6, 6.4, 6.4, 5.4, 4.5], dtype=float32)>),
             ('sepal_width',
              <tf.Tensor: id=45, shape=(32,), dtype=float32, numpy=
              array([3.1, 2.5, 2.2, 3. , 3. , 3.2, 2.3, 2.8, 3.1, 3.1, 4.4, 2.5, 2.8,
                     3. , 3.3, 2.8, 2.5, 3.9, 3.3, 3.2, 3. , 3.4, 4. , 2.6, 2.9, 3.2,
                     3.3, 3.1, 3.2, 3.1, 3.7, 2.3], dtype=float32)>),
             ('petal_length',
              <tf.Tensor: id=42, shape=(32,), dtype=float32, numpy=
              array([4.4, 4.5, 5. , 1.3, 5.2, 6. , 4.4, 5.1, 1.5, 1.5, 1.5, 5. , 6.1,
                     4.8, 4.7, 4.6, 3. , 1.7, 6. , 5.3, 5.8, 1.4, 1.2, 4. , 3.6, 5.9,
                     1.4, 1.5, 4.5, 5.5, 1.5, 1.3], dtype=float32)>),
             ('petal_width',
              <tf.Tensor: id=43, shape=(32,), dtype=float32, numpy=
              array([1.4, 1.7, 1.5, 0.2, 2. , 1.8, 1.3, 2.4, 0.1, 0.1, 0.4, 1.9, 1.9,
                     1.8, 1.6, 1.5, 1.1, 0.4, 2.5, 2.3, 2.2, 0.2, 0.2, 1.2, 1.3, 2.3,
                     0.2, 0.2, 1.5, 1.8, 0.2, 0.3], dtype=float32)>)])

同様な特徴は一緒にグループ化、あるいはバッチ化されることに気がついたでしょう。各サンプルの行のフィールドは対応する特徴配列に付加されます。batch_size の変更はこれらの特徴配列にストアされるサンプル数を設定します。

バッチからの幾つかの特徴をプロットすることで何某かのクラスタを見始めることができます :

plt.scatter(features['petal_length'],
            features['sepal_length'],
            c=labels,
            cmap='viridis')

plt.xlabel("Petal length")
plt.ylabel("Sepal length");

モデル構築ステップを単純化するために、特徴辞書を shape: (batch_size, num_features) を持つシングル配列にリパッケージする関数を作成します。

この関数は tf.stack メソッドを使用し、これは tensor のリストからの値を取り指定された次元で結合された tensor を作成します。

def pack_features_vector(features, labels):
  """Pack the features into a single array."""
  features = tf.stack(list(features.values()), axis=1)
  return features, labels

それから各 (features,label) ペアの特徴を訓練データセット (train_dataset) にパックするために tf.data.Dataset.map を使用します :

train_dataset = train_dataset.map(pack_features_vector)

Dataset の特徴要素は今では shape (batch_size, num_features) を持つ配列です。最初の幾つかのサンプルを見てみましょう :

features, labels = next(iter(train_dataset))

print(features[:5])
tf.Tensor(
[[7.7 2.6 6.9 2.3]
 [6.2 2.8 4.8 1.8]
 [7.7 3.  6.1 2.3]
 [6.5 3.  5.2 2. ]
 [5.8 4.  1.2 0.2]], shape=(5, 4), dtype=float32)

 

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

何故モデルなのでしょう?

モデル は特徴とラベルの間の関係性です。アイリス分類問題については、モデルはがく片と花弁の測定と予測されるアイリス種の間の関係性を定義します。ある単純なモデルは代数の 2, 3 行で記述できますが、複雑な機械学習モデルは要約することが難しい巨大な数のパラメータを持ちます。

貴方は機械学習を使用することなしに4つの特徴とアイリス種の間の関係性を決定できますか?つまり、貴方はモデルを作成するために伝統的なプログラミング技術 (例えば、多くの条件ステートメント) を利用できますか?多分 (可能でしょう) — もし貴方がデータセットをがく片と花弁の測定と特定の種間の関係性を決定するために十分に長く解析したのであれば。そしてこれはより複雑なデータセット上では難しく — 多分不可能に — なるでしょう。良い機械学習アプローチは貴方のためにモデルを決定します。もし十分な代表的なサンプルを正しい機械学習モデル・タイプに供給すれば、プログラムはその関係性を貴方のために解くでしょう。

 

モデルを選択する

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


Figure 2. 特徴、隠れ層、そして予測を持つニューラルネットワーク

Figure 2 からのモデルが訓練されてラベル付けされていないサンプルが供給されたとき、それは3つの予測を生成します : この花が与えられたアイリス種である尤度です。この予測は 推論 と呼ばれます。このサンプルについて、出力予測の合計は 1.0 です。Figure 2 では、この予測は以下のように分解されます : アイリス・セトサのために 0.03, アイリス・バージカラーのために 0.95, そしてアイリス・バージニカのために 0.02 です。これはモデルは — 95% の確率で — ラベル付けされていないサンプル花はアイリス・バージカラーであると予測していることを意味します。

 

Keras を使用してモデルを作成する

TensorFlow tf.keras API はモデルと層を作成するための好ましい方法です。これがモデルと実験の構築を容易にする一方で Keras は総てを一緒に接続する複雑さを処理します。

tf.keras.Sequential モデルは層の線形スタックです。そのコンストラクタは層インスタンスのリストを取り、この場合、それぞれ 10 ノードを持つ2つの Dense 層、そして私達のラベル予測を表わす3つのノードを持つ出力層です。最初の層の input_shape パラメータは dataset からの特徴の総量に対応し、これは必要です。

model = tf.keras.Sequential([
  tf.keras.layers.Dense(10, activation=tf.nn.relu, input_shape=(4,)),  # input shape required
  tf.keras.layers.Dense(10, activation=tf.nn.relu),
  tf.keras.layers.Dense(3)
])

活性化関数 は層の各ノードの出力 shape を決定します。これらの非線形性は重要です — それらなしではモデルはシングル層と同じでしょう。多くの 利用可能な活性 がありますが、隠れ層については ReLU が一般的です。

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

 

モデルを使用する

このモデルが特徴のバッチに何を遂行するかを素早く見てみましょう :

predictions = model(features)
predictions[:5]
<tf.Tensor: id=188, shape=(5, 3), dtype=float32, numpy=
array([[ 0.9279162 ,  0.45796293, -0.31660062],
       [ 0.7432568 ,  0.37785432,  0.02789852],
       [ 0.91590106,  0.41053826, -0.01784265],
       [ 0.78945756,  0.390111  ,  0.03119645],
       [ 1.2005233 ,  0.8701208 , -0.06846571]], dtype=float32)>

ここで、各サンプルは各クラスのためにロジットを返します。

これらのロジットを各クラスのための確率に変換するために、softmax 関数を使用します :

tf.nn.softmax(predictions[:5])
<tf.Tensor: id=194, shape=(5, 3), dtype=float32, numpy=
array([[0.52270865, 0.32670936, 0.15058194],
       [0.458099  , 0.3178828 , 0.22401816],
       [0.5009101 , 0.3021924 , 0.19689743],
       [0.46745604, 0.31354997, 0.21899398],
       [0.50006247, 0.35936213, 0.1405754 ]], dtype=float32)>

クラスに渡る tf.argmax を取れば予測されたクラス・インデックスを与えます。しかし、モデルはまだ訓練されていませんので、これらは良い予測ではありません。

print("Prediction: {}".format(tf.argmax(predictions, axis=1)))
print("    Labels: {}".format(labels))
Prediction: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    Labels: [2 2 2 2 0 0 0 0 0 1 0 1 2 2 1 0 1 0 0 0 1 1 2 1 0 2 2 0 2 1 0 0]

 

モデルを訓練する

訓練 はモデルが徐々に最適化される、あるいはモデルがデータセットを学習する際の機械学習のステージです。目標は、初見のデータについて予測を行なうために訓練データセットの構造について十分に学習することです。もし訓練データセットについて学習し過ぎる場合には、予測はそれが見たデータに対して動作するのみで一般化できないでしょう。この問題は overfitting と呼ばれます — それは問題をどのように解くかを理解する代わりに答えを覚えるようなものです。

アイリス分類問題は 教師あり機械学習 の例です : モデルはラベルを含むサンプルから訓練されます。教師なし機械学習 では、サンプルはラベルを含みません。代わりに、モデルは典型的には特徴内のパターンを見つけます。

 

損失と勾配関数を定義する

訓練と評価ステージの両者はモデルの 損失 を計算する必要があります。これはモデルの予測が望まれるラベルからどのくらい離れているかを測定します、換言すれば、モデルがどのくらい悪く遂行しているかです。私達はこの値を最小化、あるいは最適化することを望みます。

私達のモデルは tf.keras.losses.categorical_crossentropy 関数 (訳注: 原文まま) を使用してその損失を計算します、これはモデルのクラス確率予測と望まれるラベルを取り、サンプルに渡る平均損失を返します。

def loss(model, x, y):
  y_ = model(x)
  return tf.losses.sparse_softmax_cross_entropy(labels=y, logits=y_)


l = loss(model, features, labels)
print("Loss test: {}".format(l))
Loss test: 1.086940050125122

モデルを最適化するために使用される 勾配 を計算するために tf.GradientTape コンテキストを使用します。これの更なるサンプルのためには、eager execution ガイド を見てください。

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return loss_value, tape.gradient(loss_value, model.trainable_variables)

 

optimizer を作成する

optimizer は loss 関数を最小化するためにモデルの変数に計算された勾配を適用します。貴方は損失関数を曲面 (Figure 3 参照) として考えることができて私達は歩き回ることによりその最も低いポイントを見つけることを望みます。勾配は上りの最も険しい方向をポイントします — 従って私達は反対の道へ動いて進み丘を降ります。各バッチに対する損失と勾配を反復的に計算することにより、訓練の間にモデルを調整するでしょう。徐々に、モデルは損失を最小化するための重みとバイアスの最善の組み合わせを見つけるでしょう。そして損失がより小さくなれば、モデルの予測がより良くなります。


Figure 3. 3D 空間における時間に渡り可視化された最適化アルゴリズム。
(ソース: [Stanford class CS231n](http://cs231n.github.io/neural-networks-3/), MIT License)

TensorFlow は訓練のために利用可能な多くの 最適化アルゴリズム を持ちます。このモデルは stochastic gradient descent (SGD) アルゴリズムを実装する tf.train.GradientDescentOptimizer を使用します。learning_rate は各反復のための丘を降りるためのステップサイズを設定します。これはより良い結果を得るために一般に調整するハイパーパラメータです。

optimizer と global_step カウンターをセットアップしましょう :

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

global_step = tf.train.get_or_create_global_step()

単一の最適化ステップを計算するためにこれを使用します :

loss_value, grads = grad(model, features, labels)

print("Step: {}, Initial Loss: {}".format(global_step.numpy(),
                                          loss_value.numpy()))

optimizer.apply_gradients(zip(grads, model.variables), global_step)

print("Step: {},         Loss: {}".format(global_step.numpy(),
                                          loss(model, features, labels).numpy()))
Step: 0, Initial Loss: 1.086940050125122
Step: 1,         Loss: 1.0806043148040771

 

訓練ループ

総てのピースが所定の位置にあり、モデルは訓練のための準備ができました! 訓練ループは (モデルが) より良い予測を行なうことを手助けするためにデータセットのサンプルをモデルに供給します。次のコードブロックはこれらの訓練ステップをセットアップします :

  1. 各エポックを反復します。エポックはデータセットを通す一つのパスです。
  2. (一つの) エポック内では、特徴 (x) とラベル (y) をつかむ訓練 Dataset の各サンプルに渡り反復します。
  3. サンプルの特徴を使用して、予測を行ないそれをラベルと比較します。予測の不正確さを測定してモデルの損失と勾配を計算するためにそれを使用します。
  4. モデルの変数を更新するために optimizer を使用します。
  5. 可視化のために幾つかのスタッツを追跡します。
  6. 各エポックのために反復します。

num_epochs 変数はデータセット・コレクションに渡りループするための回数の総数です。直感に反して、モデルをより長く訓練することはより良いモデルを保証しません。num_epochs は貴方が調整可能な ハイパーパラメータ です。正しい数を選択することは通常は経験と実験の両者が必要です。

## Note: Rerunning this cell uses the same model variables

# keep results for plotting
train_loss_results = []
train_accuracy_results = []

num_epochs = 201

for epoch in range(num_epochs):
  epoch_loss_avg = tfe.metrics.Mean()
  epoch_accuracy = tfe.metrics.Accuracy()

  # Training loop - using batches of 32
  for x, y in train_dataset:
    # Optimize the model
    loss_value, grads = grad(model, x, y)
    optimizer.apply_gradients(zip(grads, model.variables),
                              global_step)

    # Track progress
    epoch_loss_avg(loss_value)  # add current batch loss
    # compare predicted label to actual label
    epoch_accuracy(tf.argmax(model(x), axis=1, output_type=tf.int32), y)

  # end epoch
  train_loss_results.append(epoch_loss_avg.result())
  train_accuracy_results.append(epoch_accuracy.result())
  
  if epoch % 50 == 0:
    print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
                                                                epoch_loss_avg.result(),
                                                                epoch_accuracy.result()))
Epoch 000: Loss: 1.120, Accuracy: 35.000%
Epoch 050: Loss: 0.722, Accuracy: 94.167%
Epoch 100: Loss: 0.537, Accuracy: 96.667%
Epoch 150: Loss: 0.423, Accuracy: 95.833%
Epoch 200: Loss: 0.347, Accuracy: 95.833%

 

損失関数を時間に渡り可視化する

モデルの訓練進捗をプリントアウトすることは有用である一方で、この進捗を見ることはしばしばより有用です。TensorBoard は TensorFlow とともにパッケージ化されている素晴らしい可視化ツールですが matplotlib モジュールを使用して基本的なチャートを作成することができます。

これらのチャートを解釈することは何某かの経験が必要ですが、貴方は実際に損失が下がり精度が上がることを見ることを実際に望むでしょう。

fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))
fig.suptitle('Training Metrics')

axes[0].set_ylabel("Loss", fontsize=14)
axes[0].plot(train_loss_results)

axes[1].set_ylabel("Accuracy", fontsize=14)
axes[1].set_xlabel("Epoch", fontsize=14)
axes[1].plot(train_accuracy_results);

 

モデルの有効性を評価する

モデルが訓練された今、その性能について何某かの統計情報を得ることができます。

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

サンプル特徴 ラベル モデル予測
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


Figure 4. 80% 精度のアイリス分類器

 

テストデータセットをセットアップする

モデルを評価することはモデルを訓練することに類似しています。最大の違いはサンプルが訓練セットではなく別の テストセット に由来することです。モデルの有効性を公正に評価するために、モデルを評価するためのサンプルはモデルを訓練するために使用されたサンプルとは異なっていなければなりません。

テスト Dataset のセットアップは訓練 Dataset のセットアップと同様です。CSV テキストファイルをダウンロードしてその値を解析して、少々シャッフルします :

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

test_fp = tf.keras.utils.get_file(fname=os.path.basename(test_url),
                                  origin=test_url)
Downloading data from http://download.tensorflow.org/data/iris_test.csv
8192/573 [============================================================================================================================================================================================================================================================================================================================================================================================================================================] - 0s 0us/step

 

test_dataset = tf.contrib.data.make_csv_dataset(
    train_dataset_fp,
    batch_size, 
    column_names=column_names,
    label_name='species',
    num_epochs=1,
    shuffle=False)

test_dataset = test_dataset.map(pack_features_vector)

 

テストデータセット上でモデルを評価する

訓練ステージとは違い、モデルはテストデータの単一の エポック を評価するだけです。次のコードセルでは、テストセットの各サンプルに渡り反復してモデルの予測を実際のラベルに対して比較します。これはテストセット全体に渡るモデルの精度を測定するために使用されます。

test_accuracy = tfe.metrics.Accuracy()

for (x, y) in test_dataset:
  logits = model(x)
  prediction = tf.argmax(logits, axis=1, output_type=tf.int32)
  test_accuracy(prediction, y)

print("Test set accuracy: {:.3%}".format(test_accuracy.result()))
Test set accuracy: 95.833%

例えば最後のバッチ上で、モデルは通常は正しいことを見て取れます :

tf.stack([y,prediction],axis=1)
<tf.Tensor: id=112986, shape=(24, 2), dtype=int32, numpy=
array([[0, 0],
       [2, 2],
       [1, 2],
       [0, 0],
       [0, 0],
       [1, 1],
       [0, 0],
       [1, 1],
       [0, 0],
       [0, 0],
       [0, 0],
       [0, 0],
       [1, 1],
       [0, 0],
       [2, 2],
       [1, 1],
       [0, 0],
       [2, 2],
       [0, 0],
       [1, 1],
       [1, 1],
       [0, 0],
       [0, 0],
       [1, 1]], dtype=int32)>

 

予測を行なうために訓練されたモデルを使用する

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

現実世界では、ラベル付けされていないサンプルはアプリケーション、CSV ファイル、そしてデータ供給を含む多くの異なるソースに由来するでしょう。当面は、ラベルを予測するために3つのラベル付けされていないサンプルを手動で提供します。思い出してください、次のようにラベル数字は名前付けられた表現にマップされます :

  • 0: アイリス・セトサ
  • 1: アイリス・バージカラー
  • 2: アイリス・バージニカ
predict_dataset = tf.convert_to_tensor([
    [5.1, 3.3, 1.7, 0.5,],
    [5.9, 3.0, 4.2, 1.5,],
    [6.9, 3.1, 5.4, 2.1]
])

predictions = model(predict_dataset)

for i, logits in enumerate(predictions):
  class_idx = tf.argmax(logits).numpy()
  p = tf.nn.softmax(logits)[class_idx]
  name = class_names[class_idx]
  print("Example {} prediction: {} ({:4.1f}%)".format(i, name, 100*p))
Example 0 prediction: Iris setosa (94.8%)
Example 1 prediction: Iris versicolor (67.0%)
Example 2 prediction: Iris virginica (52.0%)
 

以上



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