質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1005閲覧

Keras による RNN 実装サンプルを PyTorch で実装したいが上手くいかない

JavaTea

総合スコア29

Keras

Kerasは、TheanoやTensorFlow/CNTK対応のラッパーライブラリです。DeepLearningの数学的部分を短いコードでネットワークとして表現することが可能。DeepLearningの最新手法を迅速に試すことができます。

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

PyTorch

PyTorchは、オープンソースのPython向けの機械学習ライブラリ。Facebookの人工知能研究グループが開発を主導しています。強力なGPUサポートを備えたテンソル計算、テープベースの自動微分による柔軟なニューラルネットワークの記述が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2023/04/08 11:15

実現したいこと

ここに実現したいことを箇条書きで書いてください。

前提

現在、東京大学松尾研究室が公開している、機械学習・深層学習の教材 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 の推移をプロットした画像loss の推移をプロットした画像

これがまったく何も学習していないようなら諦めて挫折もできるのですが、一応最序盤に少しだけ学習は出来ているようなのでなかなか諦めきれず、私のモデルをどのように改善すれば教材のモデルと同程度の性能のモデルになるかお教えいただきたく思っております。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PondVillege

2023/04/08 12:54

Kerasの方と比べて,学習率が2倍あります.スケジューラ等を用いながら減少させたりするのはどうでしょう.もしくはnn.RNNのbatch_firstがFalseだから変な学習しているとか.
JavaTea

2023/04/08 14:09

コメントありがとうございます。 お教え頂いた通り、まさにnn.RNN の batch_first=True を指定してない点が問題でした。 batch_first に True を指定、学習率を 0.001 に変更、hidden テンソル初期化メソッドに渡す値をデータの時系列サイズからバッチサイズに変更することで、テストデータに対して正解率90%近いモデルにすることが出来ました。ありがとうございました! ご教示頂いた内容、回答欄の方に書き込んで頂けましたら、ベストアンサーに指定しスレッド解決済みとさせて頂きたく思います。
guest

回答1

0

ベストアンサー

学習率の不一致とnn.RNNがデフォルトでbatch_first=Falseであることの差異によるものと考えられる.

diff

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.rnn = nn.RNN(input_size, hidden_size, batch_first=True) 56 self.fc = nn.Linear(hidden_size, 5) 57 58 def hidden_initialize(self, time_series_size): 59 return torch.zeros((self.num_rnn_layers, time_series_size, self.hidden_size)) 60 61 def forward(self, x, hidden): 62 output, hidden = self.rnn(x, hidden) 63 output = self.fc(output[:, -1]) 64 return output, hidden 65 66hidden_size = 10 67model = MyRNN(1, hidden_size) 68-optimizer = torch.optim.Adam(model.parameters(), lr=0.002) 69+optimizer = torch.optim.Adam(model.parameters(), lr=0.001) 70criterion = nn.CrossEntropyLoss() 71 72EPOCHS = 50 73losses = [] 74 75for epoch in range(EPOCHS): 76 77 with tqdm(train_loader) as progress: 78 79 for X, y in progress: 80 optimizer.zero_grad() 81 hidden = model.hidden_initialize(time_series_size) 82 output, hidden = model(X, hidden) 83 loss = criterion(output, y) 84 loss.backward() 85 optimizer.step() 86 87 with torch.no_grad(): 88 acc = (output.argmax(dim=1) == y).sum() / batch_size 89 losses.append(loss.item()) 90 91 progress.set_postfix(acc=acc.item()) 92 93 print("loss: ", loss.item()) 94 print("acc_cal: ", acc.item()) 95 96print(acc.item())

投稿2023/04/08 14:32

PondVillege

総合スコア1579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JavaTea

2023/04/08 14:42

ありがとうございます、本当に助かりました!
PondVillege

2023/04/08 14:54

n値分類の精度1/nはRandom Choiceの精度なのでデータの取り回しあたりで具合悪そうだと考えてました.当たっててよかったです.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問