はじめに
pytorch の DataLoader や function の使い方が分からないので、手元でガチャガチャ動かしてみました。
メモです。
内容
IRIS dataset を使ってみます。
from sklearn import datasets
iris = datasets.load_iris()
ここでdata にndarray で値が収められています。
In [11]: iris.data.shape
Out[11]: (150, 4)
In [12]: type(iris.data)
Out[12]: numpy.ndarray
正解ラベルが target に収められているようです。
In [15]: iris.target
Out[15]:
array([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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
これらを学習で利用するために、pytorch ではDataLoader というクラスを使うらしい。
DataLoader を使う上でのポイントとして、まずDataset の用意があります。
DataLoader のコンストラクタで dataset が必要。dataset は map-style と iterable-style がある。map-style は getitem() と len() とが実装されていて、多くの場合 dataset[idx] で idx番目の要素を参照するように使うらしい。典型的な例では、torch.utils.data.Dataset を継承したクラスを作り、getitem() と len() を実装する例をよく見ます。
ただし、もっと簡単には TensorDataset を使うことができるようです。今の場合、
tgts = torch.tensor(iris.target, dtype=torch.int64)
inps = torch.tensor(iris.data, dtype=torch.float32)
dataset = torch.utils.data.TensorDataset(inps, tgts)
最初の要素には、dataset[0]でアクセスできます。inps と tgts の二つのテンソルがそのまま tensors で参照できます。
In [27]: len(dataset.tensors)
Out[27]: 2
In [28]: dataset[0]
Out[28]: (tensor([5.1000, 3.5000, 1.4000, 0.2000]), tensor(0))
In [29]: len(dataset)
Out[29]: 150
バッチサイズを3にすると、最初の3個のデータがまとめて取得できます。
In [34]: data_loader = torch.utils.data.DataLoader(dataset,
...: batch_size=3, shuffle=False)
In [35]: for v in data_loader:
...: print(v)
...: break
...:
[tensor([[5.1000, 3.5000, 1.4000, 0.2000],
[4.9000, 3.0000, 1.4000, 0.2000],
[4.7000, 3.2000, 1.3000, 0.2000]]), tensor([0, 0, 0])]
In [36]: dataset[0:3]
Out[36]:
(tensor([[5.1000, 3.5000, 1.4000, 0.2000],
[4.9000, 3.0000, 1.4000, 0.2000],
[4.7000, 3.2000, 1.3000, 0.2000]]),
tensor([0, 0, 0]))
バッチサイズが1(default) でも配列で与えられることは変わりないようです。
In [38]: for v in data_loader:
...: print(v)
...: break
...:
[tensor([[5.1000, 3.5000, 1.4000, 0.2000]]), tensor([0])]
In [39]: for d,t in data_loader:
...: print(d.shape, t.shape)
...: break
...:
torch.Size([1, 4]) torch.Size([1])
data_loader をtrain, validation で分けるために、dataset を分ける機能もtorch.utils.data.random_splitで提供されています。
ところで、ここで Cuda memory pinning について書かれていましたが、何のことだろう。
https://pytorch.org/docs/stable/notes/cuda.html#cuda-memory-pinning
GPUのメモリコピーは早いが、CPUで使う場合も非同期処理ができるようにほげほげ。。。
まとめ
とりあえず、DataLoader については、ざっと目を通してみた。次はloss を計算する所を調べてみようかな。