6
6

More than 1 year has passed since last update.

【多クラス分類問題】LightGBMにてパラメータチューニングの有無で精度を比較

Posted at

1.目的

MNISTデータ(0から9までの手書き数字)を分類するモデル(多クラス分類モデル)をLightGBMを用いて実装する。
その際にハイパーパラメータをチューニングしないモデルと、チューニングしたモデルの精度を比較する。
チューニングはOptunaを用いて行う。その使い方等をメモ程度に置いておく。

2.MNISTとは

MNISTはMixed National Institute of Standards and Technology databaseの略で、手書き数字画像60,000枚とテスト画像10,000枚を集めた、画像データセット。
0~9の手書き数字が教師ラベルとして各画像に与えられている。
詳しくはこちら
今回はKerasで公開されているMNISTを使う。

3.使用ライブラリ

import lightgbm as lgb
import pandas as pd
import numpy as np
from tensorflow.keras.datasets import mnist
from sklearn.model_selection import train_test_split
#評価指標は以下4つ
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
from sklearn.metrics import f1_score

4.モデル作成(チューニング無しVer)

コードは以下の通り。

# Kerasに付属の手書き数字画像データをダウンロード
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# training set を学習データ(X_train, y_train)と検証データ(X_valid, y_valid)に8:2で分割する
X_train,X_valid,y_train,y_valid = train_test_split(X_train, y_train, test_size=0.2, random_state=0)

# 各データを1次元に変換
X_train = X_train.reshape(-1,784)
X_valid = X_valid.reshape(-1,784)
X_test = X_test.reshape(-1,784)

#正規化
X_train = X_train.astype('float32')
X_valid = X_valid.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_valid /= 255
X_test /= 255

# 訓練・検証データの設定
train_data = lgb.Dataset(X_train, label=y_train)
eval_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)

#パラメータ設定
params = {
    'task': 'train',  #トレーニング用
    'boosting_type': 'gbdt', #勾配ブースティング決定木
    'objective': 'multiclass', #目的:多値分類
    'num_class': 10, #分類クラス数
    'metric': 'multi_logloss' #評価指標は多クラスのLog損失
}
#モデル作成
gbm = lgb.train(
    params,
    train_data,
    valid_sets=eval_data,
    num_boost_round=100,
    early_stopping_rounds=10
)

こうして出来たモデルを用いて、testデータの予測を行う。
そのコードは以下。

#予測
preds = gbm.predict(X_test, num_iteration=gbm.best_iteration)

y_pred = []
for x in preds:
    y_pred.append(np.argmax(x))

この予測y_predと教師データy_testを用いて評価指標を計算し、出力する。
ここでは説明を省くが、各評価指標についてはこちらでわかりやすく解説されている。

#正解率など評価指標の計算
print('正解率(accuracy_score):{}'.format(accuracy_score(y_test, y_pred)))
#適合率、再現率、F1値はマクロ平均を取る
print('再現率(recall_score):{}'.format(recall_score(y_test, y_pred, average='macro')))
print('適合率(precision_score):{}'.format(precision_score(y_test, y_pred, average='macro')))
print('F1値(f1_score):{}'.format(f1_score(y_test, y_pred, average='macro')))

出力結果は以下の通りである。

正解率(accuracy_score):0.9766
再現率(recall_score):0.9764353695446533
適合率(precision_score):0.9764619714676158
F1値(f1_score):0.9764381593889576

ハイパーパラメータをチューニングしなくても、正解率が97.6%とかなり高い数字になっている。
また、モデルの作成もわずか数分で終わったのでlightGBMの凄さが分かる。

ちなみに、上の4つの指標はclassification_reportを使うことで以下のように一気に計算できることが分かった。0から9の各数字についての指標も出してくれる。

from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred, digits=5)) #digitsは表示桁数
実行結果
              precision    recall  f1-score   support

           0    0.97778   0.98776   0.98274       980
           1    0.99120   0.99207   0.99163      1135
           2    0.97282   0.97093   0.97187      1032
           3    0.96961   0.97921   0.97438      1010
           4    0.97955   0.97556   0.97755       982
           5    0.97860   0.97422   0.97640       892
           6    0.98115   0.97808   0.97961       958
           7    0.97835   0.96693   0.97260      1028
           8    0.96735   0.97331   0.97032       974
           9    0.96822   0.96630   0.96726      1009

    accuracy                        0.97660     10000
   macro avg    0.97646   0.97644   0.97644     10000
weighted avg    0.97661   0.97660   0.97660     10000

5.モデル作成 (チューニング有り)

次に、ハイパーパラメータをチューニングしてモデルを作る。
Optunaを用いてチューニングをするため、以下をインポート。

# LightGBM Optunaを使ってハイパーパラメタチューニング
import optuna.integration.lightgbm as lgb_o

あとはパラメータ設定までは同じコードになる。

# Kerasに付属の手書き数字画像データをダウンロード
(X_train, y_train), (X_test, y_test) = mnist.load_data()

# training set を学習データ(X_train, y_train)と検証データ(X_valid, y_valid)に8:2で分割する
X_train,X_valid,y_train,y_valid = train_test_split(X_train, y_train, test_size=0.2, random_state=0)

# 各データを1次元に変換
X_train = X_train.reshape(-1,784)
X_valid = X_valid.reshape(-1,784)
X_test = X_test.reshape(-1,784)

#正規化
X_train = X_train.astype('float32')
X_valid = X_valid.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_valid /= 255
X_test /= 255

# 訓練・検証データの設定
train_data = lgb_o.Dataset(X_train, label=y_train)
eval_data = lgb_o.Dataset(X_valid, label=y_valid, reference=train_data)

# パラメータ設定
params = {
    'task': 'train', 
    'boosting_type': 'gbdt',
    'objective': 'multiclass',
    'num_class': 10,
    'metric': 'multi_logloss'
}

Optunaでパラメータチューニングをする。
チューニングされたパラメータをbest_paramsとして表示させてみる。
この実行はかなり時間がかかるため注意。(特徴量が784列分もあるためだろうか。。?)

best_params= {}

#モデル作成
gbm = lgb_o.train(
    params,
    train_data,
    valid_sets=[train_data, eval_data], #ここがチューニングしない場合と違う
    num_boost_round=100,
    early_stopping_rounds=10
)

best_params = gbm.params
best_params

チューニングされたパラメータが次のようになった。

実行結果
{'task': 'train',
 'boosting_type': 'gbdt',
 'objective': 'multiclass',
 'num_class': 10,
 'metric': 'multi_logloss',
 'feature_pre_filter': False,
 'lambda_l1': 1.4206763386954986e-08,
 'lambda_l2': 0.0004970847920575475,
 'num_leaves': 37,
 'feature_fraction': 0.784,
 'bagging_fraction': 0.9001098370804291,
 'bagging_freq': 3,
 'min_child_samples': 20,
 'num_iterations': 100,
 'early_stopping_round': 10}

先と同じように、このモデルを用いて予測してみる。

#予測
preds = gbm.predict(X_test, num_iteration=gbm.best_iteration)

y_pred = []
for x in preds:
    y_pred.append(np.argmax(x))

#正解率など評価指標の計算
print('正解率(accuracy_score):{}'.format(accuracy_score(y_test, y_pred)))
#適合率、再現率、F1値はマクロ平均を取る
print('再現率(recall_score):{}'.format(recall_score(y_test, y_pred, average='macro')))
print('適合率(precision_score):{}'.format(precision_score(y_test, y_pred, average='macro')))
print('F1値(f1_score):{}'.format(f1_score(y_test, y_pred, average='macro')))

チューニング後のモデルでの評価指数が以下となる。

チューニング後
正解率(accuracy_score):0.978
再現率(recall_score):0.9778036992589507
適合率(precision_score):0.9778601989002492
F1値(f1_score):0.9778154759497815

チューニング前と比べてみる

チューニング前
正解率(accuracy_score):0.9766
再現率(recall_score):0.9764353695446533
適合率(precision_score):0.9764619714676158
F1値(f1_score):0.9764381593889576

いずれも0.0014ほど上昇していることが分かる。
が、チューニングせずともかなり良い精度で分類できていたので、あまりその恩恵を感じられなかった。。
次は違うデータセットでも試してみたい。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6