絶賛pytorch勉強中の人間の備忘録です。
あるデータに対しては動いていたはずの学習/検証のための関数を別のデータに適用したらCrossEntropyLoss()
の部分がmulti-target not supported at なんちゃら/ClassNLLCriterion.cu:15
というエラーを吐くようになりました。
修正前
(不慣れで冗長なコードですすみません・・・・)
train_valid_loop.pyの一部
def train_valid_loop(
train_loader, valid_loader, valid_data_tensor, valid_label_tensor, model,
n_epoch, optimizer):
train_acc_list = []
train_loss_list = []
valid_acc_list = []
valid_loss_list = []
auc_score_list = []
for epoch in range(n_epoch):
train_loss = 0
train_acc = 0
valid_loss = 0
valid_acc = 0
best_auc_score = 0
model.train()
for xt, yt in train_loader:
xt = xt.to(device)
yt = yt.to(device)
y_pred = model.forward(xt)
loss = loss_fn(y_pred, yt)
# errorの原因はここ↑
# どういうわけかこの第2引数をyvのまま入力すると
# multi-target(?)だと怒られる
train_loss += loss.item() * xt.size(0)
train_acc += (y_pred.max(1)[1] == yt).sum().item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
avg_train_loss = train_loss / len(train_loader.dataset)
avg_train_acc = train_acc / len(train_loader.dataset)
model.eval()
with torch.no_grad():
for xv, yv in valid_loader:
xv = xv.to(device)
yv = yv.to(device)
y_pred = model.forward(xv)
loss = loss_fn(y_pred, yv)
# 同上のエラー
valid_loss += loss.item() * xv.size(0)
valid_acc += (y_pred.max(1)[1] == yv).sum().item()
avg_valid_loss = valid_loss / len(valid_loader.dataset)
avg_valid_acc = valid_acc / len(valid_loader.dataset)
if epoch == 0 or (epoch + 1 ) % 10 == 0:
train_acc_list.append(avg_train_acc)
train_loss_list.append(avg_train_loss)
valid_acc_list.append(avg_valid_acc)
valid_loss_list.append(avg_valid_loss)
# 出来たモデルでauc scoreを計算
_,prediction = torch.max(
model.forward(valid_data_tensor.to(device)),dim=1)#fold全体の予測値
# tensor配列からnumpy配列に戻すときはdetach()を挟む必要アリ
auc_score = roc_auc_score(valid_label_tensor.detach().numpy().copy(),prediction.to('cpu').detach().numpy().copy())
if auc_score > best_auc_score:
model_path = 'model_pth'
torch.save(model.state_dict(), model_path)
auc_score_list.append(auc_score)
return train_acc_list, train_loss_list, valid_acc_list, valid_loss_list, auc_score_list
解決策
元のpd.DataFrameの訓練用ラベルをtensorに変換する手順で次元に冗長な部分があったっぽい?です。データの整形が甘かったのかも。
よってただ単に損失関数を計算する前に正解ラベルyt,yv
をsqueeze_()
にぶち込む。
# 該当箇所1
yt = yt.squeeze_()
loss = loss_fn(y_pred, yt)
# 該当箇所2
yv = yv.squeeze_()
loss = loss_fn(y_pred, yv)
これで正常に動いてくれました。