OSSライブラリを組み合わせたsklearn-fabの使用方法¶

本ノートブックでは、OSSライブラリの機能を、sklearn-fabと組み合わせた使用方法を紹介します。
使用方法として、以下の4点について説明します。

  • Pipelineを使用し、分析を一括実行する
    2. Pipelineの作成および3. ベストモデルの選択をご覧ください

  • GridSearchCVを使用し、ベストモデルの選択を実施する
    3. ベストモデルの選択をご覧ください

  • joblibを使用し、モデルを永続化する
    4. ベストモデルの永続化をご覧ください

  • モデルホットスタートを使用し、モデルを再学習する
    5. モデル再学習の実施をご覧ください

1. データ準備¶

まず、学習およびテストに使用するデータを確認します。
本ノートブックでは、乳がんの検査結果を示すデータを使用します。
データの詳細については、以下をご覧ください(本ハンズオンでは、当該データをベースにシャッフルし、分割したものを使用します)。
Breast cancer wisconsin dataset

In [ ]:
import pandas as pd

train_data = pd.read_csv('./data/train_data_1.csv')
train_data.head()

上記のデータについて、

  • カテゴリ変数が存在しない
  • 説明変数の標準化は、Pipelineで実施する

という理由から、そのまま使用します。
また、説明変数をX_train、目的変数をy_trainとして定義しておきます。

In [ ]:
X_train = train_data.iloc[:, 1:]
y_train = train_data.iloc[:, 0]

2. Pipelineの作成¶

本ハンズオンにおいて、実施したい手順は以下になります。

  • データを入力 -> データを標準化 -> 分類用のestimatorのインスタンス作成 -> 学習および予測を実行

これらを簡単かつ一括に実行する、scikit-learnのPipelineという機能があります。
上記の手順を実施するため、以下を指定し、Pipelineを作成します。

  • データ標準化のクラス: StandardScaler
  • 分類用のestimatorのクラス: SklearnFABBernGateLinearClassifier
In [ ]:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn_fab import SklearnFABBernGateLinearClassifier

pipeline = Pipeline([('sc', StandardScaler()), ('cl', SklearnFABBernGateLinearClassifier())])
pipeline

作成したPipelineを、ベストモデルを作成する過程で使用していきます。

3. ベストモデルの選択¶

scikit-learnのGridSearchCVという機能を使用し、複数モデルを作成してベストモデルを選択します。
多くのモデルを作成することにより、より精度の高いモデルを選択することができます。

今回は、estimatorが有する以下のパラメーターを網羅的に組み合わせ、複数モデルを作成します。

  • random_seed: 0, 1
  • tree_depth: 4, 5
  • shrink_threshold: 1.0%, 5.0%

作成した複数モデルからベストモデルを選択するために、評価指標には以下を指定します。

  • recall(再現率)
    「乳がんであることを、検査により漏れなく発見する」ことを目的として、この評価指標を用います。

前章で作成したPipelineと、指定したパラメーターおよび評価指標を使用し、GridSearchCVを実行します。

In [ ]:
from sklearn.model_selection import GridSearchCV

# estimatorのパラメーターを指定
estimator_param_grid = {'cl__random_seed': [0, 1], 'cl__tree_depth': [4, 5],
                        'cl__shrink_threshold': ['1.0%', '5.0%']}

cl = GridSearchCV(pipeline, estimator_param_grid, cv=2, scoring='recall')
cl.fit(X_train, y_train)

ベストモデルのスコア、およびパラメーターの組み合わせを確認します。

In [ ]:
best_estimator = cl.best_estimator_
print('best_score: {}'.format(cl.best_score_))
print('best_model: {}'.format(best_estimator))

4. ベストモデルの永続化¶

ここでは、作成済みのベストモデルの永続化(保存)を行います。

モデルを保存することで、そのモデルを再利用することや複数人で共有することが可能です。
scikit-learnで学習したモデルは、joblibというライブラリを使うことで、簡単に保存することができます。

In [ ]:
import os
import joblib

save_dir = './share/'
os.makedirs(save_dir, exist_ok=True)

saved_estimator_path = os.path.join(save_dir, 'saved_estimator.joblib')
joblib.dump(best_estimator, saved_estimator_path)

モデルを保存する際、モデル作成時の条件や使用データも併せて管理・保存したい場合があります。
そこで、以下を保存する方法をそれぞれ示します。

  • 学習およびテストに使用したデータ
  • モデルのスコアおよびパラメーター
  • 分析に使用したノートブック(本ノードブック)
  • 分析環境のsklearn-fabおよび依存ライブラリのバージョン
In [ ]:
import csv

# データの保存
train_data.to_csv(os.path.join(save_dir, 'saved_train_data.csv'), index=False)

# スコアおよびパラメーターの保存
score = [cl.best_score_, cl.best_params_]
with open(os.path.join(save_dir, 'score.csv'), 'w') as f:
    writer = csv.writer(f)
    writer.writerow(score)

# ノートブックの保存
notebook_name = 'use_sklearn_fab_with_oss_library.ipynb'
!cp {notebook_name} {save_dir}

# ライブラリのバージョンの保存
!pip freeze > {save_dir}pip_info.txt

保存したモデルが、ロードできることを確認します。

In [ ]:
loaded_estimator = joblib.load(saved_estimator_path)
loaded_estimator

ロードしたモデルは、通常の学習済みモデルと同様、予測や可視化に使用することができます。
なお、保存したモデルをロードして使用する条件として、以下を満たす必要があります。

  • モデルを保存した環境と、同じバージョンのsklearn-fab(依存ライブラリを含む)がインストールされている

5. モデル再学習の実施¶

前章でロードしたモデルを使用し、再学習を実施します。再学習は以下のようなケースで実施します。

  • 日々変化するデータで再学習し、モデルの精度が低下するのを防ぎたい場合
  • データを追加して再学習し、モデルの精度を向上したい場合

sklearn-fabは、再学習時に元モデルと同等構造のモデルを学習するための、モデルホットスタートという機能を有しています。
以下に実施方法を示します。

まず、再学習に使用するデータを確認します。

In [ ]:
train_data_2 = pd.read_csv('./data/train_data_2.csv')
train_data_2.head()

再学習に使用するパラメーターとして、以下を新たに与えます。

  • gate_opt_mode
    再学習のベースとなるモデルの門木構造を、どのように保持して学習するかを定めるパラメーターです。
  • comp_opt_mode
    再学習のベースとなるモデルの予測式を、どのように保持して学習するかを定めるパラメーターです。
  • base_model_dict
    再学習のベースとなるモデルを設定するパラメーターです。

ベストモデルの選択時と同様、Pipelineを作成し、学習を実行します。

In [ ]:
X_train_2 = train_data_2.iloc[:, 1:]
y_train_2 = train_data_2.iloc[:, 0]

# 再学習に使用するパラメーターを定義
random_seed = 0
gate_opt_mode = 'opt'
comp_opt_mode = 'opt'
base_model_dict = loaded_estimator.named_steps['cl'].get_model_dict()

cl_2 = SklearnFABBernGateLinearClassifier(random_seed=random_seed, gate_opt_mode=gate_opt_mode,
                                          comp_opt_mode=comp_opt_mode,
                                          base_model_dict=base_model_dict)

pipeline_2 = Pipeline([('sc', StandardScaler()), ('cl', cl_2)])
pipeline_2.fit(X_train_2, y_train_2)

再学習の有無によるスコア(再現率)を計算して比較するために使用する、テスト用データを確認します。

In [ ]:
test_data = pd.read_csv('./data/test_data.csv')
test_data.head()

テスト用データを使用し、以下のスコアを計算して比較します。

  • 再学習なし
  • 再学習あり
In [ ]:
from sklearn.metrics import recall_score

X_test = test_data.iloc[:, 1:]
y_test = test_data.iloc[:, 0]

print('再学習なし: {}'.format(recall_score(y_test, loaded_estimator.predict(X_test))))
print('再学習あり: {}'.format(recall_score(y_test, pipeline_2.predict(X_test))))

再学習した際のスコアが向上したことを確認でき、再学習が有効であることがわかりました。