pytorch学習メモ

Pytorchを学習する中で分からなくて調べた知識をまとめました。随時追加していきます。  
#ネットワーク関連
###torch.nn.Conv2d
畳み込み層の定義  

```python  
torch.nn.Conv2d(入力チャネル数, 出力チャネル数, カーネルサイズ)
```


###torch.nn.Linear
線形層($y=Wx+b$)の定義  

```python
torch.nn.Linear(in_features, out_features, bias=True)
```
例えば, 次元数3のデータを2つ用意してこれを5次元に変換する場合  

```python
x = torch.randn(2, 3)
W = torch.nn.Linear(3, 5, False)
y = m(x)
print(y.size()) #torch.Size([2, 5])
```
```math
x=
\begin{bmatrix}
x_{11} & x_{12} & x_{13}\\
x_{21} & x_{22} & x_{23}
\end{bmatrix},\\
W=
\begin{bmatrix}
w_{11} & w_{12} & w_{13} & w_{14} & w_{15}\\
w_{21} & w_{22} & w_{23} & w_{24} & w_{25}\\
w_{31} & w_{32} & w_{33} & w_{34} & w_{35}
\end{bmatrix},\\
y=xW = 
\begin{bmatrix}
y_{11} & y_{12} & y_{13} & y_{14} & y_{15}\\
y_{21} & y_{22} & y_{23} & y_{24} & y_{25}
\end{bmatrix}\\
```

###torch.nn.functional.max_pool2d
プーリング処理を行う**関数**[^1]  

```python
torch.nn.functional.max_pool2d(入力, カーネルサイズ)
```



#勾配
###net.zero_grad()
netの各パラメータの勾配を0で初期化  
（初期化するのは, 勾配がイテレーション毎に加算される仕様であるため）

###backward()
出力や損失に対する各パラメータの勾配を計算する.  

```python
y.backward()
```
`backward()`は`backward(torch.Tensor([1]))`の省略形である. 
そのため, 例えば出力が[1,10]次元のベクトルである場合  

```python
y.backward(torch.randn(1, 10))
```
のようにする.

###requires_grad="FLAG"
計算グラフを保持することで, そのTensorの全ての演算を追跡する.  
これにより, backward()を使って全ての勾配を自動的に計算できる

```python
x = torch.ones(2,2,requires_grad=True)
print(x)
# tensor([[1., 1.],
#         [1., 1.]], requires_grad=True)
```

###属性grad_fn
演算によって生成されたvariableには属性grad_fnが付与される(独立変数のrequires_gradフラグがTrueだった場合).
これは, どの演算によってvariableが生成されたかを知るものである  

```python
x = torch.randn(2,2)
y = x + 2
print(y.grad_fn)#None / xのrequires_gradがFalseである(演算が追跡されていない)ため

x = torch.randn(2,2,requires_grad=True)
y = x + 2
print(y.grad_fn)#<AddBackward0 object at 0x101b40e48>
z = x/2
print(z.grad_fn)#<DivBackward0 object at 0x10432beb8>

```

#損失
###nn.MSELoss()
平均二乗誤差関数  

```python
criterion=nn.MSELoss()
loss=criterion(output,target)
```

#Tensor関連
###torch.empty()
Tensorを作成する. 作成したTensorは初期化されておらず何らかの値が入っている.

```python
x = torch.empty(5, 3)
print(x)

#tensor([[ 0.0000e+00,  1.5846e+29, -2.6611e-27],
#        [-3.6902e+19, -2.6884e-27,  1.5849e+29],
#        [ 0.0000e+00,  1.5846e+29,  5.6052e-45],
#        [ 0.0000e+00,  0.0000e+00,  1.5846e+29],
#        [ 0.0000e+00,  1.5846e+29, -2.6615e-27]])
```

どうやって決まるのか何の値かは謎…

###torch.rand()
ランダムなTensorを作成する. 

```python
x = torch.rand(5, 3)
print(x)

#tensor([[0.5934, 0.8821, 0.2641],
#        [0.3726, 0.3678, 0.2573],
#        [0.2761, 0.6679, 0.7228],
#        [0.9908, 0.5877, 0.5313],
#        [0.4664, 0.1699, 0.0252]])
```

###torch.zeros()
要素が0で初期化されたTensorを作成する.

```python
x = torch.zeros(5, 3, dtype=torch.long)
print(x)

#tensor([[0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0]])
```

###torch.tensor()
値を直接指定してTensorを作成する.

```python
x = torch.tensor([5.5, 3])
print(x)

#tensor([5.5000, 3.0000])
```

###new_* 
既存のTensorを上書きする. ちなみに元のshapeと揃える必要は無い.

```python
x = torch.tensor([5.5, 3])
x = x.new_ones(5, 3, dtype=torch.double)
print(x)
#tensor([[1., 1., 1.],
#        [1., 1., 1.],
#        [1., 1., 1.],
#        [1., 1., 1.],
#        [1., 1., 1.]], dtype=torch.float64)
```
- new_zeros, new_ones, new_emptyは動いた.
- new_randはエラー

###torch.randn_like()
Tensorの値をランダムに書き換え, 型を変換する
下の例では5*3のゼロ行列を, 5*3の値がランダムなフロート型に変換

```python
x = x.new_zeros(5, 3, dtype=torch.double)      
print(x)
#tensor([[0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0],
#        [0, 0, 0]])
x = torch.randn_like(x, dtype=torch.float)
print(x)       
#tensor([[ 0.4074, -0.4801, -1.7652],
#        [ 0.9456, -0.8796, -0.5751],
#        [-1.5125, -2.3049,  0.7683],
#        [ 0.8419, -0.6031, -0.2340],
#        [ 0.7071,  0.8503,  0.5636]])
```

###transpose

転置  

```python
x = torch.randn(4,3) #4行3列
torch.transpose(x)#3行4列
```
###view
サイズ変更

```python
x = torch.randn(4,3) #4行3列
x.view(12,1) #12行1列
x.view(-1,2) #n行2列（この場合n=6）
```

###size
tensorのサイズを取得

```python
x = torch.randn(4,3)
x.size() #torch.Size([4,3])
```

###numpy()
Tensorをndarrayに変換

```python
a = torch.ones(5)
print(a)　#tensor([1., 1., 1., 1., 1.])
b = a.numpy()
print(b) #[1. 1. 1. 1. 1.]
```

ちなみに

```pythn
a.add_(1)
print(a)
print(b)
# tensor([2., 2., 2., 2., 2.])
# [2. 2. 2. 2. 2.]
```

aの値の変更がbにも反映される.

###torch.from_numpy()
ndarrayをTensorに変換

```python
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
# [2. 2. 2. 2. 2.]
# tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
```

#その他用語
- Affine(アフィン) : 全結合層, 線型層  
  
[^1]: プーリング層を定義するクラス(torch.nn.MaxPool2d)もある