Pytorch公式のtorch.utils.data.DataLoaderって, torch.utils.data.Datasetクラス継承してiteratorとかlen改造したりと, 初心者の心を折る要素がいっぱいあります。
今回は, DataLoaderなしでNumpyを基本として学習させる方法をメモします。
要点だけ言えば, numpy.array(dtype=np.float32)からtorch.tensor()へcast(型変換)すればOKです。
torch.nn.Module系のモデルは, 基本的にtorch.tensor(dtype=torch.float32)しか受け付けません。
mobile-net系とかは量子化されてそうだから違うのかもしれない...
では実装, まずは簡易データを作ります。
# make_easy_dataset.py import numpy as np def make_easy_dataset(X_length): theta = np.linspace(0,10*np.pi, 5000) sin = np.sin(theta) X, y = [], [] for i in range(len(theta) - X_length - 1): X.append([sin[i : i + X_length]]) label = [0,1] if sin[i + X_length + 1] > sin[i + X_length]: label = [1,0] y.append(label) return np.array(X, dtype=np.float32), np.array(y, dtype=np.float32)
Xは, sin波の時系列データ,
yは, 次に上昇するか否かの判定結果です。
この時, 注意すべきは, Xの型を dtype=np.float32 に設定しておくことです。
np.float32に設定しておかないと, 後ほどtorch.tensorへの変換でエラーが出ます。
次にモデルを適当に作っておきます。
以下は, 自作の任意層数1dConvolution簡易モデル, 任意層数FullConnect簡易モデル, 簡易結合networkです。
自分で使いたいモデルがある人は, 自分のモデルでOKです。
# DNN_module.py import torch from torch import nn class SimpleCNN1d(nn.Module): def __init__(self, in_channel:int, out_channel:int, num_block:int, kernel_size:int, stride:int=1, dropout:float=0.0): super(SimpleCNN1d, self).__init__() self.in_channel = in_channel self.out_channel = out_channel self.num_block = num_block self.kernel_size = kernel_size self.dropout = dropout layers = [] for i in range(num_block): if i != 0: layers += [nn.Conv1d(out_channel, out_channel, kernel_size, stride), nn.ReLU()] else: layers += [nn.Conv1d( in_channel, out_channel, kernel_size, stride), nn.ReLU()] if dropout > 0: layers += [nn.Dropout(dropout)] self.net = nn.Sequential(*layers) def forward(self, x): return self.net(x) class FC_classifier(nn.Module): def __init__(self, in_channel:int, in_length:int, out_channel:int, num_block:int): super(FC_classifier, self).__init__() self.in_dim = in_channel * in_length self.out_channel = out_channel self.num_block = num_block self.flatten = nn.Flatten() layers = [] for i in range(num_block): in_dim_ = self.in_dim // (i + 1) if in_dim_ < 1: in_dim_ = 1 out_dim_ = in_dim_ // 2 if out_dim_ < out_channel or i == num_block-1: out_dim_ = out_channel layers += [nn.Linear(self.in_dim, out_dim_)] layers += [nn.Hardsigmoid()] self.net = nn.Sequential(*layers) def forward(self, x): x = self.flatten(x) out = self.net(x) return out class CombinedNet(nn.Module): def __init__(self, models): super(CombinedNet, self).__init__() layers = [] for model in models: layers += [model] self.net = nn.Sequential(*layers) def forward(self, x): return self.net(x)
それではnumpyベースのデータセットとモデルを定義して, 実際に学習を回しましょう。
import torch import make_easy_dataset as med import DNN_module if __name__ == "__main__": data_len = 10 X, y = med.make_easy_dataset(data_len) num_block = 1 base_model = DNN_module.SimpleCNN1d( in_channel = 1, out_channel = 1, num_block = num_block, kernel_size = 3, dropout = 0.2, ) base_out_data_len = data_len - 2*num_block classifier = DNN_module.FC_classifier( in_channel = 1, in_length = base_out_data_len, out_channel = 2, num_block = 1, ) combined_model = DNN_module.CombinedNet([base_model, classifier]) batch_size = 256 epochs = 10 for t in range(epochs): for num_batch in range(len(X) // batch_size + 1): index_start = num_batch * batch_size index_end = index_start + batch_size # torch.tensorへcast(型変換) X_batch = torch.tensor(X[index_start : index_end]) # float32 y_batch = torch.tensor(y[index_start : index_end], dtype=torch.long) # classiferなのでintでOK, float 32でもOK out = combined_model(X_batch) # after processing ....
以上です。