TensorFlowの自動微分の基礎をまとめてみる
TensorFlowの自動微分の基礎について自分なりにまとめてみました。
自動微分の正確な挙動を解説したわけではなく、「こんな感じの挙動なのではないか?」という私の考察を記しているだけなので、参考程度にしていただけると助かります。
TensoeFlowの公式ドキュメントによるとこんな感じで書くと自動微分になるようです。自動微分(Automatic Differentiation)といっていますが、要は普通に微分してくれるだけです。
import tensorflow.compat.v2 as tf #要素が1の2×2配列を生成 #[[1. 1.] # [1. 1.]] x = tf.ones((2, 2)) with tf.GradientTape() as t: t.watch(x) # どの変数で微分するのか明示している(ここでは変数X) #[[1. 1.] # [1. 1.]] #の要素をすべて足し合わせる(つまりy = 4) y = tf.reduce_sum(x) #上の配列の要素がXとすると # Y = 4×X # みたいになっている # Z = Y^2 #をする。 z = tf.multiply(y, y) # 元の入力テンソル x に対する z の微分 dz_dx = t.gradient(z, x) # 要はdz/dy × dy/dxをしている。
コメントアウトで簡単に解説していますが、本文中でも解説します(間違えて理解していたらごめんなさい)。
1. 自動微分のクラスGradientTape()
をt
インスタンスに格納
with tf.GradientTape() as t:
2. watch()
メソッドでどの変数について微分するか明示
t.watch(x)
ここでは変数Xx
で微分すると明示しています。明示しておかないと微分の結果が`None'となってしまいます。
x = tf.Variable(tf.ones((2, 2)))
として、x
を生成しておいても微分できます。
3. 数式の生成
以下のコードで配列Xの中身をすべて足し合わせています。
y = tf.reduce_sum(x)
要素(x)がすべて1で、要素数が4つの配列なので
という数式になっていると思ってよいと思います(この場合は...)。
次に以下のコードで
という数式が出来上がります。
z = tf.multiply(y, y)
これらの数式がt
(テープ: Tape)の中に記録されていきます(たぶん...)。
4.微分の実行
gradient(数式, 変数)
メソッドで微分を実行します。数式
の部分は上で生成した数式(ここではz
)、変数
の部分は何について微分するか明示したものを入れてあげます(ここではx
)。
dz_dx = t.gradient(z, x)
なので
と数式が微分されます。
それと同時にx
の要素を代入した値も同時に計算されます。なので、dz_dx
には
#[[8. 8.] # [8. 8.]]
が格納されます。
微分の注意点として、インスタンスt
に対してメソッドgradient()
は一回しか呼び出せないということです。
つまり、連続して
dz_dx = t.gradient(z, x) dz_dy = t.gradient(z, y) # <- yはxを入れ子にしている変数なので微分できる
とすると
RuntimeError: A non-persistent GradientTape can only be used to compute one set of gradients (or jacobians)
というエラーが返されます。
偏微分などをしたい場合は、初めに
with tf.GradientTape() as t: with tf.GradientTape() as t2:
として、
dz_dx = t.gradient(z, x) dz_dy = t2.gradient(z, y)
としてあげればよいみたいです。
自動?
数値計算のためにコードを書いたら必然的にそれが数式と同様の意味を持つと思います。この”自動”の意味は、数値計算コード(数式)から微分されたコード(数式)を生成して数値計算をしてくれるということなのでしょうか?
確かに、自動微分、便利ですね。