はじめに
前回はChatGPTにpytorchで簡単なAIを実装させ、前処理について簡単に調査しました。
今回は前回のコードの中でモデル部分について調査してみたいと思います。
pytorchのモデルについて調べてみた
ChatGPTに聞いたコード全体
まずは前回のコードの全体から
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch.utils.data import DataLoader, TensorDataset
# Iris データセットの読み込み
iris = load_iris()
X, y = iris.data, iris.target
# データの前処理
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# PyTorchのテンソルに変換
X_train = torch.tensor(X_train, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_test = torch.tensor(y_test, dtype=torch.long)
# データローダーの作成
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
# ニューラルネットワークの定義
class IrisNet(nn.Module):
def __init__(self):
super(IrisNet, self).__init__()
self.fc1 = nn.Linear(4, 64)
self.fc2 = nn.Linear(64, 64)
self.fc3 = nn.Linear(64, 3)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
model = IrisNet()
# 損失関数とオプティマイザ
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# トレーニングプロセス
def train(model, criterion, optimizer, train_loader, epochs=100):
for epoch in range(epochs):
for inputs, targets in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
if epoch % 10 == 0:
print(f"Epoch {epoch}/{epochs}, Loss: {loss.item()}")
train(model, criterion, optimizer, train_loader)
# テストデータで評価
with torch.no_grad():
outputs = model(X_test)
_, predicted = torch.max(outputs, 1)
accuracy = (predicted == y_test).sum().item() / y_test.size(0)
accuracy
pytorchのモデルの定義を調べてみた
全体のコードの中でモデルに当たる部分は以下の箇所です。
# ニューラルネットワークの定義
class IrisNet(nn.Module):
def __init__(self):
super(IrisNet, self).__init__()
self.fc1 = nn.Linear(4, 64)
self.fc2 = nn.Linear(64, 64)
self.fc3 = nn.Linear(64, 3)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
すごく難しそうです…
では読み解いてみましょう。さて
モデルの定義
class IrisNet(nn.Module):
def __init__(self):
super(IrisNet, self).__init__()
が分らん。まずはnn.Moduleからこちらによると決まり文句のようです。ただ、super(…)とも関係しているようでこちらの記事と合わせるとnn.Moduleというpytorchに含まれているモジュールを継承してきて、そのinitを引き継いでいるようです。まぁ、決まり文句ということで
ニューロンの定義
次は
self.fc1 = nn.Linear(4, 64)
self.fc2 = nn.Linear(64, 64)
self.fc3 = nn.Linear(64, 3)
ですね。よくわからなけど数字を見るとニューロンに見えます。
4が入力層、64が隠れ層のニューロン数、3が出力層
のように見えます。前回の前処理で入力ががく片と花弁の長さ、幅でしたので、入力層は4。あやめの種類が3だったので出力層が3になってます。これはニューロン数で確定ですね。
図で書くとこんな感じ
順伝播の定義
次はこれ
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
return self.fc3(x)
forwardが書いてあるので、順伝播なのでしょう。きっと
となると、self.fc1というのが、上で定義したニューロンなので、xで入力されて活性化関数reluで出力し、さらにself.fc2の入力になって、またreluで出力し、最後にself.fc3を通して活性化関数なしで出力するという流れでしょうか
すごく分かりやすい順伝播ですね。
では、逆伝播はどこにあるのでしょうか?
後々のコードをみるとloss.backward()とあるので、こちらで何か行っているのでしょう。
そのときが来たら調べてみます。
コメント