■
本日もパイトーチの続き。
今日からNN型のシンプルなモデルの勉強。
データセットはSklearnにデフォルトで入っているwineのデータセットを使う
今回は下の図のネットワークを作る。
全コード
#ライブラリ import torch #自動で計算してくれる from torch.autograd import Variable import torch.nn as nn #様々な関数 import torch.nn.functional as F import torch.optim as optim #DataLoader -> 撥サイズ決める時に必要 #TensorDataset -> トレーニング用データをまとめてくれる from torch.utils.data import DataLoader , TensorDataset from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split import pandas as pd #ワインデータセットのロード #wine_keys -> (['data', 'target', 'target_names', 'DESCR', 'feature_names']) wine = load_wine() #2種類のワイン情報(特徴は13項目にも及ぶ) wine_data = wine.data[0:130] #ワインの種類 → 今回は2種類に wine_target = wine.target[0:130] #学習用、テスト用に切り分けてくれる x_train , x_test , y_train , y_test = train_test_split(wine_data , wine_target , test_size = 0.25) #array形式をtensor形式に変換 #数がばらばらのため、浮動小数点数に x_train = torch.from_numpy(x_train).float() x_test = torch.from_numpy(x_test).float() #整数 y_train = torch.from_numpy(y_train).long() y_test = torch.from_numpy(y_test).long() #テンソル形式のトレーニングデータにする train_data = TensorDataset(x_train , y_train) #バッチサイズの設定 → 学習させるときにどれくらいまとめてやりますか? #DataLoader(学習させたいデータ , バッチサイズ数 , ごちゃまぜにする?-> YES) train_loader = DataLoader(train_data , batch_size = 15 , shuffle= True) """ モデル定義 """ class Net(nn.Module): #単純にレイヤーを作る def __init__(self): #親クラスをそのまま継承する super(Net , self).__init__() #第1層-第2層 self.fc1 = nn.Linear(13 , 128) #第2層-第3層 self.fc2 = nn.Linear(128 , 2) #重みをかけていtte def forward(self , x): x = F.relu(self.fc1(x)) x = self.fc2(x) #それぞれ0 , 1 の確率を出す return F.log_softmax(x , dim=0) model = Net() """ トレーニングの実行 """ #正解と、出力の差分算出方法 criterion = nn.CrossEntropyLoss() #差分を埋めるのに必要な値は?を計算してくれる opt = optim.SGD(model.parameters() , lr = 0.001) #学習回数 for epoch in range(500): #初期化 total_loss = 0 #学習用のミニバッチからx , y に分ける for train_x , train_y in train_loader: #Variable -> 計算操作を記録してくれる train_x , train_y = Variable(train_x) , Variable(train_y) #どの値が最適か、わからないから、一旦初期化させる opt.zero_grad() #モデルで学習した結果 output = model(train_x) #差分を調べる loss = criterion(output , train_y) #その差分を後ろにパス loss.backward() #最適化な重みを探す opt.step() total_loss += loss.data if (epoch + 1 ) % 50 == 0: #回数を重ね得るほど、低くなっていく print( epoch+1 , total_loss) """ 精度の計算 モデルの精度を確かめるべく、テスト用でとってたデータを モデルに充ててみる """ test_x , test_y = Variable(x_test) , Variable(y_test) #結果が高いほうをresultに result = torch.max(model(test_x).data , 1)[1] accuracy = sum(test_y.data.numpy() == result.numpy()) / len(test_y.data.numpy()) print(accuracy)
#ライブラリ import torch #自動で計算してくれる from torch.autograd import Variable import torch.nn as nn #様々な関数 import torch.nn.functional as F import torch.optim as optim #DataLoader -> 撥サイズ決める時に必要 #TensorDataset -> トレーニング用データをまとめてくれる from torch.utils.data import DataLoader , TensorDataset from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split import pandas as pd
まずは今回のライブラリーから見ておく。
後々出てきますがoptimは今回SGDを使用している
また、pytorchの醍醐味といってもいい、autogradも入れる。
こいつはざっくり自動で計算してくれる奴ってぐらいでいいのかな?w
#wine_keys -> (['data', 'target', 'target_names', 'DESCR', 'feature_names'])
wine = load_wine()
ここで、ワインのデータセットを読み込む。
キー自体は5個のキーからなり、3種類のワインのデータが入っている。
今回は2種類のワインの判別を行うので、
3種類目のデータをちょん切る
#2種類のワイン情報(特徴は13項目にも及ぶ) wine_data = wine.data[0:130] #ワインの種類 → 今回は2種類に wine_target = wine.target[0:130]
そして、2種類のデータセットに分けたら、次は学習用、テスト用にデータを分ける
x_train , x_test , y_train , y_test = train_test_split(wine_data , wine_target , test_size = 0.25)
test_sizeでそれぞれの割合を定義(今回は3:1に)
注意が、ここではまだarray形式なので、次にtensor形式に変換する
x_train = torch.from_numpy(x_train).float() x_test = torch.from_numpy(x_test).float() y_train = torch.from_numpy(y_train).long() y_test = torch.from_numpy(y_test).long()
xデータのほう数値のばらつきが多いので、これでは学習しづらいということで、
数字を小さく設定する→float():浮動小数点数
yデータは逆にラベルしか入っていないため、そのまま、整数として扱う(long)
train_data = TensorDataset(x_train , y_train) #バッチサイズの設定 → 学習させるときにどれくらいまとめてやりますか? train_loader = DataLoader(train_data , batch_size = 15 , shuffle= True)
ここで、トレーニングデータをひとまとめにして、次に、
このひとまとめのデータをさらに細かくバッチサイズを設定(小さいパケットみたいなイメージ)する
つまりは一回の学習にどれくらいの量をまとめてやりますか?ってこと。
よく見るのは、32や64だが、データセットがおおきくなればなる程に大きくなっていく
shuffleは字のごとく、バッチサイズに入れるデータをランダムにする?→YESということ。
class Net(nn.Module): #単純にレイヤーを作る def __init__(self): #親クラスをそのまま継承する super(Net , self).__init__() #第1層-第2層 self.fc1 = nn.Linear(13 , 128) #第2層-第3層 self.fc2 = nn.Linear(128 , 2) #重みをかけていく def forward(self , x): x = F.relu(self.fc1(x)) x = self.fc2(x) #それぞれ0 , 1 の確率を出す return F.log_softmax(x , dim=0) model = Net()
モデルの定義を行う。
まずは、Netクラスをそのまま継承( super(Net , self).__init__() )し、
第1層~第3層までを作る。
そして、def fowardでそれぞれに重みを付けてあげて,
最後にreturn でsoftbax関数でそれぞれ0の確率、1 の確率を抽出する
イメージ的には下の図のようになる
これでモデルの定義は完了。
ここからトレーニングの実行に移っていく。
#正解と、出力の差分算出方法 criterion = nn.CrossEntropyLoss() #差分を埋めるのに必要な値は?を計算してくれる opt = optim.SGD(model.parameters() , lr = 0.001) #学習回数 for epoch in range(500): #初期化 total_loss = 0 #学習用のミニバッチからx , y に分ける for train_x , train_y in train_loader: #Variable -> 計算操作を記録してくれる train_x , train_y = Variable(train_x) , Variable(train_y) #どの値が最適か、わからないから、一旦初期化させる opt.zero_grad() #モデルで学習した結果 output = model(train_x) #差分を調べる loss = criterion(output , train_y) #その差分を後ろにパス loss.backward() #最適化な重みを探す opt.step() total_loss += loss.data if (epoch + 1 ) % 50 == 0: #回数を重ね得るほど、低くなっていく print( epoch+1 , total_loss)
criterion →コメント通り、正解と出力の差分をどうやって計算するのか?
opt →criterionで出た差分をどのように埋めていくのか?埋めるにあたり、必要な値って?
を計算してくれる
for epoch in range(500) → 500回に学習回数を設定
total_loss = 0 →まずは一旦、全損失関数の値を0にしておく。
理由は初めから値が入っていたら、差分が適切に出てこない
そして、train_loaderにはすでにミニバッチされたデータが格納されており、
それぞれをVariableで計算操作を記録する。
opt.zero_grad() → total_lossと同じように、最適化の値についても初期化
outputでモデルが学習した結果を格納し、lossで正解とoutputの差分を調べる。
loss.backward()で差分をバックパスする
opt.step() →loss.backward()から来たパスをもとに最適な重みを探してくれる。
total_loss += loss.data →そこから、適正な重みを新たにたして、再学習させる(500回)
ここでは、主にトレーニングの段階である。
次に、このモデルが本当に正しいのか、どれくらいの精度なのかを見ていく
test_x , test_y = Variable(x_test) , Variable(y_test) #結果が高いほうをresultに result = torch.max(model(test_x).data , 1)[1] accuracy = sum(test_y.data.numpy() == result.numpy()) / len(test_y.data.numpy()) print(accuracy)
まずはtrainデータの時同様に、Variable関数で、計算可能なものに変換。
次に、test_xに格納されているデータで0か1か、確率が高いほうをresultに入れる
resultをもとに、更にyの持つ正解ラベルデータの個数で演算することで、
どれだけの精度なのか、を測定する。