ホーム » TensorFlow 2.0 » TensorFlow 2.0 : ガイド : 効果的な TensorFlow 2.0

TensorFlow 2.0 : ガイド : 効果的な TensorFlow 2.0

TensorFlow 2.0 : ガイド : 効果的な TensorFlow 2.0 (翻訳/解説)

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

* 本ページは、TensorFlow org サイトの TF 2.0 – Guide : TensorFlow 2.0 の以下のページを翻訳した上で
適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、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 2.0

TensorFlow ユーザをより生産力を高くするために TensorFlow 2.0 で複数の変更があります。TensorFlow 2.0 は 冗長な API を除去し、API をより首尾一貫性のあるものとし (統一 (= unified) RNN, 統一 Optimizer)、そして Eager execution で Python ランタイムとより良く統合します。

多くの RFC は TensorFlow 2.0 の作成に注がれてきた変更を説明しています。このガイドは TensorFlow 2.0 の開発がどのようなものであるべきかのビジョンを提示します。貴方が TensorFlow 1.x への何某かの馴染みを持つことを仮定しています。

 

主要な変更の簡潔な要約

API クリーンアップ

多くの API が なくなるか TF 2.0 に移されました。主要な変更の幾つかは、新しいオープンソース absl-py を支持して tf.app, tf.flags と tf.logging の除去、tf.contrib に存在するプロジェクトの rehome (ホーム変更)、そしてあまり使用されない関数を tf.math のようなサブパッケージに移動することによる主要な tf.* 名前空間のクリーンアップを含みます。幾つかの API はそれらの 2.0 等値である – tf.summary, tf.keras.metricstf.keras.optimizers に置き換えられました。これらの名前変更を自動的に適用する最も容易な方法は v2 upgrade スクリプト を利用することです。

 

Eager execution

TensorFlow 1.X は tf.* API コールによりユーザに 抽象構文木 (グラフ) を手動で一緒に縫い合わせる (= stitch) ことを要求しました。そしてそれは出力 tensor と入力 tensor のセットを session.run() コールに渡すことにより抽象構文木を手動でコンパイルすることをユーザに要求します。TensorFlow 2.0 は (Python が通常行なうように) 逐次命令的に(= eagerly) 実行します、そして 2.0 ではグラフとセッションは実装詳細のような感じです。

eager execution の一つの注目すべき副産物は tf.control_dependencies() はもはや必要とされないことです、何故ならばコードの総ての行は順番に実行されるからです (tf.function 内で、副作用を持つコードは書かれた順番に実行されます)。

 

No more globals

TensorFlow 1.X は大域 (= global) 名前空間に暗黙的に大きく依拠していました。tf.Variable() を呼び出すとき、それはデフォルト・グラフに置かれ、それを指す Python 変数の追跡を貴方が失った場合でさえもそこに存続します。それからその tf.Variable をリカバーできる可能性がありますが、貴方がそれが作成されたときの名前を知る場合に限ります。貴方が変数の作成を管理していなかった場合にはこれは行なうことが困難でした。結果的に、ユーザがそれらの変数を再度見つけることを助けようとするために、そしてフレームワークがユーザが作成した変数を見つけるために総ての種類のメカニズムが急増しました : Variable スコープ、global コレクション、tf.get_global_step(), tf.global_variables_initializer() のようなヘルパーメソッド、総ての訓練可能な変数に渡り暗黙的に勾配を計算する optimizer、等々。TensorFlow 2.0 はこれらのメカニズムの総てをデフォルト・メカニズムのために除去しました (Variables 2.0 RFC) : 貴方の変数を追跡してください!tf.Variable の追跡を失う場合、それはガベージコレクションされます。

変数を追跡するための要件はユーザのための幾つかの追加の作業を作成しますが、Keras オブジェクト (下を参照) で、重荷は最小化されます。

 

Functions, not sessions

session.run() コールは殆ど関数呼び出しのようなものです : 貴方は入力と呼び出される関数を指定し、出力のセットを取り戻します。TensorFlow 2.0 では、Python 関数を JIT コンパイルのためにマークするために tf.function() を使用して修飾 (デコレート) できます、その結果 TensorFlow はそれを単一グラフとして実行します (Functions 2.0 RFC)。このメカニズムは TensorFlow 2.0 にグラフモードの総ての恩恵を得ることを可能にします。

  • パフォーマンス: その関数は最適化できます (ノード枝狩り (= pruning), カーネル融合 etc.)。
  • 可搬性 (= Portability): その関数はエクスポート/再インポート可能 (SavedModel 2.0 RFC)で、ユーザにモジュール化された TensorFlow 関数を再利用して共有することを可能にします。
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TensorFlow 2.0
outputs = f(input)

Python と TensorFlow コードを自由に散在させるパワーにより、ユーザが Python の表現力を活用できます。しかし可搬な TensorFlow はモバイル, C++ そして JavaScript のような、Python インタープリタがないコンテキストで実行されます。@tf.function を追加するときユーザが彼らのコードを書き直さなければならないことを回避する手助けをするために、AutoGraph は Python 構成部品のサブセットをそれらの TensorFlow の等価物に変換します :

  • for/while -> tf.while_loop (break と continue がサポートされます)
  • if -> tf.cond
  • for _ in dataset -> dataset.reduce

AutoGraph は制御フローの任意のネスティングをサポートします、これはシークエンスモデル、 強化学習、カスタム訓練ループ等のような多くの複雑な ML プログラムを性能良くそして簡潔に実装することを可能にします。

 

慣用的な TensorFlow 2.0 のための推奨

貴方のコードをより小さい関数にリファクタリングする

TensorFlow 1.X の一般的な使用方法パターンは「キッチン・シンク」ストラテジーでした、そこでは総ての可能な計算の結合が先取権のある状態で (= preemptively) 並べ立てられて、そしてそれから選択された tensors が session.run() を通して評価されました。TensorFlow 2.0 では、ユーザはコードを (必要に応じて呼び出される) より小さい関数にリファクタリングするべきです。一般に、これらのより小さい関数の各々を tf.function で修飾する必要はありません ; 高位な計算を修飾するために tf.function を使用するだけです – 例えば、訓練の 1 ステップや、モデルの forward パスです。

 

変数を管理するために Keras 層とモデルを使用する

Keras モデルと層は便利な variables と trainable_variables プロパティを提供します、これは総ての依存する変数を再帰的に集めます。これは変数を (それらが使用されている) ローカルで管理することを非常に容易にします。

次を :

def dense(x, W, b):
  return tf.nn.sigmoid(tf.matmul(x, W) + b)

@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
  x = dense(x, w0, b0)
  x = dense(x, w1, b1)
  x = dense(x, w2, b2)
  ...

# You still have to manage w_i and b_i, and their shapes are defined far away from the code.

Keras バージョンと比較してください :

# Each layer can be called, with a signature equivalent to linear(x)
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)

# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]

Keras 層/モデルは tf.train.Checkpointable から継承されて @tf.function と統合されます、これは Keras オブジェクトから直接的にチェックポイントするか SavedModels をエクスポートすることを可能にします。これらの統合を活用するために貴方は必ずしも Keras の fit() API を使用する必要はありません。

ここに転移学習のサンプルがあります、これは関連する変数のサブセットを集めることを Keras がどのように容易にするかを実演します。共有されるトランクを持つマルチヘッド・モデルを訓練しているとしましょう :

trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])

path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])

# Train on primary dataset
for x, y in main_dataset:
  with tf.GradientTape() as tape:
    prediction = path1(x)
    loss = loss_fn_head1(prediction, y)
  # Simultaneously optimize trunk and head1 weights.
  gradients = tape.gradient(loss, path1.trainable_variables)
  optimizer.apply_gradients(zip(gradients, path1.trainable_variables))

# Fine-tune second head, reusing the trunk
for x, y in small_dataset:
  with tf.GradientTape() as tape:
    prediction = path2(x)
    loss = loss_fn_head2(prediction, y)
  # Only optimize head2 weights, not trunk weights
  gradients = tape.gradient(loss, head2.trainable_variables)
  optimizer.apply_gradients(zip(gradients, head2.trainable_variables))

# You can publish just the trunk computation for other people to reuse.
tf.saved_model.save(trunk, output_path)

 

tf.data.Datasets と @tf.function を結合する (= combine)

メモリに fit する訓練データに渡り iterate するとき、通常の Python iteration を自由に使用してください。そうでないならば、tf.data.Dataset はディスクから訓練データをストリームするために最善の方法です。Datasets は iterable で (iterator ではありません)、Eager モードではちょうど他の Python iterable のように動作します。貴方はコードを tf.function() でラップすることにより dataset 非同期 prefetching/streaming 特徴を完全に活用できます、それは AutoGraph を使用して Python iteration を同値のグラフ演算に置き換えます。

@tf.function
def train(model, dataset, optimizer):
  for x, y in dataset:
    with tf.GradientTape() as tape:
      prediction = model(x)
      loss = loss_fn(prediction, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Keras .fit() API を使用する場合には、dataset iteration について心配する必要はないでしょう。

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)

 

Python 制御フローで AutoGraph を活用する

AutoGraph はデータ依存制御フローを tf.condtf.while_loop のようなグラフモードの等価物に変換する方法を提供します。

データ依存制御フローが出現する一つの一般的な場所はシークエンス・モデル内です。tf.keras.layers.RNN は RNN セルをラップして、リカレンスを静的にあるいは動的に展開することを可能にします。デモのためには、動的展開 (= unroll) を次のように再実装できるでしょう :

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell

  def call(self, input_data):
    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    outputs = tf.TensorArray(tf.float32, input_data.shape[0])
    state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
    for i in tf.range(input_data.shape[0]):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state

AutoGraph の特徴のより詳細な概要については、ガイド を見てください。

 

データを累積する tf.metrics とそれらをログ記録する tf.summary

要約をログ記録するためには、tf.summary.(scalar|histogram|…) を使用してそれをコンテキスト・マネージャを使用して writer にリダイレクトします。(コンテキスト・マネージャを省けば、何も起きません。)TF 1.x とは違い、要約は writer に直接送られます ; 個別の “merge” op と個別の add_summary() 呼び出しはなく、これは step value は callsite で提供されなければならないことを意味します。

summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)

データをそれらをロギングする前に要約として蓄積するためには、tf.metrics を使用します。Metrics はステートフルです : それらは値を累積して .result() を呼び出すときに累積結果を返します。累積値は .reset_states() でクリアします。

def train(model, optimizer, dataset, log_freq=10):
  avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
  for images, labels in dataset:
    loss = train_step(model, optimizer, images, labels)
    avg_loss.update_state(loss)
    if tf.equal(optimizer.iterations % log_freq, 0):
      tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
      avg_loss.reset_states()

def test(model, test_x, test_y, step_num):
  loss = loss_fn(model(test_x), test_y)
  tf.summary.scalar('loss', loss, step=step_num)

train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')

with train_summary_writer.as_default():
  train(model, optimizer, dataset)

with test_summary_writer.as_default():
  test(model, test_x, test_y, optimizer.iterations)

TensorBoard を要約ログディレクトリをポイントさせることにより生成された要約を可視化します :

tensorboard --logdir /tmp/summaries

 

デバッグするとき tf.config.experimental_run_functions_eagerly() を使用する

TensorFlow 2.0 では、Eager Execution は shape、データ型と値を調査するために貴方にコードをステップ毎に実行させます。

tf.function, tf.keras 等のような特定の API はパフォーマンスと可搬性のために Graph 実行を使用するために設計されています。デバッグするとき、このコード内で Eager execution を使用するために experimental_run_functions_eagerly(True) を使用します。

例えば :

@tf.function
def f(x):
  if x > 0:
    import pdb
    pdb.set_trace()
    x = x + 1
  return x

tf.config.experimental_run_functions_eagerly(True)
f(tf.constant(1))
>>>f()
-> x = x + 1
(Pdb) l
  6      @tf.function
  7      def f(x):
  8        if x > 0:
  9          import pdb
 10          pdb.set_trace()
 11  ->      x = x + 1
 12        return x
 13
 14      tf.config.experimental_run_functions_eagerly(True)
 15      f(tf.constant(1))
[EOF]

これはまた Keras モデルと Eager execution をサポートする他の API 内で動作します。

class CustomModel(tf.keras.models.Model):

  @tf.function
  def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
      return input_data
    else:
      import pdb
      pdb.set_trace()
      return input_data // 2


tf.config.experimental_run_functions_eagerly(True)
model = CustomModel()
model(tf.constant([-2, -4]))
>>> call()
-> return input_data // 2
(Pdb) l
 10         if tf.reduce_mean(input_data) > 0:
 11           return input_data
 12         else:
 13           import pdb
 14           pdb.set_trace()
 15  ->       return input_data // 2
 16
 17
 18     tf.config.experimental_run_functions_eagerly(True)
 19     model = CustomModel()
 20     model(tf.constant([-2, -4]))

 

以上



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