Pytorch#

PyTorchはPythonのオープンソースの機械学習・深層学習ライブラリです。

  • 柔軟性を重視した設計であり、さらに、機械学習・深層学習モデルをPythonの慣用的なクラスや関数の取り扱い方で実装できるようになっています。

  • GPUを使用した計算をサポートしますので、CPU上で同じ計算を行う場合に比べて、数十倍の高速化を実現します。

#pip install torch torchvision torchaudio
import torch
import numpy as np

テンソル#

深層学習モデルは通常、入力から出力にどのようにマッピングされるのかを対応つけるデータ構造を表します。一般的に、このようなある形式のデータから別の形式への変換は膨大な浮動小数点数の計算を通じて実現されています。

データを浮動小数点数を扱うためには、Pytorchは基本的なデータ構造として「テンソル」を導入しています。

深層学習の文脈でのテンソルとは、ベクトルや行列を任意の次元数に一般化したものを指します。つまり、多次元配列を扱います。

テンソルの操作#

テンソルの作成#

x = torch.ones(5, 3)
print(x)
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
x = torch.rand(5, 3)
print(x)
tensor([[0.7691, 0.3893, 0.4585],
        [0.9306, 0.9650, 0.6333],
        [0.6451, 0.6950, 0.9526],
        [0.9605, 0.9724, 0.9388],
        [0.5096, 0.7665, 0.2708]])
x = torch.tensor([5.5, 3])
print(x)
tensor([5.5000, 3.0000])

テンソル要素の型#

テンソル要素の型は、引数に適切なdtypeを渡すことで指定します。

double_points = torch.ones(10, 2, dtype=torch.double)
short_points = torch.tensor([[1, 2], [3, 4]], dtype=torch.short)

テンソルの操作(変形・変換等)#

PyTorchにはテンソルに対する操作(変形・演算など)が多く用意されています。

x = torch.rand(5, 3)
y = torch.rand(5, 3)
print(x + y)
tensor([[1.1720, 0.9075, 0.4947],
        [0.7416, 1.1541, 1.5946],
        [0.9672, 1.1217, 0.9681],
        [1.4389, 1.1629, 0.9818],
        [1.1470, 1.2798, 1.4505]])
print(torch.add(x, y))
tensor([[1.1720, 0.9075, 0.4947],
        [0.7416, 1.1541, 1.5946],
        [0.9672, 1.1217, 0.9681],
        [1.4389, 1.1629, 0.9818],
        [1.1470, 1.2798, 1.4505]])

テンソルの一部指定や取り出し(Indexing)#

Pytorchテンソルは、Numpyや他のPythonの科学計算ライブラリーと同じく、テンソルの次元ごとのレンジインデックス記法で一部指定や取り出しを行えます。

x[3:,:]
tensor([[0.5626, 0.5872, 0.1351],
        [0.9063, 0.4152, 0.7680]])
x[1:,0]
tensor([0.2983, 0.7405, 0.5626, 0.9063])

テンソルの微分機能#

PyTorchテンソルは、テンソルに対して実行された計算を追跡し、計算結果の出力テンソルの微分を、各テンソルの要素に対して解析的に計算することができます。

# 微分を計算するためのテンソルを作成
x = torch.tensor(2.0, requires_grad=True)
# 関数の定義
y = x ** 2
# 勾配を計算
y.backward()

# 勾配の値を表示
print(x.grad)  # 4.0 (これは2*xの値、x=2のとき)
tensor(4.)

CUDA Tensors(CUDA テンソル)#

tensorは .to メソッドを使用することであらゆるデバイス上のメモリへと移動させることができます。

if torch.cuda.is_available():
    device = torch.device("cuda")          # a CUDA device object
    y = torch.ones_like(x, device=device)  # directly create a tensor on GPU
    x = x.to(device)                       # or just use strings ``.to("cuda")``
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # ``.to`` can also change dtype together!

学習データセットの作成#

Datasetクラス#

Pytorchで深層学習を実装する際には、特徴量行列とラベルをDatasetというクラスに渡して、特徴量行列とラベルを一つのデータベース的なものにまとめる働きをします。

一般的には、PyTorchのtorch.utils.data.Datasetクラスを継承して定義します。以下に示すメソッドを定義するように指定されています。

  • __init__(self): 初期実行関数です。Datasetを定義する際に必要な情報を受け取ります。

  • __len__(self): データ全体の数を返す関数です。

  • __getitem__(self, index): 指定されたindexに対応するデータと正解ラベル(ターゲット)を返します。

from torch.utils.data import Dataset


class CustomDataset(Dataset):
    def __init__(self, data, labels):
        self.data = data
        self.labels = labels

    def __len__(self):
        # データセットのサイズを返す
        return len(self.data)

    def __getitem__(self, index):
        # 指定されたインデックスのデータとラベルを返す
        return self.data[index], self.labels[index]
# サンプルデータ
data = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
labels = torch.tensor([0, 1, 0])

# カスタムデータセットのインスタンスを作成
dataset = CustomDataset(data, labels)
dataset[0]
(tensor([1., 2.]), tensor(0))

DataLoaderクラス#

機械学習のトレーニングには、データセットのサンプリング、シャッフル、バッチ分割などの操作が必要されます。これらの操作を効率化にするためにDataLoaderクラスが用意されます。

  • バッチ処理: 指定したバッチサイズでデータを分割します

  • シャッフル: データの順序をランダムに並べ替えられます

# サンプルデータ
data = torch.randn(100, 3)  # 100個のデータ、3つの特徴
labels = torch.randint(0, 2, (100,))  # 100個のラベル (0または1)
dataset = CustomDataset(data, labels)
from torch.utils.data import DataLoader

dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
dataloader
<torch.utils.data.dataloader.DataLoader at 0x147ba50d0>
for batch_data, batch_labels in dataloader:
    print("Batch data shape:", batch_data.shape)
    print("Batch labels shape:", batch_labels.shape)
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
Batch data shape: torch.Size([10, 3])
Batch labels shape: torch.Size([10])
# 最初のバッチを取得
data_iter = iter(dataloader)
sample_data, sample_label = next(data_iter)

# 1つ目のサンプルのデータとラベルを確認
print("Sample data:", sample_data[0])
print("Sample label:", sample_label[0])
Sample data: tensor([2.0007, 0.7645, 0.6446])
Sample label: tensor(0)

DataLoaderは反復処理が可能なので、トレーニング中のループで直接に使用することができます。

Note

iter(dataloader)は、DataLoaderオブジェクトからイテレーターを作成します。 イテレーターは順次データを取り出すためのオブジェクトで、forループやnext()を使用して1つずつデータを取得できます。

深層学習モデルの構築#

torch.nnで用意されているクラス、関数は、独自のニューラルネットワークを構築するために必要な要素を網羅しています。

PyTorchの全てのモジュールは、nn.Moduleを継承しています。

そしてニューラルネットワークは、モジュール自体が他のモジュール(レイヤー)から構成されています。

この入れ子構造により、複雑なアーキテクチャを容易に構築・管理することができます。

クラスの定義#

nn.Moduleを継承し、独自のネットワークモデルを定義し、その後ネットワークのレイヤーを __init__で初期化します。

nn.Module を継承した全モジュールは、入力データの順伝搬関数であるforward関数を持ちます。

from torch import nn
class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(512, 128),
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Linear(128, 3),
            nn.ReLU()
        )

    def forward(self, x):
        logits = self.linear_relu_stack(x)
        return logits

このクラスは、PyTorchのnn.Moduleを継承した単純なニューラルネットワークの実装を示しています。入力は固定長の\(512\)とされており、出力は\(3\)の次元を持つベクトルです。

  • self.linear_relu_stack: このシーケンシャルな層は、3つの線形層とそれぞれの後に続くReLU活性化関数から構成されています。

    • nn.Sequentialにレイヤーを順に渡すだけで、数のレイヤーを順に積み重ねたモデルを簡単に定義できます。

    • linear layerは、線形変換を施します。linear layerは重みとバイアスのパラメータを保持しています。

    • nn.ReLUという活性化関数を設置することで、ニューラルネットワークの表現力を向上させます。

  • 順伝播メソッド (forward): 入力テンソルxを受け取り、ネットワークを通して出力を生成する機能を持ちます。

GPUの利用#

NeuralNetworkクラスのインスタンスを作成し、変数device上に移動させます。

以下でネットワークの構造を出力し確認します。

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('Using {} device'.format(device))
Using cpu device
model = NeuralNetwork().to(device)
print(model)
NeuralNetwork(
  (linear_relu_stack): Sequential(
    (0): Linear(in_features=512, out_features=128, bias=True)
    (1): ReLU()
    (2): Linear(in_features=128, out_features=128, bias=True)
    (3): ReLU()
    (4): Linear(in_features=128, out_features=3, bias=True)
    (5): ReLU()
  )
)

モデルによる計算#

  • ニューラルネットワークの最後のlinear layerはlogitsを出力します。このlogitsnn.Softmaxモジュールへと渡されます。出力ベクトルの要素の値は\([0, 1]\)の範囲となり、これは各クラスである確率を示します。

X = torch.rand(3, 512, device=device)
logits = model(X) 
print(logits)
tensor([[0.0000, 0.0000, 0.0422],
        [0.0000, 0.0000, 0.0234],
        [0.0000, 0.0000, 0.0727]], grad_fn=<ReluBackward0>)
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
Predicted class: tensor([2, 2, 2])

自動微分#

ニューラルネットワークを訓練する際、その学習アルゴリズムとして、バックプロパゲーション(back propagation) がよく使用されます。

バックプロパゲーションでは、モデルの重みなどの各パラメータは、損失関数に対するその変数の微分値(勾配)に応じて調整されます。

これらの勾配の値を計算するために、PyTorchにはtorch.autograd という微分エンジンが組み込まれています。

autogradはPyTorchの計算グラフに対する勾配の自動計算を支援します。

シンプルな1レイヤーのネットワークを想定しましょう。

入力をx、パラメータをwb、そして適切な損失関数を決めます。


PyTorchでは例えば以下のように実装します。

import torch

x = torch.rand(5)  # input tensor
y = torch.zeros(3)  # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)

勾配情報の保存#

こののニューラルネットワークでは、wbが最適したいパラメータです。

そのため、これらの変数に対する損失関数の微分値を計算する必要があります。

これらのパラメータで微分を可能にするために、requires_grad属性をこれらのテンソルに追記します。

そうすると、勾配は、テンソルの grad_fn プロパティに格納されます。

print('Gradient function for z =',z.grad_fn)
print('Gradient function for loss =', loss.grad_fn)
Gradient function for z = <AddBackward0 object at 0x1071b59c0>
Gradient function for loss = <BinaryCrossEntropyWithLogitsBackward0 object at 0x1071b59c0>

勾配計算#

ニューラルネットワークの各パラメータを最適化するために、入力xと出力yが与えられたもとで、損失関数の各変数の偏微分値、

すなわち

\(\frac{\partial loss}{\partial w}\)\(\frac{\partial loss}{\partial b}\)

を求める必要があります。

これらの偏微分値を求めるためにloss.backward()を実行し、w.gradb.gradの値を導出します。

逆伝搬では、.backward()がテンソルに対して実行されると、autogradは、

  • 各変数の .grad_fnを計算する

  • 各変数の.grad属性に微分値を代入する

  • 微分の連鎖律を使用して、各leafのテンソルの微分値を求める

を行います。

loss.backward()
print(w.grad)
print(b.grad)
tensor([[0.1130, 0.0217, 0.1649],
        [0.1691, 0.0324, 0.2466],
        [0.1606, 0.0308, 0.2343],
        [0.1831, 0.0351, 0.2670],
        [0.1226, 0.0235, 0.1788]])
tensor([0.1926, 0.0369, 0.2809])

最適化ループを構築し、Pytorchより自動的に逆伝播

import torch.nn.functional as F

def training_loop(n_epochs, learning_rate, model, input, target):
    for epoch in range(1, n_epochs + 1):
        # Forward pass
        outputs = model(input)
        
        # Compute the loss using Binary Cross Entropy with Logits
        loss = F.binary_cross_entropy_with_logits(outputs, target)
        
        # Backward pass
        loss.backward()
        
        # Update the parameters
        with torch.no_grad():
            for param in model.parameters():
                param -= learning_rate * param.grad
        model.zero_grad()
        # Zero the parameter gradients after updating 
        if epoch % 100 == 0:
            print(f"Epoch {epoch}, Loss: {loss.item()}")

    return model
# Example usage (with dummy data)
input = torch.rand(10, 512)  # 10 samples with 512 features each
target = torch.rand(10, 3)  # 10 samples with 3 target values each

n_epochs = 500
learning_rate = 0.01
model = NeuralNetwork()

trained_model = training_loop(n_epochs, learning_rate, model, input, target)
Epoch 100, Loss: 0.6875591278076172
Epoch 200, Loss: 0.6831498742103577
Epoch 300, Loss: 0.6800097823143005
Epoch 400, Loss: 0.6770234704017639
Epoch 500, Loss: 0.6738294959068298

Note

PyTorchの勾配計算メカニズムでは、.backwardを呼び出すと、リーフノードで導関数の計算結果が累積されます。つまり、もし.backwardが以前にも呼び出されていた場合、損失関数が再び計算され、.backwardも再び呼び出され、各リーフの勾配が前の反復で計算された結果の上に累積されます。その結果、勾配の値は誤ったものになります。

このようなことが起こらないようにするためには、反復のルーブのたびにmodel.zero_grad()を用いて明示的に勾配をゼロに設定する必要があります。

最適化関数#

最適化は各訓練ステップにおいてモデルの誤差を小さくなるように、モデルパラメータを調整するプロセスです。

ここまでの説明は、単純な勾配下降法を最適化に使用しました。これは、シンプルなケースでは問題なく機能しますが、モデルが複雑になったときのために、パラメータ学習の収束を助ける最適化の工夫が必要されます。

Optimizer#

optimというモジュールには、様々な最適化アルゴリズムが実装されています。

ここでは、確率的勾配降下法(Stochastic Gradient Descent)を例として使い方を説明します。

確率的勾配降下法は、ランダムに選んだ1つのデータのみで勾配を計算してパラメータを更新し、データの数だけ繰り返す方法です。

訓練したいモデルパラメータをoptimizerに登録し、合わせて学習率をハイパーパラメータとして渡すことで初期化を行います。訓練ループ内で、最適化(optimization)は3つのステップから構成されます。

  • optimizer.zero_grad()を実行し、モデルパラメータの勾配をリセットします。勾配の計算は蓄積されていくので、毎イテレーション、明示的にリセットします。

  • 続いて、loss.backwards()を実行し、バックプロパゲーションを実行します。PyTorchは損失に対する各パラメータの偏微分の値(勾配)を求めます。

  • 最後に、optimizer.step()を実行し、各パラメータの勾配を使用してパラメータの値を調整します。

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
def training_loop(n_epochs, learning_rate, model, input, target):
    # Use Binary Cross Entropy with Logits as the loss function
    
    # Use Adam as the optimizer
    optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
    
    for epoch in range(1, n_epochs + 1):
        # Zero the parameter gradients
        optimizer.zero_grad()
        
        # Forward pass
        outputs = model(input)
        loss = F.binary_cross_entropy_with_logits(outputs, target)
        
        # Backward pass and optimize
        loss.backward()
        optimizer.step()

        # Print loss every 100 epochs
        if epoch % 100 == 0:
            print(f"Epoch {epoch}, Loss: {loss.item()}")

    return model
input = torch.rand(10, 512)  # 10 samples with 512 features each
target = torch.rand(10, 3)  # 10 samples with 3 target values each

n_epochs = 1000
learning_rate = 0.001
model = NeuralNetwork()

trained_model = training_loop(n_epochs, learning_rate, model, input, target)
Epoch 100, Loss: 0.6915722489356995
Epoch 200, Loss: 0.6911361813545227
Epoch 300, Loss: 0.6907067894935608
Epoch 400, Loss: 0.6902722716331482
Epoch 500, Loss: 0.6898691654205322
Epoch 600, Loss: 0.6894822716712952
Epoch 700, Loss: 0.6891085505485535
Epoch 800, Loss: 0.6887398362159729
Epoch 900, Loss: 0.6883582472801208
Epoch 1000, Loss: 0.6879760026931763

Pytorchによる深層学習の実装例#

データの読み込み#

import pandas as pd
train_df = pd.read_csv('./Data/Titanic/train.csv')
train_df.head()
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
test_df = pd.read_csv('./Data/Titanic/test.csv')
test_df.head()
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 892 3 Kelly, Mr. James male 34.5 0 0 330911 7.8292 NaN Q
1 893 3 Wilkes, Mrs. James (Ellen Needs) female 47.0 1 0 363272 7.0000 NaN S
2 894 2 Myles, Mr. Thomas Francis male 62.0 0 0 240276 9.6875 NaN Q
3 895 3 Wirz, Mr. Albert male 27.0 0 0 315154 8.6625 NaN S
4 896 3 Hirvonen, Mrs. Alexander (Helga E Lindqvist) female 22.0 1 1 3101298 12.2875 NaN S
print(train_df.dtypes)
PassengerId      int64
Survived         int64
Pclass           int64
Name            object
Sex             object
Age            float64
SibSp            int64
Parch            int64
Ticket          object
Fare           float64
Cabin           object
Embarked        object
dtype: object

データの前処理#

  • 列の削除: 要らない列を消していきます.乗客IDや名前,チケット,港(Embarked)や部屋番号(Cabin)はは生死にあまり関係がなさそうので、削除します。

  • 欠損の補完: 平均値で欠損しているデータを補完します。

  • 文字列を数字に置換

def process_df(df):
    df = df.drop(["PassengerId", "Name", "Ticket", "Cabin", "Embarked"], axis=1)
    df["Age"] = df["Age"].fillna(df["Age"].mean())
    df = df.replace("male", 0)
    df = df.replace("female", 1)
    return df

train_df = process_df(train_df)
test_df = process_df(test_df)
train_df.head()
Survived Pclass Sex Age SibSp Parch Fare
0 0 3 0 22.0 1 0 7.2500
1 1 1 1 38.0 1 0 71.2833
2 1 3 1 26.0 0 0 7.9250
3 1 1 1 35.0 1 0 53.1000
4 0 3 0 35.0 0 0 8.0500

データセットの作成#

データセットとデータローダーでミニバッチ学習ためのデータセットを作成します。

features = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare"]
X = train_df[features]
y = train_df["Survived"]
from sklearn.model_selection import train_test_split

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
class TitanicDataset(Dataset):
    def __init__(self, X, y):
        # DataFrameをNumPy配列に変換
        self.X = torch.tensor(X.values, dtype=torch.float32)  # XをNumPy配列に変換してからテンソル化
        self.y = torch.tensor(y.values, dtype=torch.float32)  # yも同様にテンソル化

    def __len__(self):
        return len(self.y)

    def __getitem__(self, idx):
        return self.X[idx], self.y[idx]
# データローダーの作成
train_dataset = TitanicDataset(X_train, y_train)
val_dataset = TitanicDataset(X_val, y_val)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)
train_dataset[0]
(tensor([ 1.0000,  0.0000, 45.5000,  0.0000,  0.0000, 28.5000]), tensor(0.))

モデルの定義#

__init__で行列の掛け算の定義をして,forwardでそれをどの順番で行うかを指定する感じです.

class TitanicModel(nn.Module):
    def __init__(self, input_size):
        super(TitanicModel, self).__init__()
        self.fc1 = nn.Linear(input_size, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = torch.sigmoid(self.fc3(x))
        return x

モデルの学習#

損失関数は2乗誤差、最適化関数はAdamを使用します.

import torch.optim as optim


def train_model(model, train_loader, val_loader, n_epochs, learning_rate):
    criterion = nn.BCELoss()  # 分類の損失関数
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)

    for epoch in range(n_epochs):
        model.train()
        train_loss = 0.0
        for X_batch, y_batch in train_loader:
            optimizer.zero_grad()
            outputs = model(X_batch).squeeze()
            loss = criterion(outputs, y_batch)
            loss.backward()
            optimizer.step()
            train_loss += loss.item() * X_batch.size(0)

        # 検証データでの評価
        model.eval()
        val_loss = 0.0
        with torch.no_grad():
            for X_batch, y_batch in val_loader:
                outputs = model(X_batch).squeeze()
                loss = criterion(outputs, y_batch)
                val_loss += loss.item() * X_batch.size(0)
        # 訓練と検証の損失をデータセットのサイズで割り、平均損失を計算します
        train_loss /= len(train_loader.dataset) 
        val_loss /= len(val_loader.dataset)
        if epoch % 10 == 0:
            print(f"Epoch {epoch+1}/{n_epochs}, Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}")
model = TitanicModel(input_size=X_train.shape[1])
train_model(model, train_loader, val_loader, n_epochs=100, learning_rate=0.001)
Epoch 1/100, Train Loss: 0.6814, Val Loss: 0.5866
Epoch 11/100, Train Loss: 0.5715, Val Loss: 0.5519
Epoch 21/100, Train Loss: 0.5041, Val Loss: 0.4909
Epoch 31/100, Train Loss: 0.4537, Val Loss: 0.4288
Epoch 41/100, Train Loss: 0.4637, Val Loss: 0.4511
Epoch 51/100, Train Loss: 0.4327, Val Loss: 0.4278
Epoch 61/100, Train Loss: 0.4192, Val Loss: 0.4218
Epoch 71/100, Train Loss: 0.4175, Val Loss: 0.4248
Epoch 81/100, Train Loss: 0.4210, Val Loss: 0.4301
Epoch 91/100, Train Loss: 0.4252, Val Loss: 0.4311

モデルの評価#

from sklearn.metrics import classification_report

def evaluate_model(model, loader):
    model.eval()
    predictions = []
    true_labels = []
    
    with torch.no_grad():
        for X_batch, y_batch in loader:
            outputs = model(X_batch).squeeze()
            # 出力を0または1に丸める
            predicted_classes = outputs.round().numpy()
            predictions.extend(predicted_classes)
            true_labels.extend(y_batch.numpy())

    # レポートの表示
    print(classification_report(true_labels, predictions, target_names=["Did not survive", "Survived"],digits=4))
# モデルの評価を実行
evaluate_model(model, val_loader)
                 precision    recall  f1-score   support

Did not survive     0.8058    0.7905    0.7981       105
       Survived     0.7105    0.7297    0.7200        74

       accuracy                         0.7654       179
      macro avg     0.7582    0.7601    0.7590       179
   weighted avg     0.7664    0.7654    0.7658       179

深層学習の実装を以下の指示に従って、改めて学習を行なってください。

  • バッチサイズを64に変更しなさい

  • モデルに一つ隠れ層を追加しなさい

  • ドロップアウト層を追加しなさい

  • オプティマイザはAdamWを設定しなさい

  • epochを増やしんさい