実現したいこと
Pytorchのneural networkを実装したところ、学習曲線が直線的になる原因が知りたいです。
前提
現在、Python3.7にPytorchを入れて、
https://free.kikagaku.ai/tutorial/basic_of_deep_learning/learn/pytorch_basic
こちらのサイトを参考に、92のパラメータから3つのクラスに分類する2層のneural networkを作成しました。
発生している問題・エラーメッセージ
学習結果は98%程度得られていいのですが、学習曲線を描出すると、直線的になります。
更に検証用、テスト用のデータセットをランしても同様に直線的な結果になります。
バッチサイズも10にしていますが、x軸のサンプルサイズが3,000近くになります。
エラーメッセージ
該当のソースコード
import pandas as pd import numpy as np import torch import torch.nn as nn import torch.nn.functional as F data = pd.read_csv("data.csv", index_col = 0) label=pd.read_csv("label.csv",index_col = 0) data=data.astype('f') label=label.values.astype('i') data=np.array(data,dtype=np.float32) label=label.reshape(-1) x = torch.tensor(data, dtype=torch.float32) t = torch.tensor(label, dtype=torch.int64) print(x.size()) print(t.size()) dataset = torch.utils.data.TensorDataset(x, t) # 各データセットのサンプル数を決定 # train : val: test = 60% : 20% : 20% n_train = int(len(dataset) * 0.6) n_val = int(len(dataset) * 0.2) n_test = len(dataset) - n_train - n_val # ランダムに分割を行うため、シードを固定して再現性を確保 torch.manual_seed(0) # データセットの分割 train, val, test = torch.utils.data.random_split(dataset, [n_train, n_val, n_test]) # バッチサイズ batch_size = 10 # shuffle はデフォルトで False のため、学習データのみ True に指定 train_loader = torch.utils.data.DataLoader(train, batch_size, shuffle=True) val_loader = torch.utils.data.DataLoader(val, batch_size) test_loader = torch.utils.data.DataLoader(test, batch_size) class Net(nn.Module): # 使用するオブジェクトを定義 def __init__(self): super(Net, self).__init__() self.fc1 = nn.Linear(92, 31) self.fc2 = nn.Linear(31, 3) # 順伝播 def forward(self, x): x = self.fc1(x) x = F.relu(x) x = self.fc2(x) return x # 乱数のシードを固定して再現性を確保 torch.manual_seed(0) # インスタンス化 net = Net() criterion = F.cross_entropy optimizer = torch.optim.SGD(net.parameters(), lr=0.1) batch = next(iter(train_loader)) x, t = batch # 予測値の算出 y = net.forward(x) # call メソッドを用いた forward の計算(推奨) y = net(x) # 目的関数の計算 criterion の call メソッドを利用 loss = criterion(y, t) # 全結合層 fc1 の重みに関する勾配 net.fc1.weight.grad # 全結合層 fc1 のバイアスに関する勾配 net.fc1.bias.grad # 全結合層 fc2 の重みに関する勾配 net.fc2.weight.grad # 全結合層 fc2 のバイアスに関する勾配 net.fc2.bias.grad # 勾配の算出 loss.backward() # 勾配の情報を用いたパラメータの更新 optimizer.step() # 演算に使用できる GPU の有無を確認 torch.cuda.is_available() # GPU の設定状況に基づいたデバイスの選択 device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # 指定したデバイスへのモデルの転送 net.to(device) # 指定したデバイスへの入力変数の転送 x = x.to(device) # 指定したデバイスへの目的変数の転送 t = t.to(device) # 勾配情報の初期化 optimizer.zero_grad() # エポックの数 max_epoch = 1 ############################################################# # モデルの初期化 torch.manual_seed(0) # モデルのインスタンス化とデバイスへの転送 net = Net().to(device) # 最適化手法の選択 optimizer = torch.optim.SGD(net.parameters(), lr=0.1) # 学習ループ for epoch in range(max_epoch): for batch in train_loader: # バッチサイズ分のサンプルを抽出 x, t = batch # 学習時に使用するデバイスへデータの転送 x = x.to(device) t = t.to(device) # パラメータの勾配を初期化 optimizer.zero_grad() # 予測値の算出 y = net(x) # 目標値と予測値から目的関数の値を算出 loss = criterion(y, t) # 目的関数の値を表示して確認 # item(): tensot.Tensor => float print('loss: ', loss.item()) # 各パラメータの勾配を算出 loss.backward() # 勾配の情報を用いたパラメータの更新 optimizer.step() # dim=1 で行ごとの最大値に対する要素番号を取得(dim=0 は列ごと) y_label = torch.argmax(y, dim=1) # 予測値から最大となるクラスの番号を取り出した結果 y_label # 正解率 acc = torch.sum(y_label == t) * 1.0 / len(t) acc ####################################################### # モデルの初期化 torch.manual_seed(0) # モデルのインスタンス化とデバイスへの転送 net = Net().to(device) # 最適化手法の選択 optimizer = torch.optim.SGD(net.parameters(), lr=0.1) for epoch in range(max_epoch): for batch in train_loader: x, t = batch x = x.to(device) t = t.to(device) optimizer.zero_grad() y = net(x) loss = criterion(y, t) # New:正解率の算出 y_label = torch.argmax(y, dim=1) acc = torch.sum(y_label == t) * 1.0 / len(t) print('accuracy:', acc) loss.backward() optimizer.step() val_loss_list = [] val_acc_list = [] # 正解率の計算 def calc_acc(data_loader): with torch.no_grad(): for epoch in range(max_epoch): accs = [] # 各バッチごとの結果格納用 val_loss = 0 val_acc = 0 for i, batch in enumerate(data_loader): x, t = batch x = x.to(device) t = t.to(device) y = net(x) loss = criterion(y, t) val_loss += loss.item() val_acc += (y.max(1)[1] == t).sum().item() #y_label = torch.argmax(y, dim=1) #acc = torch.sum(y_label == t) * 1.0 / len(t) #accs.append(acc) avg_val_loss = val_loss / len(data_loader.dataset) avg_val_acc = val_acc / len(data_loader.dataset) print ('Epoch [{}/{}], val_loss: {val_loss:.4f}, val_acc: {val_acc:.4f}' .format(epoch+1, max_epoch, i+1, val_loss=avg_val_loss, val_acc=avg_val_acc)) val_loss_list.append(avg_val_loss) val_acc_list.append(avg_val_acc) # 全体の平均を算出 # avg_acc = torch.tensor(accs).mean() #print('Accuracy: {:.1f}%'.format(avg_acc * 100)) #return avg_acc calc_acc(val_loader) #正解率の書き出し pd.DataFrame(val_acc_list).to_csv("val_acc.csv")

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