jacobianによる勾配ベクトルの計算【torch】
スカラ値関数のベクトル変数に関するヤコビ行列として勾配ベクトルが求められる。
jacobian(arg1, arg2)
arg1 ... 勾配ベクトルを求める関数、ここでは戻り値はスカラとする
arg2 ... 勾配ベクトルを求める座標、requires_grad=True は不要、int型はダメ、pt.float型推奨
引数が複数の場合
各引数に対応する勾配を要素に持つタプルが返される。
code:p.py
import torch as pt
from torch.autograd.functional import jacobian
def himmelblau(x, y):
return (x**2 + y - 11)**2 + (x + y**2 - 7)**2
x = pt.tensor(0, dtype=pt.float)
y = pt.tensor(0, dtype=pt.float)
jac = jacobian(himmelblau, (x, y))
print(jac)
'''
(tensor(-14.), tensor(-22.))
'''
引数の数に対応した勾配を要素に持つタプルが返される。引数2個なので、タプルの長さ2。
$ (\partial f / \partial x ~,~ \partial f / \partial y )ということだ。
引数が1つの場合
引数の数が1個の場合、1個の戻り値が返される。
code:p.py
import torch as pt
from torch.autograd.functional import jacobian
def himmelblau(x):
return (x0**2 + x1 - 11)**2 + (x0 + x1**2 - 7)**2 x = pt.tensor(0, 0, dtype=pt.float) jac = jacobian(himmelblau, x)
print(jac)
'''
'''
戻り値は1つのテンソル$ \left[ \partial f / \partial x ~,~ \partial f / \partial y \right] となる。
行列の引数をベクトルで与える
行列操作(行列式の計算)を行う関数にベクトル化した行列を与える例。期待した通りの結果が得られる。
code:p.py
import torch as pt
from torch.autograd.functional import jacobian
def func(x):
x = x.reshape(2,2)
return pt.det(x)
x = pt.tensor(1, 0],[2, 3, dtype=pt.float, requires_grad=True)
x = x.reshape(-1)
jac = jacobian(func, x)
print(jac)
jac = jac.reshape(2, 2)
print(jac)
'''
'''
backwardとの比較
code:p.py
import torch as pt
from torch.autograd.functional import jacobian
def func(x):
return pt.det(x)
x = pt.tensor(1, 0],[2, 3, dtype=pt.float, requires_grad=True)
jac = jacobian(func, x)
print('# by jacobian:\n', jac)
y = func(x)
y.backward()
print('# by backward:\n', x.grad)
'''
# by jacobian:
# by backward:
'''
期待しているとおり、ヤコビ行列と勾配は同じ値。
同じテンソルインスタンス x を使っているにもかかわらず、backward の計算が jacobian の計算の影響を受けていないことに注意。おそらくjacobianに引数xを渡した時点でコピーが生成され、それにrequires_grad=Trueなどが設定されているのではないか?