実現したいこと
ここに実現したいことを箇条書きで書いてください。
- 松尾研究室が公開している学習コンテンツの Keras による RNN 実装を PyTorch で実現したい。
前提
現在、東京大学松尾研究室が公開している、機械学習・深層学習の教材 DL4US を利用して深層学習の独習をしています。学習において、教材を読むのに合わせてコードを写経しているのですが、ただ写経するだけでは「分かったつもり」で流してしまうかもしれませんので、自分の理解度を確認するため Pytorch で同じ機能の実装しながら進めています。
現在、Lesson3 の Section2 で RNN の実装を学習しているところですが、教材の Keras による RNN 実装を Pytorch で実現しようとしても、明らかに性能が劣ったものしか作れていません。私の実装の問題点をご指摘いただき、どのように改善すれば教材の実装と同程度の性能を実現できるか、ご教示よろしくお願いします。
教材の実装の Fix 版
上記教材は公開が2019年と古く、2023年4月8日現在、ダウンロードを指定された ECG5000 のデータの仕様が変わっているため、その点を私的にフィックスしたソースが以下になります。
Python
1!wget -P ./data/ http://timeseriesclassification.com/Downloads/ECG5000.zip 2!unzip -d ./data/ /content/data/ECG5000.zip 3 4from scipy.io import arff 5import numpy as np 6 7# TEST.arff のデータが4500件、TRAIN.arff のデータが500件、 8# これは多分名前が取り違えられてると思うので、TRAIN と TESTの役割を入れ替え 9train_dataset, train_meta = arff.loadarff('data/ECG5000_TEST.arff') 10train_ds = np.asarray(train_dataset.tolist(), dtype=np.float32) 11x_train_dataset = train_ds[:, :140] 12y_train_dataset = np.asarray(train_ds[:,-1].tolist(), dtype=np.int8)-1 13 14test_dataset, test_meta = arff.loadarff('data/ECG5000_TRAIN.arff') 15test_ds = np.asarray(test_dataset.tolist(), dtype=np.float32) 16x_test_dataset = test_ds[:, :140] 17y_test_dataset = np.asarray(test_ds[:,-1].tolist(), dtype=np.int8)-1 18 19print(x_train_dataset.shape) 20print(y_train_dataset.shape) 21print(x_test_dataset.shape) 22print(y_test_dataset.shape) 23 24#(4500, 140) 25#(4500,) 26#(500, 140) 27#(500,) 28 29from sklearn.model_selection import train_test_split 30from tensorflow.keras.utils import to_categorical 31 32x_train = x_train_dataset[:,:,np.newaxis] 33y_train = to_categorical(y_train_dataset) 34 35x_test = x_test_dataset[:,:,np.newaxis] 36y_test = to_categorical(y_test_dataset) 37 38from tensorflow.keras.models import Sequential 39from tensorflow.keras.layers import Dense, Activation, SimpleRNN 40 41hid_dim = 10 42 43# SimpleRNNにDenseを接続し、分類 44model = Sequential() 45 46model.add(SimpleRNN(hid_dim, input_shape=x_train.shape[1:])) # input_shape=(系列長T, x_tの次元), output_shape=(units(=hid_dim),) 47model.add(Dense(y_train.shape[1], activation='softmax')) 48 49model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 50 51model.fit(x_train, y_train, epochs=50, batch_size=100, verbose=2, validation_split=0.2) 52 53score = model.evaluate(x_test, y_test, verbose=0) 54print('test_loss:', score[0]) 55print('test_acc:', score[1])
上記コードの Colab リンク
以上のコードを実行して頂くと、テストデータに対してだいたい90%前後の正解を出せるモデルが完成します。
教材版の RNN と同機能を実現したいと思うも上手くいっていない私の Pytorch 実装
Python
1from scipy.io import arff 2import numpy as np 3import torch 4from torch.utils.data import Dataset 5from torch.utils.data import DataLoader 6from torch import nn 7from tqdm.notebook import tqdm 8 9!wget -P ./data/ http://timeseriesclassification.com/Downloads/ECG5000.zip 10!unzip -d ./data/ /content/data/ECG5000.zip 11 12# TEST.arff のデータが4500件、TRAIN.arff のデータが500件、 13# これは多分名前が取り違えられてると思うので、TRAIN と TESTの役割を入れ替え 14down_loaded_train_data, train_meta = arff.loadarff("data/ECG5000_TEST.arff") 15down_loaded_test_data, test_meta = arff.loadarff('data/ECG5000_TRAIN.arff') 16 17print(len(down_loaded_train_data)) # 4500 18print(len(down_loaded_train_data[0])) # 141 19 20print(len(down_loaded_test_data)) # 500 21print(len(down_loaded_test_data[0])) # 141 22 23class CustomDataset(Dataset): 24 def __init__(self, dataset=None, time_series_size=None): 25 dataset = np.array(dataset.tolist(), dtype=np.float32) 26 labels_index = torch.from_numpy(dataset[:, -1]).to(torch.long) - 1 27 28 self.X = torch.from_numpy(dataset[:, :time_series_size]).unsqueeze(2) 29 self.y = labels_index 30 31 def __len__(self): 32 return len(self.X) 33 34 def __getitem__(self, idx): 35 return self.X[idx], self.y[idx] 36 37time_series_size = 140 # 一件のデータの時系列サイズが140 で、ラベルが1つ 38train_data = CustomDataset(down_loaded_train_data, time_series_size) 39test_data = CustomDataset(down_loaded_test_data, time_series_size) 40 41# Dataset から DataLoader を作成 42batch_size=100 43train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True) 44test_loader = DataLoader(test_data, batch_size=batch_size) 45 46class MyRNN(nn.Module): 47 def __init__(self, input_size=1, hidden_size=1): 48 super().__init__() 49 50 self.num_rnn_layers = 1 51 self.input_size = input_size 52 self.hidden_size = hidden_size 53 54 self.rnn = nn.RNN(input_size, hidden_size) 55 self.fc = nn.Linear(hidden_size, 5) 56 57 def hidden_initialize(self, time_series_size): 58 return torch.zeros((self.num_rnn_layers, time_series_size, self.hidden_size)) 59 60 def forward(self, x, hidden): 61 output, hidden = self.rnn(x, hidden) 62 output = self.fc(output[:, -1]) 63 return output, hidden 64 65hidden_size = 10 66model = MyRNN(1, hidden_size) 67optimizer = torch.optim.Adam(model.parameters(), lr=0.002) 68criterion = nn.CrossEntropyLoss() 69 70EPOCHS = 50 71losses = [] 72 73for epoch in range(EPOCHS): 74 75 with tqdm(train_loader) as progress: 76 77 for X, y in progress: 78 optimizer.zero_grad() 79 hidden = model.hidden_initialize(time_series_size) 80 output, hidden = model(X, hidden) 81 loss = criterion(output, y) 82 loss.backward() 83 optimizer.step() 84 85 with torch.no_grad(): 86 acc = (output.argmax(dim=1) == y).sum() / batch_size 87 losses.append(loss.item()) 88 89 progress.set_postfix(acc=acc.item()) 90 91 print("loss: ", loss.item()) 92 print("acc_cal: ", acc.item()) 93 94print(acc.item())
上記コードの Colab リンク
以上のコードを実行しても、正解率は60%を中心に、しかも上下に10%ほど激しく正解率のブレるモデルしか作れずにいます。
loss の推移をプロットした画像
これがまったく何も学習していないようなら諦めて挫折もできるのですが、一応最序盤に少しだけ学習は出来ているようなのでなかなか諦めきれず、私のモデルをどのように改善すれば教材のモデルと同程度の性能のモデルになるかお教えいただきたく思っております。よろしくお願いします。

回答1件
あなたの回答
tips
プレビュー