今回は、ニューラルネットワークを作って動かしてみた。
アヤメの形状データを入力してその種類を推定するというものなんだけど、具体的にどういう仕組みなのかいまいちよくわからない。
nnの中の演算は、活性化関数というものがあって、f(入力値*重み+バイアス)という演算をして種類を推定するということらしい。 最初にある手順で重みとバイアスの初期値を設定し、学習データと答えを参照して重みとバイアスを修正していくようだ。
で、実際にコーディングして、重みとバイアスの変化、5つのアヤメのデータを入れた時に答えが一致するかを見てみた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split import torch from torch import nn INPUT_FEATURES = 4 HIDDEN = 5 OUTPUT_FEATURES = 1 # ニューラルネットワークのクラス class Net(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(INPUT_FEATURES, HIDDEN) self.fc2 = nn.Linear(HIDDEN, OUTPUT_FEATURES) def forward(self, x): x = self.fc1(x) x = torch.sigmoid(x) x = self.fc2(x) return x # scikit-learnからアヤメのデータをロード iris = load_iris() X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target) # scikit-learnのデータをPytorchのデータに変換 X_train = torch.from_numpy(X_train).float() y_train = torch.tensor([[float(x)] for x in y_train]) X_test = torch.from_numpy(X_test).float() y_test = torch.tensor(([[float(x)] for x in y_test])) # 重みとバイアスの初期値を表示 net = Net() print(f'initial weight: {net.fc1.weight}') print(f'initial bias: {net.fc1.bias}') criterion = nn.MSELoss() optimizer = torch.optim.SGD(net.parameters(), lr=0.003) # アヤメのデータを使って学習を3000回行う EPOCHS = 3000 for epoch in range(EPOCHS): optimizer.zero_grad() outputs = net(X_train) loss = criterion(outputs, y_train) loss.backward() optimizer.step() if epoch == 2999: # 学習後の重みとバイアスの値を出力 print(f'weight: {net.fc1.weight}') print(f'bias: {net.fc1.bias}') # 学習後のnnの出力と答えを表示 for idx, item in enumerate(zip(outputs, y_train)): if idx == 5: break print(item[0].data, ':', item[1]) |
結果
重みとバイアスは、確かに変化しているけど思ったより変化が少ない。
最後の5行は答え合わせだけど、左が計算結果で右が答え。
四捨五入すると、答えが0と1の時は一致するけど2の時は1と間違っている。
学習回数を増やすとか、データ数を増やせば精度があがるのだろう。
とりあえずPytorchでRNNが動かせたし、ニューラルネットワークがちょこっとだけ理解できたかな..