Autogradを試す

お仕事でpytorchを使うって言うので、個人的なメモのその1.環境として

  • pythonは3.7
  • pytorchは1.4.0
    環境はセットアップされた前提だとします。

AutoGradについて

1
2
3
4
5
6
## まずはimport
import torch

## Tensorを作ります
tensor1 = torch.Tensor([[1,2,3], [4,5,6]])
tensor2 = torch.Tensor([[7,8,9], [10,11,12]])

後々のために数式で書いておきましょうか。

例えば、 などです。

で、この後自動微分(AutoGrad)を勝手にやってもらうためのオマジナイ(と言ったら怒られるかな)のrequires_gradに対応してるか、をこの状態でチェックしてみます。

1
tensor1.requires_grad ## False tensor2も同様ですね。

どうやってこれをTrueにするか、と言うと、ほんの少し異なるrequires_grad_()を使います:

1
2
3
4
5
tensor1.requires_grad_()
##tensor([[1., 2., 3.],
## [4., 5., 6.]], requires_grad=True)
tensor1.requires_grad
## Trueになると思います。

一足早いですが、gradient(Neural Networkのパラメータを調整時に求める勾配)があるかって言うとまだないですね:

1
2
tensor1.grad
## None

で、足し算してみますね:

1
2
output_tensor = tensor1 + tensor2
output_tensor.backward()

とやると、盛大に怒られます。取り敢えず、アウトプットをスカラー(1次元の数)にせよ、と。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
----> 1 output_tensor.backward()

~\AppData\Local\Continuum\anaconda3\lib\site-packages\torch\tensor.py in backward(self, gradient, retain_graph, create_graph)
193 products. Defaults to ``False``.
194 """
--> 195 torch.autograd.backward(self, gradient, retain_graph, create_graph)
196
197 def register_hook(self, hook):

~\AppData\Local\Continuum\anaconda3\lib\site-packages\torch\autograd\__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
91 grad_tensors = list(grad_tensors)
92
---> 93 grad_tensors = _make_grads(tensors, grad_tensors)
94 if retain_graph is None:
95 retain_graph = create_graph

~\AppData\Local\Continuum\anaconda3\lib\site-packages\torch\autograd\__init__.py in _make_grads(outputs, grads)
32 if out.requires_grad:
33 if out.numel() != 1:
---> 34 raise RuntimeError("grad can be implicitly created only for scalar outputs")
35 new_grads.append(torch.ones_like(out, memory_format=torch.preserve_format))
36 else:

RuntimeError: grad can be implicitly created only for scalar outputs

ということで、計算式をちょっと変えます

1
output_tensor = (tensor1 * tensor2).mean()

冒頭の式

の記号を使うと、、、

ですね(対応する行列成分を掛け算した結果に対して、最後に平均を取る)。ここでもう一度backwardを取ってみます。パット見は何も返って来ません(それが正常です):

1
output_tensor.backward()

この後に.gradを計算させると、、、

1
2
3
tensor1.grad
##tensor([[1.1667, 1.3333, 1.5000],
## [1.6667, 1.8333, 2.0000]])

ですが、これが出てきた背景をば。結論から言えば、tensor1の各成分に関する偏微分(partial)

を計算しています。上記のようにoutput_tensor

でしたから、例えば に関して(偏)微分すると、

となり一致しました。