3 あやめの分析
3.1 データの準備
では実際にディープラーニングで学習と予測を行っています。まずは機械学習でも行った「あやめ」(iris)のデータを読み込んでみます。deep_iris.ipynbに記述します。
import pandas as pd
df = pd.read_csv("iris.csv")
df.head()
このデータには以下の列があります。
- SepalLength 花がくの長さ
- SepalWidth 花がくの幅
- PetalLength 花びらの長さ
- PetalWidth 花びらの幅
- Name 種類
SepalLength、SepalWidth、PetalLength、PetalWidthが特徴量、Nameが正解ラベルになります。
学習データと教師データに分けます。ディープラーニングの場合、教師データは数値である必要があるため、replaceで0~2に置き換えます。そして、学習用とテスト用に分割します。
# 学習データ
x = df[["SepalLength", "SepalWidth", "PetalLength", "PetalWidth"]]
# # 教師データ
y = df['Name'].replace({'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2})
# 学習用とテスト用の分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state=0)
ニューラルネットワークの入力データは標準化を行うことで精度を上げることができます。
# 特徴量の標準化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
3.2 モデルの構築
ディープラーニングにはMLPClassifierというクラスを使用します。
from sklearn.neural_network import MLPClassifier
# モデルの構築
model = MLPClassifier(
hidden_layer_sizes=(32, 16),
max_iter=500,
random_state=0
)
引数 hidden_layer_sizesが隠れ層のサイズを指定します。最初の隠れ層では32個、次の隠れ層では16個のニューロンを指定しています。
入力層は指定されていませんが、自動的に4個です。これはSepalLength、SepalWidth、PetalLength、PetalWidth の4つの列が特徴量だからです。 4個のニューロンから入力したデータを32個に拡大し、16個に縮小します。
そして、出力層も指定されていませんが3個のニューロンになります。これは3種類の答え(0、1、2)があるからです。この出力層にはその値になる確率が入ります。それぞれに数値が入り、最も大きなものが予測結果となります。
つまり、4個 → 32個 → 16個 → 3個 という層になります。
引数 max_iterで学習の回数を指定します。規定値は200回です。今回は500回にしています。
3.3 学習と評価
学習にはfitを使用します。
model.fit(x_train, y_train)
評価を表示します。
model.score(x_test, y_test)
予測はpredictを使用します。予測データを標準化して予測します。
sample = scaler.fit_transform([[5.5, 3.8, 1.9, 1.2]])
model.predict(sample)
実際には予測結果はデータそれぞれに対し3つの数値(確率)になっています。predictでは最も高い確率のものがどれかが表示されています。
確率はmodel.predict_probaで得ることが出来ます。
proba = model.predict_proba(sample)
pd.Series(proba[0], ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'])
3.4 誤差
誤差を学習回数毎にグラフで表示してみます。model.loss_curve_ に記録されています。
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(font=["Meiryo"])
plt.plot(model.loss_curve_)
plt.title('学習の損失推移')
plt.xlabel('反復回数')
plt.ylabel('損失')
plt.show()
学習を重ねる毎に損失が少なくなっていきます。損失が安定したぐらいの回数で打ち切ると効率的です。
3.5 パラメータ数
ニューラルネットワークによる「学習」とは各ニューロンの重み付けとバイアスの決定です。 model.coefs_ には重み付けが、model.intercepts_にはバイアスが入っています。 それぞれ、各層ごとの配列になっています。
重み付けとバイアスがいくつあるかを表示してみます。
for coef in model.coefs_:
print(f"重み付け : {coef.shape}")
最初の層では4つのニューロンが32個のニューロンに結合しています。ということは4×32=128個の重み付けの値を決める必要があります。 次の層は32個のニューロンが16個に結合しています(計512個)。 最後の出力層は16個が3個に結合しています(計48個)
では、バイアスを表示してみます。
for bias in model.intercepts_:
print(f"バイアス : {bias.shape}")
バイアスはニューロンの数だけ決めれば良いので、最初の層が32個、次が16個、最後が3個です。
このような、学習で決める値のことをパラメータと呼びます。つまり、パラメータとは重み付けとバイアスの総数です。
パラメータの総数を計算してみます。
param_sum = 0
for i, coef in enumerate(model.coefs_):
print(f"Layer {i+1} 重み付け : {coef.shape} パラメータ数:{coef.shape[0] * coef.shape[1]}")
param_sum += coef.shape[0] * coef.shape[1]
for i, bias in enumerate(model.intercepts_):
print(f"Layer {i+1} バイアス : {bias.shape} パラメータ数:{bias.shape[0]}")
param_sum += bias.shape[0]
print(f"総パラメータ数: {param_sum}")