Pytorch を久しぶりにさわる前に見るやつ(途中)

# import

```.py
import torch
```

最低これは必要。むしろこんなレベルで忘れるとか、どうなってるのかと。

```py
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
```

多分、これくらいないと最低限も使えない。

# tensor の作成

参考：
- [TORCH.TENSOR](https://pytorch.org/docs/stable/tensors.html)： 最低限これの冒頭は見ておくべき。
- [【Pytorch】torch.Tensorの作成と基本操作](https://codezine.jp/article/detail/11052)
- [pytorch Tensor操作チートシート](https://qiita.com/dokkozo/items/e173acded17a142e6d02)：これも見るべき
- [pyTorchのTensor型とは](https://qiita.com/mathlive/items/241bfb42d852bb801b96)

## 要素を指定して作成

次元数はいくつでも作れる。2次元以上の場合、要素の数が列と行であってないとエラーになる。

```.py
>>> x = torch.tensor([1,2,3,4,5])
>>> x
tensor([1, 2, 3, 4, 5])

>>> x = torch.tensor([[1,2,3],[4,5,6]])
>>> x
tensor([[1, 2, 3],
        [4, 5, 6]])

>>> x = torch.tensor([[[1,2],[3,4]],[[5,6],[7,8]]])
>>> x
tensor([[[1, 2],
         [3, 4]],

        [[5, 6],
         [7, 8]]])
```

## 0 や 1 で初期化して作成

```.py
>>> x = torch.zeros(2,3)
>>> x
tensor([[0., 0., 0.],
        [0., 0., 0.]])

>>> x = torch.ones(2,3)
>>> x
tensor([[1., 1., 1.],
        [1., 1., 1.]])
```

2 で初期化したければ、1 で初期化した上で2倍する。

```.py
>>> x = torch.ones(2,3)
>>> x
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>> y = x * 2
>>> y
tensor([[2., 2., 2.],
        [2., 2., 2.]])
```

## ランダムに作成

(0, 1) の一様にランダムな float 値で 4x5 の行列を生成する。

```.py
>>> x = torch.rand(4,5)
>>> x
tensor([[0.5477, 0.8997, 0.3783, 0.0031, 0.6420],
        [0.2774, 0.3532, 0.9457, 0.5091, 0.3471],
        [0.3089, 0.0933, 0.8736, 0.7133, 0.2644],
        [0.8568, 0.8609, 0.2354, 0.2613, 0.8367]])
```

正規分布にするなら `randn` にする。

```.py
>>> x = torch.randn(4,5)
>>> x
tensor([[ 1.0334, -0.3700, -0.4751, -0.1441,  0.7601],
        [-0.3379,  1.6306, -1.0848, -0.3700,  0.6873],
        [-1.0197, -0.3172, -0.7064,  0.0902, -0.1624],
        [-0.5472,  0.7175, -0.8284, -0.4853, -0.9506]])
```

## 連続した数値

0 から 9 までの連続した整数で行列を作る。

```.py
>>> x = torch.arange(0,10)
>>> x
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
```

等差数列の差を指定する。

```.py
>>> x = torch.arange(0,5,0.5)
>>> x
tensor([0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 
        3.0000, 3.5000, 4.0000, 4.5000])
```

## dataloader を使う

MNIST のデータを使う場合。

```.py
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST


data = MNIST(root='../data', 
       train=False, 
       download=True, 
       transform=transforms.ToTensor())

data_loader = DataLoader(data, batch_size=2, shuffle=True)

for i, data in enumerate(data_loader):
    x, y = data
```

x,y を表示させると下記のようになる。

```.py
>>> x
tensor([[[[0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          ...,
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.]]],


        [[[0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          ...,
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.]]]])
>>> y
tensor([7, 1])
```

batch を 2 にしているので、モノクロ画像(28x28 pixel の 0-1 の間の数値)と、画像に対するラベル(0-9の数値)のデータがそれぞれ x, y に 2 つずつ入る。画素のデータは、0-255 の値を 0-1 になるように正規化されたものらしい。

上の表示例では、行列の途中の値が省略されて表示されているため、すべての画素の値が 0 になっているように見えるが、行列の要素をすべて表示させてみると、0 でないデータも入っていることが確認できる。

### MNIST関数

- [公式ドキュメント](https://pytorch.org/docs/stable/torchvision/datasets.html#mnist)
- root: データをダウンロードするディレクトリ。なければ作成される。
- train: True なら training.pt から作成。False なら test.pt から作成。
- download: ローカルにデータが無い場合にダウンロードするなら True、しないなら False
- transform: データに行なう前処理。デフォルトでは None。Compose を使って作成する。変換しない場合でも、演算するなら transform.ToTensor() を指定する必要あり。

### dataloader

- [公式ドキュメント](https://pytorch.org/docs/stable/data.html)
- batch_size: 読み込むデータの個数。デフォルトは 1。
- shuffle: True ならデータをシャッフルしてから読み込む。False なら元データの順序通りに読み込む。


参考
- [PytorchでDataLoaderからデータを取り出す](https://tzmi.hatenablog.com/entry/2020/03/01/202349)
- [pyTorchのtransforms,Datasets,Dataloaderの説明と自作Datasetの作成と使用](https://qiita.com/mathlive/items/2a512831878b8018db02)
- [PyTorchでMNIST](https://qiita.com/fukuit/items/215ef75113d97560e599)

# 行列操作

## index 操作

```index.py
>>> y
tensor([[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11],
        [12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23]])

>>> y[0,0]
tensor(0)

>>> y[:,0]
tensor([ 0,  6, 12, 18])

>>> y[1,:]
tensor([ 6,  7,  8,  9, 10, 11])


```

## 転置

`y = tensor.t(x)`


## 次元を減らす

`y = torch.flatten(x)`

## item

Tensor 型から、python の数値型の値を取り出す。

```
>>> x = torch.tensor([1])
>>> x
tensor([1])

>>> x.item()
1

>>> x[0]
tensor(1)
```

# 演算

## 加減算

そのまま書ける。行列のサイズがあっている必要あり。

```.py
>>> x
tensor([[1., 1., 1.],
        [1., 1., 1.]])

>>> y
tensor([[2., 2., 2.],
        [2., 2., 2.]])

>>> z = x + y
>>> z
tensor([[3., 3., 3.],
        [3., 3., 3.]])

>>> w = z - y
>>> w
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>> 
```

## 積算

行列積は `torch.mm` を使う。

```.py
>>> x
tensor([[1, 1, 1],
        [2, 2, 2],
        [3, 3, 3]])

>>> y
tensor([[1, 2, 3],
        [2, 3, 4],
        [5, 6, 7]])

>>> a = torch.mm(x,y)
>>> a
tensor([[ 8, 11, 14],
        [16, 22, 28],
        [24, 33, 42]])
```

アスタリスク `*` を使うと、行列の要素間の積になる。

```.py
>>> x
tensor([[1, 1, 1],
        [2, 2, 2],
        [3, 3, 3]])

>>> y
tensor([[1, 2, 3],
        [2, 3, 4],
        [5, 6, 7]])

>>> z = x * y
>>> z
tensor([[ 1,  2,  3],
        [ 4,  6,  8],
        [15, 18, 21]])

>>> w = y * z
>>> w
tensor([[  1,   4,   9],
        [  8,  18,  32],
        [ 75, 108, 147]])
```

## 内積

`torch.dot` を使う。

```.py
>>> x = torch.tensor([1,2,3])
>>> y = torch.tensor([4,5,6])
>>> z = torch.dot(x,y)
>>> z
tensor(32)
```

## ベクトルと行列の積

`torch.mv` を使う。

```.py
>>> x = torch.tensor([1,2,3])
>>> y = torch.tensor([[1,2,3],[3,4,5],[5,6,7]])
>>> z = torch.mv(y,x)
>>> z
tensor([14, 26, 38])
```

## matmul

引数を見て、`mm`, `dot`, `mv` のうち適切なものを使う。しかし、適切というのが結構あやしい。

## sum

オプションなしなら、行列の中身をすべて加算した結果を返す。`dim` で和を取る次元を指定できる。二次元配列の場合、0なら列、1なら行の和を取る。`keepdim=True` で行列の次元数を減らさないまま結果を返す。

`z.sum()` という書き方も受け付けられる。 

```sum.py
>>> z = torch.ones(4,6)
>>> z
tensor([[1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1.]])

>>> torch.sum(z)
tensor(24.)

>>> torch.sum(z,dim=0)
tensor([4., 4., 4., 4., 4., 4.])

>>> torch.sum(z,dim=1)
tensor([6., 6., 6., 6.])

>>> z.sum()
tensor(24.)

>>> z.sum(dim=0)
tensor([4., 4., 4., 4., 4., 4.])

>>> torch.sum(z,dim=1,keepdim=True)
tensor([[6.],
        [6.],
        [6.],
        [6.]])
```