コンテンツにスキップ

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}")