世界の国560595 views
中学理科1626207 views
いろは2986023 views
Computer365120 views
MathPython491378 views
高校日本史189857 views
高校生物549842 views
教育148875 views
中学英語808712 views
高校国語785655 views
Help
Tools

English

TensorFlow の定数・変数・プレースホルダの違い

TensorFlow でデータを扱う際、定数(Constant)、変数(Variable)、プレースホルダ(Placeholder)という3つの概念が登場します。TensorFlow 2.x では Eager モードがデフォルトになり、プレースホルダは非推奨となりましたが、レガシーコードを読む機会もあるため、それぞれの役割と違いを理解しておくことは大切です。

定数 - tf.constant

定数は一度作成すると値を変更できないテンソルです。学習中に変化しないデータ、たとえばハイパーパラメータや固定の入力データに使います。

import tensorflow as tf

# 定数の作成
learning_rate = tf.constant(0.01)
labels = tf.constant([0, 1, 1, 0, 1])

print(learning_rate)  # tf.Tensor(0.01, shape=(), dtype=float32)
print(labels)         # tf.Tensor([0 1 1 0 1], shape=(5,), dtype=int32)

定数はグラフに値がそのまま埋め込まれるため、大きなデータを定数にするとメモリ効率が悪くなる場合があります。大量のデータを扱う場合は tf.data.Dataset などを検討してください。

変数 - tf.Variable

変数は値を更新できるテンソルです。ニューラルネットワークの重みやバイアスなど、訓練中に最適化されるパラメータに使います。

# 変数の作成
weights = tf.Variable(tf.random.normal([3, 2]))
bias = tf.Variable(tf.zeros([2]))

print(weights)
print(bias)

変数の値を更新するには assignassign_addassign_sub メソッドを使います。直接代入はできない点に注意が必要です。

counter = tf.Variable(0)

# 値の代入
counter.assign(10)
print(counter)  # <tf.Variable ... numpy=10>

# 加算
counter.assign_add(5)
print(counter)  # <tf.Variable ... numpy=15>

# 減算
counter.assign_sub(3)
print(counter)  # <tf.Variable ... numpy=12>

変数と定数の決定的な違いは「値を変更できるかどうか」です。訓練ループの中でオプティマイザが自動的に変数を更新してくれるため、モデルのパラメータには必ず tf.Variable を使います。

tf.constant(定数)

値は不変。ハイパーパラメータや固定データに使う。グラフに値が埋め込まれるため、大きなデータには不向き。

tf.Variable(変数)

値を更新できる。モデルの重みやバイアスに使う。オプティマイザによる自動更新の対象になる。

変数の訓練対象フラグ

tf.Variable には trainable パラメータがあります。デフォルトは True で、オプティマイザの更新対象になります。転移学習などで特定の層を凍結したい場合は False に設定します。

# 訓練対象の変数
trainable_var = tf.Variable(1.0, trainable=True)

# 凍結された変数(オプティマイザが更新しない)
frozen_var = tf.Variable(1.0, trainable=False)

# trainable な変数の一覧を取得
model_vars = [trainable_var, frozen_var]
trainable_only = [v for v in model_vars if v.trainable]
print(len(trainable_only))  # 1

この仕組みにより、モデルの一部だけを学習させるファインチューニングが簡単に実現できます。

プレースホルダ - tf.placeholder(TensorFlow 1.x)

プレースホルダは TensorFlow 1.x で使われていた仕組みで、計算グラフの中に「後からデータを流し込む穴」を定義するものでした。

# TensorFlow 1.x のコード(2.x では非推奨)
import tensorflow.compat.v1 as tf1
tf1.disable_eager_execution()

x = tf1.placeholder(tf1.float32, shape=[None, 3])
y = x * 2

with tf1.Session() as sess:
    result = sess.run(y, feed_dict={x: [[1, 2, 3]]})
    print(result)  # [[2. 4. 6.]]

Sessionfeed_dict を使ってデータを供給する必要があり、デバッグが困難でした。TensorFlow 2.x では Eager モードにより、Python の関数をそのまま呼び出す形で計算できるため、プレースホルダは不要になっています。

TensorFlow 2.x での代替パターン

TensorFlow 2.x ではプレースホルダの代わりに、Python の関数引数やKeras の tf.keras.Input を使います。

# 方法1: 通常の Python 関数
def compute(x):
    return x * 2

result = compute(tf.constant([[1, 2, 3]]))
print(result)  # [[2, 4, 6]]
# 方法2: Keras の Input レイヤー
inputs = tf.keras.Input(shape=(3,))
outputs = tf.keras.layers.Dense(1)(inputs)
model = tf.keras.Model(inputs=inputs, outputs=outputs)

model.summary()

Keras の Input はモデルの入力形状を宣言する役割を持ちますが、プレースホルダとは異なり、Eager モードの恩恵を受けてデバッグしやすくなっています。

実践での使い分けまとめ

固定値には tf.constant

学習率、ラベルデータ、設定値など変化しないデータに使います。計算途中の中間結果も自動的に定数テンソルとして扱われます。

学習パラメータには tf.Variable

重み、バイアスなどオプティマイザが更新するパラメータに使います。Keras のレイヤーは内部で自動的に Variable を作成するため、手動で作る機会は限られます。

入力データは tf.data か関数引数

大量のデータは tf.data.Dataset パイプラインで供給し、小さなデータは関数の引数として渡すのが TensorFlow 2.x の標準的なパターンです。

TensorFlow 2.x を使っている限り、日常的に意識するのは tf.constanttf.Variable の2つです。Keras を使えば変数の管理もフレームワークが自動で行ってくれるため、まずはこの2つの違いをしっかり理解しておきましょう。