【機械学習】Pytorchでニューラルネットワークモデルを構築(シンプルなやつ)
機械学習では、
性質の違うモデルを組み合わせることで
高い精度を出すことができます。
このように複数のモデルを組み合わせることを
アンサンブルと言います。
ニューラルネットワークモデル(NNモデル)は、
画像解析や自然言語処理では高い精度を
発揮しますが、
機械学習でよくあるテーブルデータとなると、
精度はイマイチです。
しかしながら、NNモデルも、
アンサンブルの一つとして使うと
高い精度を発揮してくれることがあります。
特にブースティング系のモデルと組み合わせることで
高い精度が発揮されることが多いようです。
ここでは、アンサンブル用に、
シンプルなNNモデルを
構築する方法についてご紹介します。
フレームワークはPytorchを使います。
なお、データ分割においては、
クロスバリデーションを取り入れています。
NNモデルを構築するにあたっての注意点
ニューラルネットワークモデルを構築する際には、以下の点に注意する必要があります。
数値化: データは数値形式に変換する必要があります。文字列やカテゴリデータをそのまま扱えません、それらを適切に数値に変換することが求められます。
欠損値の処理: 欠損値を扱うことができません。データセットに欠損値が含まれている場合、それらを適切に処理する必要があります。
標準化・正規化: データの尺度を揃えるために、標準化や正規化を行うことが重要です。これにより、モデルは異なる尺度の特徴間で均衡を保つことができます。
ライブラリーのインポート
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset, TensorDataset, Subset
from sklearn.metrics import f1_score
from sklearn.model_selection import KFold
import numpy as np
import pandas as pd
データの準備など
ここから、Pytorchで処理できるよう
データを揃えていきます。
ここでは、学習用にtrain_df_nn、テスト用にtest_df_nnを用意します。
”MIS_Status”がターゲットとします(二値分類タスク)
あらかじめ、欠損値は処理しているものとします。
❶データフレームの数値化
train_df_nn = train_df_nn.select_dtypes(include=["int","float"]).drop("MIS_Status",axis=1)
test_df_nn = test_df_nn.select_dtypes(include=["int","float"])
features = train_df_nn.columns
❷データの標準化
# 訓練データだけで標準化を行う
scaler = StandardScaler()
train_df_sc = scaler.fit_transform(train_df_nn)
# テストデータに対しても、訓練データの平均、標準偏差を用いて標準化を行う
test_df_sc = scaler.transform(test_df_nn)
❸tensor化
# トレーニングデータの準備(例)
train_features = torch.tensor(train_df_sc,dtype=torch.float32) # トレーニングデータの特徴量
train_labels = torch.tensor(train_df_nn_load["MIS_Status"].values,dtype=torch.int64) # トレーニングデータのラベル
train_labels = train_labels.unsqueeze(1)
train_dataset = torch.utils.data.TensorDataset(train_features,train_labels)
ニューラルネットワークモデルの定義
超シンプルなモデルを作ります。
3層構造です。
それぞれの層で標準化を行います。
活性化関数にはReluを使用しています。
class BinaryClassificationModel(nn.Module):
def __init__(self, num_features):
super(BinaryClassificationModel, self).__init__()
self.layer_1 = nn.Linear(num_features, 64)
self.layer_2 = nn.Linear(64, 32)
self.layer_out = nn.Linear(32, 1)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(p=0.1)
self.batchnorm1 = nn.BatchNorm1d(64)
self.batchnorm2 = nn.BatchNorm1d(32)
def forward(self, x):
x = self.relu(self.layer_1(x))
x = self.batchnorm1(x)
x = self.dropout(x)
x = self.relu(self.layer_2(x))
x = self.batchnorm2(x)
x = self.dropout(x)
x = torch.sigmoid(self.layer_out(x))
return x
学習の実行
通常の機械学習のモデルと同じような実装になります。
ここでは評価指標としてMean F1スコアを用いています。
Pytorchでクロスバリデーションを行う際には、
Subsetを使う必要があります。
# クロスバリデーションの設定
n_splits = 7 # 分割数
kf = KFold(n_splits=n_splits)
# Mean F1スコアの初期化
mean_f1_score = 0
oof_predictions = np.zeros(len(train_df_nn))
models = []
# クロスバリデーション
for train_index, valid_index in kf.split(train_dataset):
# トレーニングデータとバリデーションデータに分割
train_subset = Subset(train_dataset, train_index)
valid_subset = Subset(train_dataset, valid_index)
# データローダーの作成
train_dataloader = DataLoader(train_subset, batch_size=32, shuffle=True)
valid_dataloader = DataLoader(valid_subset, batch_size=32, shuffle=False)
# モデルの初期化
model = BinaryClassificationModel(num_features=train_features.shape[1])
# 損失関数とオプティマイザの設定
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# トレーニングループ
num_epochs = 10
for epoch in range(num_epochs):
for inputs, labels in train_dataloader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels.float())
loss.backward()
optimizer.step()
# 予測
predictions = []
true_labels = []
model.eval()
with torch.no_grad():
for inputs, labels in valid_dataloader:
outputs = model(inputs)
predictions.extend(outputs.tolist())
true_labels.extend(labels.tolist())
oof_predictions[valid_index] = np.array(predictions).flatten()
models.append(model)
# F1スコアの計算
f1 = f1_score(true_labels, [1 if p[0] > 0.5 else 0 for p in predictions],average="macro")
print(f"Mean F1 Score_fold: {f1}")
# Mean F1スコアの更新
mean_f1_score += f1 / n_splits
oof_df_nn = pd.DataFrame({"nn_pred":oof_predictions,"MIS_Status":train_df_nn_load["MIS_Status"]})
cm = confusion_matrix(train_df_nn_load["MIS_Status"], np.round(oof_predictions))
plt.figure(figsize=(5, 5))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues")
plt.title(f'Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()
# Mean F1スコアの出力
print(f"Mean F1 Score: {mean_f1_score}")
推論
テストデータを使って推論します
test = torch.tensor(test_df_sc,dtype=torch.float32)
pred = torch.zeros(len(test), dtype=torch.float32)
with torch.no_grad():
for model in models:
model.eval()
output = model(test)
# ここでoutputの形状を調整
output = output.squeeze() # 余分な次元がある場合は削除
# outputが複数の特徴量を持つ場合、適切な処理を行う
pred += output
pred /= len(models)
pred_np = pred.numpy()
よろしければサポートお願いします! いただいたサポートはクリエイターとしての活動費に使わせていただきます!