Skip to content

ClasCat® AI Research

クラスキャット – 生成 AI, AI エージェント, MCP

Menu
  • ホーム
    • ClassCat® AI Research ホーム
    • クラスキャット・ホーム
  • OpenAI API
    • OpenAI Python ライブラリ 1.x : 概要
    • OpenAI ブログ
      • GPT の紹介
      • GPT ストアの紹介
      • ChatGPT Team の紹介
    • OpenAI platform 1.x
      • Get Started : イントロダクション
      • Get Started : クイックスタート (Python)
      • Get Started : クイックスタート (Node.js)
      • Get Started : モデル
      • 機能 : 埋め込み
      • 機能 : 埋め込み (ユースケース)
      • ChatGPT : アクション – イントロダクション
      • ChatGPT : アクション – Getting started
      • ChatGPT : アクション – アクション認証
    • OpenAI ヘルプ : ChatGPT
      • ChatGPTとは何ですか?
      • ChatGPT は真実を語っていますか?
      • GPT の作成
      • GPT FAQ
      • GPT vs アシスタント
      • GPT ビルダー
    • OpenAI ヘルプ : ChatGPT > メモリ
      • FAQ
    • OpenAI ヘルプ : GPT ストア
      • 貴方の GPT をフィーチャーする
    • OpenAI Python ライブラリ 0.27 : 概要
    • OpenAI platform
      • Get Started : イントロダクション
      • Get Started : クイックスタート
      • Get Started : モデル
      • ガイド : GPT モデル
      • ガイド : 画像生成 (DALL·E)
      • ガイド : GPT-3.5 Turbo 対応 微調整
      • ガイド : 微調整 1.イントロダクション
      • ガイド : 微調整 2. データセットの準備 / ケーススタディ
      • ガイド : 埋め込み
      • ガイド : 音声テキスト変換
      • ガイド : モデレーション
      • ChatGPT プラグイン : イントロダクション
    • OpenAI Cookbook
      • 概要
      • API 使用方法 : レート制限の操作
      • API 使用方法 : tiktoken でトークンを数える方法
      • GPT : ChatGPT モデルへの入力をフォーマットする方法
      • GPT : 補完をストリームする方法
      • GPT : 大規模言語モデルを扱う方法
      • 埋め込み : 埋め込みの取得
      • GPT-3 の微調整 : 分類サンプルの微調整
      • DALL-E : DALL·E で 画像を生成して編集する方法
      • DALL·E と Segment Anything で動的マスクを作成する方法
      • Whisper プロンプティング・ガイド
  • Gemini API
    • Tutorials : クイックスタート with Python (1) テキスト-to-テキスト生成
    • (2) マルチモーダル入力 / 日本語チャット
    • (3) 埋め込みの使用
    • (4) 高度なユースケース
    • クイックスタート with Node.js
    • クイックスタート with Dart or Flutter (1) 日本語動作確認
    • Gemma
      • 概要 (README)
      • Tutorials : サンプリング
      • Tutorials : KerasNLP による Getting Started
  • Keras 3
    • 新しいマルチバックエンド Keras
    • Keras 3 について
    • Getting Started : エンジニアのための Keras 入門
    • Google Colab 上のインストールと Stable Diffusion デモ
    • コンピュータビジョン – ゼロからの画像分類
    • コンピュータビジョン – 単純な MNIST convnet
    • コンピュータビジョン – EfficientNet を使用した微調整による画像分類
    • コンピュータビジョン – Vision Transformer による画像分類
    • コンピュータビジョン – 最新の MLPモデルによる画像分類
    • コンピュータビジョン – コンパクトな畳込み Transformer
    • Keras Core
      • Keras Core 0.1
        • 新しいマルチバックエンド Keras (README)
        • Keras for TensorFlow, JAX, & PyTorch
        • 開発者ガイド : Getting started with Keras Core
        • 開発者ガイド : 関数型 API
        • 開発者ガイド : シーケンシャル・モデル
        • 開発者ガイド : サブクラス化で新しい層とモデルを作成する
        • 開発者ガイド : 独自のコールバックを書く
      • Keras Core 0.1.1 & 0.1.2 : リリースノート
      • 開発者ガイド
      • Code examples
      • Keras Stable Diffusion
        • 概要
        • 基本的な使い方 (テキスト-to-画像 / 画像-to-画像変換)
        • 混合精度のパフォーマンス
        • インペインティングの簡易アプリケーション
        • (参考) KerasCV – Stable Diffusion を使用した高性能画像生成
  • TensorFlow
    • TF 2 : 初級チュートリアル
    • TF 2 : 上級チュートリアル
    • TF 2 : ガイド
    • TF 1 : チュートリアル
    • TF 1 : ガイド
  • その他
    • 🦜️🔗 LangChain ドキュメント / ユースケース
    • Stable Diffusion WebUI
      • Google Colab で Stable Diffusion WebUI 入門
      • HuggingFace モデル / VAE の導入
      • LoRA の利用
    • Diffusion Models / 拡散モデル
  • クラスキャット
    • 会社案内
    • お問合せ
    • Facebook
    • ClassCat® Blog
Menu

TensorFlow : Guide : 高位 API : Eager Execution

Posted on 04/08/2018 by Sales Information

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 を翻訳した上で
適宜、補足説明したものです:

  • https://www.tensorflow.org/guide/eager

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

 
以上



クラスキャット

最近の投稿

  • LangGraph 0.5 on Colab : Get started : human-in-the-loop 制御の追加
  • LangGraph 0.5 on Colab : Get started : Tavily Web 検索ツールの追加
  • LangGraph 0.5 on Colab : Get started : カスタム・ワークフローの構築
  • LangGraph 0.5 on Colab : Get started : クイックスタート
  • LangGraph on Colab : SQL エージェントの構築

タグ

AutoGen (13) ClassCat Press Release (20) ClassCat TF/ONNX Hub (11) DGL 0.5 (14) Eager Execution (7) Edward (17) FLUX.1 (16) Gemini (20) HuggingFace Transformers 4.5 (10) HuggingFace Transformers 4.6 (7) HuggingFace Transformers 4.29 (9) Keras 2 Examples (98) Keras 2 Guide (16) Keras 3 (10) Keras Release Note (17) Kubeflow 1.0 (10) LangChain (45) LangGraph (24) MediaPipe 0.8 (11) Model Context Protocol (16) NNI 1.5 (16) OpenAI Agents SDK (8) OpenAI Cookbook (13) OpenAI platform (10) OpenAI platform 1.x (10) OpenAI ヘルプ (8) TensorFlow 2.0 Advanced Tutorials (33) TensorFlow 2.0 Advanced Tutorials (Alpha) (15) TensorFlow 2.0 Advanced Tutorials (Beta) (16) TensorFlow 2.0 Guide (10) TensorFlow 2.0 Guide (Alpha) (16) TensorFlow 2.0 Guide (Beta) (9) TensorFlow 2.0 Release Note (12) TensorFlow 2.0 Tutorials (20) TensorFlow 2.0 Tutorials (Alpha) (14) TensorFlow 2.0 Tutorials (Beta) (12) TensorFlow 2.4 Guide (24) TensorFlow Deploy (8) TensorFlow Get Started (7) TensorFlow Graphics (7) TensorFlow Probability (9) TensorFlow Programmer's Guide (22) TensorFlow Release Note (18) TensorFlow Tutorials (33) TF-Agents 0.4 (11)
2018年4月
月 火 水 木 金 土 日
 1
2345678
9101112131415
16171819202122
23242526272829
30  
« 3月   5月 »
© 2025 ClasCat® AI Research | Powered by Minimalist Blog WordPress Theme