変数の概要

TensorFlow.org で実行 Google Colab で実行 GitHubでソースを表示 ノートブックをダウンロード

TensorFlow の変数は、プログラムが操作する共通の永続的な状態を表すために推奨される方法です。このガイドでは、TensorFlow で tf.Variable のインスタンスを作成、更新、管理する方法について説明します。

変数は tf.Variable クラスを介して作成および追跡されます。tf.Variable は、そこで演算を実行して値を変更できるテンソルを表します。特定の演算ではこのテンソルの値の読み取りと変更を行うことができます。tf.keras などのより高度なライブラリは tf.Variable を使用してモデルのパラメーターを保存します。

セットアップ

このノートブックでは、変数の配置について説明します。変数が配置されているデバイスを確認するには、この行のコメントを外します。

import tensorflow as tf

# Uncomment to see where your variables get placed (see below)
# tf.debugging.set_log_device_placement(True)
2022-12-14 22:50:41.438311: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-12-14 22:50:41.438412: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-12-14 22:50:41.438434: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

変数の作成

変数を作成するには、初期値を指定します。tf.Variable は、初期化の値と同じ dtype を持ちます。

my_tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]])
my_variable = tf.Variable(my_tensor)

# Variables can be all kinds of types, just like tensors
bool_variable = tf.Variable([False, False, False, True])
complex_variable = tf.Variable([5 + 4j, 6 + 1j])

変数の外観と動作はテンソルに似ており、実際にデータ構造が tf.Tensor で裏付けられています。テンソルのように dtype と形状を持ち、NumPy にエクスポートできます。

print("Shape: ", my_variable.shape)
print("DType: ", my_variable.dtype)
print("As NumPy: ", my_variable.numpy())
Shape:  (2, 2)
DType:  <dtype: 'float32'>
As NumPy:  [[1. 2.]
 [3. 4.]]

ほとんどのテンソル演算は期待どおりに変数を処理しますが、変数は変形できません。

print("A variable:", my_variable)
print("\nViewed as a tensor:", tf.convert_to_tensor(my_variable))
print("\nIndex of highest value:", tf.math.argmax(my_variable))

# This creates a new tensor; it does not reshape the variable.
print("\nCopying and reshaping: ", tf.reshape(my_variable, [1,4]))
A variable: <tf.Variable 'Variable:0' shape=(2, 2) dtype=float32, numpy=
array([[1., 2.],
       [3., 4.]], dtype=float32)>

Viewed as a tensor: tf.Tensor(
[[1. 2.]
 [3. 4.]], shape=(2, 2), dtype=float32)

Index of highest value: tf.Tensor([1 1], shape=(2,), dtype=int64)

Copying and reshaping:  tf.Tensor([[1. 2. 3. 4.]], shape=(1, 4), dtype=float32)

上記のように、変数はテンソルによって裏付けられています。テンソルは tf.Variable.assign を使用して再割り当てできます。assign を呼び出しても、(通常は)新しいテンソルは割り当てられません。代わりに、既存テンソルのメモリが再利用されます。

a = tf.Variable([2.0, 3.0])
# This will keep the same dtype, float32
a.assign([1, 2]) 
# Not allowed as it resizes the variable: 
try:
  a.assign([1.0, 2.0, 3.0])
except Exception as e:
  print(f"{type(e).__name__}: {e}")
ValueError: Cannot assign value to variable ' Variable:0': Shape mismatch.The variable shape (2,), and the assigned value shape (3,) are incompatible.

演算でテンソルのような変数を使用する場合、通常は裏付けているテンソルで演算します。

既存の変数から新しい変数を作成すると、裏付けているテンソルが複製されます。2 つの変数が同じメモリを共有することはありません。

a = tf.Variable([2.0, 3.0])
# Create b based on the value of a
b = tf.Variable(a)
a.assign([5, 6])

# a and b are different
print(a.numpy())
print(b.numpy())

# There are other versions of assign
print(a.assign_add([2,3]).numpy())  # [7. 9.]
print(a.assign_sub([7,9]).numpy())  # [0. 0.]
[5. 6.]
[2. 3.]
[7. 9.]
[0. 0.]

ライフサイクル、命名、監視

Python ベースの TensorFlow では、tf.Variable インスタンスのライフサイクルは他の Python オブジェクトと同じです。変数への参照がない場合、変数は自動的に割り当て解除されます。

変数には名前を付けることもでき、変数の追跡とデバッグに役立ちます。2 つの変数に同じ名前を付けることができます。

# Create a and b; they will have the same name but will be backed by
# different tensors.
a = tf.Variable(my_tensor, name="Mark")
# A new variable with the same name, but different value
# Note that the scalar add is broadcast
b = tf.Variable(my_tensor + 1, name="Mark")

# These are elementwise-unequal, despite having the same name
print(a == b)
tf.Tensor(
[[False False]
 [False False]], shape=(2, 2), dtype=bool)

変数名は、モデルの保存と読み込みを行う際に維持されます。デフォルトでは、モデル内の変数は一意の変数名を自動的に取得するため、必要がない限り自分で割り当てる必要はありません。

変数は区別のためには重要ですが、一部の変数は区別する必要はありません。作成時に trainable を false に設定すると、変数の勾配をオフにすることができます。勾配を必要としない変数には、トレーニングステップカウンターなどがあります。

step_counter = tf.Variable(1, trainable=False)

変数とテンソルの配置

パフォーマンスを向上させるため、TensorFlow はテンソルと変数を dtype と互換性のある最速のデバイスに配置しようとします。つまり、GPU を使用できる場合はほとんどの変数が GPU に配置されることになります。

ただし、この動作はオーバーライドすることができます。このスニペットでは GPU が使用できる場合でも浮動小数点数テンソルと変数を CPU に配置します。デバイスの配置ログをオンにすると(セットアップを参照)、変数が配置されている場所を確認できます。

注:手動配置も機能しますが、配置戦略 を使用したほうがより手軽かつスケーラブルに計算を最適化することができます。

このノートブックを GPU の有無にかかわらず異なるバックエンドで実行すると、異なるログが表示されます。ロギングデバイスの配置は、セッション開始時にオンにする必要があります。

with tf.device('CPU:0'):

  # Create some tensors
  a = tf.Variable([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
  b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
  c = tf.matmul(a, b)

print(c)
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

あるデバイスで変数またはテンソルの場所を設定し、別のデバイスで計算を行うことができます。この処理ではデバイス間でデータをコピーする必要があるため、遅延が発生します。

ただし、複数の GPU ワーカーがあっても 1 つの変数のコピーだけが必要な場合は、この処理を実行することができます。

with tf.device('CPU:0'):
  a = tf.Variable([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
  b = tf.Variable([[1.0, 2.0, 3.0]])

with tf.device('GPU:0'):
  # Element-wise multiply
  k = a * b

print(k)
tf.Tensor(
[[ 1.  4.  9.]
 [ 4. 10. 18.]], shape=(2, 3), dtype=float32)

注意: tf.config.set_soft_device_placement はデフォルトでオンになっているため、このコードは GPU のないデバイスで実行する場合でも実行され、CPU で乗算ステップが発生します。

分散トレーニングの詳細については、ガイドをご覧ください。

次のステップ

変数が一般的にどのように使用されているかを理解するには、自動分散に関するガイドをご覧ください。