はじめに
「AutoAIでお手軽機械学習」シリーズの第5弾です。
AutoAIは、元々UIで機械学習モデルを作るツールなのですが、最近APIも用意されて、Pythonからモデル生成機能を呼び出すことが可能になりました。
当記事は、その事例の紹介となります。
前4つの記事は以下のとおりです。
- AutoAIでお手軽機械学習(その1) 準備編
- AutoAIでお手軽機械学習(その2) モデル構築編
- AutoAIでお手軽機械学習(その3) Webサービス編
- AutoAIでお手軽機械学習(その4) Jupyter Notebook編
元ネタ
Githubに公開されているAutoAI and COVID-19 with TEST DATAが元ネタです。
このコードのコメントを日本語化したものを、次のリンクに公開しました。
また、このNotebookは(英語ですが)以下のブログでも解説されているので、こちらも参照して下さい。
モデルのユースケース
モデルのユースケースは、「コロナの感染者数予測」です。データはジョンズ・ホプキンス大学でリアルに公開されているデータを利用します。
オリジナルのコードではポーランドの予測をしていましたが、折角なので絞り込み対象を「日本」に変更しています。
モデルの種類としては、感染者数の予測なので、「回帰」モデルとなります。
以下、オリジナルのnotebookに沿った章立てで説明をしていきます。
1. セットアップ
WMLの資格情報
wml_credentials = {
"url": "xxx",
"apikey":"xxx",
"instance_id": "xxx"
}
まず、WMLの資格情報をNotebookに設定します。資格情報の入手手順は下記リンク先を参考にして下さい。
ライブラリの導入
次に必要ライブラリを導入します。Notebook内の関連するコードは以下のとおりです。
!pip uninstall -y watson-machine-learning-client-V4 | tail -n 1
!pip install -U watson-machine-learning-client-V4 | tail -n 1
!pip install -U autoai-libs | tail -n 1
!pip show watson-machine-learning-client-V4e
データ入手
ジョンズ・ホプキンス大学システム科学工学センターで公開されているデータを入手します。
import pandas as pd
import numpy as np
confirmed_df = pd.read_csv('https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv')
confirmed_df.head()
こんな感じの出力が得られます。
日本の感染者数を時系列形式で抽出
次のコードで日本の感染者数を時系列形式で入手します。
country = 'Japan'
confirmed = confirmed_df.loc[:, confirmed_df.keys()[4]:confirmed_df.keys()[-1]]
days_since_1_22 = np.array([i for i in range(len(confirmed.keys()))]).reshape(-1, 1)
country_cases = [confirmed_df[confirmed_df['Country/Region']==country][i].sum() for i in confirmed.keys()]
training_df = pd.DataFrame(days_since_1_22, columns=['Day'])
training_df['Elapsed_days'] = training_df.Day
training_df['Cases'] = country_cases
training_df = training_df.fillna(0)
test_df = training_df.tail(5)
training_df = training_df.iloc[:-5]
training_df
最終結果はこんな表データになります。
Cloud Object Storageに新しいデータセットをcsvとしてアップロードする
APIでモデルを作るため、こうやって作った学習データをCSVファイルにする必要があります。さらに、このCSVファイルをIBM Cloudの別サービスであるCloud Object Storageにアップロードします。
具体的なコードは以下のとおりです。
project_id
とproject_access_token
の入手方法についてはNotebook内に説明がありますので、そちらを参照して下さい。
project_id = 'xxx`
project_access_token = 'xxx`
from project_lib import Project
project = Project(project_id=project_id, project_access_token=project_access_token)
pc = project.project_context
csv_details = project.save_data(data=training_df.to_csv(index=False),file_name='covid19_training.csv',overwrite=True)
storage_meta = project.get_storage_metadata()
2. オプティマイザー定義
これで事前準備は完了です。いよいよ、モデル生成のための「オプティマイザー」の定義に入ります。
トレーニングデータ定義
前のステップでObject StorageにアップロードしたCSVファイルのリファレンスを定義します。
具体的なコードは以下のとおりです。
filename = csv_details['file_name']
bucket_name = csv_details['bucket_name']
from watson_machine_learning_client.helpers import DataConnection, S3Connection, S3Location
csv_data_conn = DataConnection(
connection=S3Connection(endpoint_url=storage_meta['properties']['endpoint_url'],
access_key_id=storage_meta['properties']['credentials']['editor']['access_key_id'],
secret_access_key=storage_meta['properties']['credentials']['editor']['secret_access_key']),
location=S3Location(bucket=bucket_name,
path=filename))
training_data_reference=[csv_data_conn]
オプティマイザの設定
UIの場合、画面で設定する情報を、パラメータの形で指定していきます。
具体的なコードは以下の形になります。
from watson_machine_learning_client.experiment import AutoAI
experiment = AutoAI(wml_credentials)
pipeline_optimizer = experiment.optimizer(
name='COVID-19 Japan - AutoAI',
prediction_type=AutoAI.PredictionType.REGRESSION,
daub_include_only_estimators=['RidgeEstimator', 'LinearRegressionEstimator'],
prediction_column='Cases',
scoring=AutoAI.Metrics.R2_SCORE,
)
get_params()
でオプティマイザのすべてのパラメータを確認できます。
pipeline_optimizer.get_params()
結果は、以下の形になります。
{'name': 'COVID-19 Japan - AutoAI',
'desc': '',
'prediction_type': 'regression',
'prediction_column': 'Cases',
'scoring': 'r2',
'test_size': 0.1,
'max_num_daub_ensembles': 1,
't_shirt_size': 'l',
'train_sample_rows_test_size': None,
'daub_include_only_estimators': ['RidgeEstimator',
'LinearRegressionEstimator'],
'data_join_graph': False,
'csv_separator': ',',
'excel_sheet': 0,
'positive_label': None,
'run_id': None}
ちなみにまだ工事中のようですが、APIリファレンスは下記です。サンプル以外のパラメータを指定したい場合は、こちらを参照して下さい。
3. モデル構築
これで学習のためのすべての準備は完了です。あとは、optimizerに対してfit関数を呼び出すと、モデル構築がはじまります。
この時の引数として1で準備したCSVファイルのリファレンスを利用します。
また、background_mode
というパラメータもあり、学習を同期・非同期どちらで行うかが指定できます。
run_details = pipeline_optimizer.fit(
training_data_reference=training_data_reference,
background_mode=False)
4. パイプラインの比較とテスト
学習が完了したら、できたモデル(パイプライン)間の比較が可能です。
実装とその結果を以下に示します。
summary = pipeline_optimizer.summary()
summary
可視化
また、次のコードで、パイプライン間の比較をグラフで行うこともできます。
%matplotlib inline
summary.holdout_r2.plot();
結果は以下のとおりです。
最適なパイプラインモデルを取得する
次のコードにより、最適なパイプラインをNotebook上に取得することができます。
また、'Pipeline_1'のような参照方法でそれ以外のパイプラインも取得できます。
best_pipeline = pipeline_optimizer.get_pipeline()
pipeline1 = pipeline_optimizer.get_pipeline(pipeline_name='Pipeline_1')
パイプラインの可視化
Notebook上に取得したパイプラインはvisualizeという関数を持っていて、処理プロセスの可視化が可能です。
コードと、結果を以下に示します。
最適なパイプラインの可視化
best_pipeline.visualize()
最初のパイプラインの可視化
pipeline1.visualize()
パイプラインのコード化
パイプラインはpretty_print関数も持っていて、パイプライン構築のためのコードを生成してくれます。
実装と結果を以下に示します。
best_pipeline.pretty_print(ipython_display=True)
from autoai_libs.transformers.exportable import ColumnSelector
from lale.lib.autoai_libs import NumpyColumnSelector
from lale.lib.autoai_libs import FloatStr2Float
from lale.lib.autoai_libs import NumpyReplaceMissingValues
from lale.lib.autoai_libs import NumImputer
from lale.lib.autoai_libs import OptStandardScaler
from lale.lib.autoai_libs import float32_transform
from lale.lib.autoai_libs import TA1
import numpy as np
import autoai_libs.utils.fc_methods
from lale.lib.autoai_libs import FS1
import autoai_libs.cognito.transforms.textras_methods
from lale.lib.sklearn import Ridge
import lale
lale.wrap_imported_operators()
column_selector = ColumnSelector(columns_indices_list=[1])
numpy_column_selector = NumpyColumnSelector(columns=[0])
float_str2_float = FloatStr2Float(dtypes_list=['int_num'], missing_values_reference_list=[])
numpy_replace_missing_values = NumpyReplaceMissingValues(filling_values=float('nan'), missing_values=[])
num_imputer = NumImputer(missing_values=float('nan'), strategy='median')
opt_standard_scaler = OptStandardScaler(num_scaler_copy=None, num_scaler_with_mean=None, num_scaler_with_std=None, use_scaler_flag=False)
ta1_0 = TA1(fun=np.sqrt, name='sqrt', datatypes=['numeric'], feat_constraints=[autoai_libs.utils.fc_methods.is_non_negative, autoai_libs.utils.fc_methods.is_not_categorical], col_names=['Elapsed_days'], col_dtypes=[np.dtype('float32')])
fs1_0 = FS1(cols_ids_must_keep=range(0, 1), additional_col_count_to_keep=4, ptype='regression')
ta1_1 = TA1(fun=np.square, name='square', datatypes=['numeric'], feat_constraints=[autoai_libs.utils.fc_methods.is_not_categorical], col_names=['Elapsed_days', 'sqrt(Elapsed_days)'], col_dtypes=[np.dtype('float32'), np.dtype('float32')])
fs1_1 = FS1(cols_ids_must_keep=range(0, 1), additional_col_count_to_keep=4, ptype='regression')
ta1_2 = TA1(fun=autoai_libs.cognito.transforms.textras_methods.cube, name='cube', datatypes=['numeric'], feat_constraints=[autoai_libs.utils.fc_methods.is_not_categorical], col_names=['Elapsed_days', 'sqrt(Elapsed_days)', 'square(Elapsed_days)', 'square(sqrt(Elapsed_days))'], col_dtypes=[np.dtype('float32'), np.dtype('float32'), np.dtype('float32'), np.dtype('float32')])
fs1_2 = FS1(cols_ids_must_keep=range(0, 1), additional_col_count_to_keep=4, ptype='regression')
ridge = Ridge(alpha=3.739450909578426e-05, max_iter=53, random_state=33, solver='cholesky', tol=3.913158955537585e-05)
pipeline = column_selector >> numpy_column_selector >> float_str2_float >> numpy_replace_missing_values >> num_imputer >> opt_standard_scaler >> float32_transform() >> ta1_0 >> fs1_0 >> ta1_1 >> fs1_1 >> ta1_2 >> fs1_2 >> ridge
トレーニングデータとホールドアウトデータをCOSから読み取る
オプティマイザーからは、トレーニングデータとホールドアウトデータを取得することも可能です。
実装は以下の通りです。
train_df, holdout_df = pipeline_optimizer.get_data_connections()[0].read(with_holdout_split=True)
holdout_X = holdout_df.drop(['Cases'], axis=1).values
holdout_y = holdout_df.Cases.values
パイプラインモデルをローカルでテストする
sckit-learnのパイプランを取得することもできるので、ローカル環境でモデルの予測・評価ができます。
実装は、以下のとおりです。
model = pipeline_optimizer.get_pipeline(astype='sklearn')
from sklearn.metrics import r2_score
predicted_y = model.predict(holdout_X)
score = r2_score(predicted_y, holdout_y)
print(f'r2_score {score:.1%}')
r2_score 94.9%
5. デプロイとスコアリング
構築したモデルをWatson Machine Learningにデプロイし、Webサービスとして呼び出してスコアリングをしてみます。
最初のコードは、モデルをWebサービスとしてデプロイするためのコードです。
デプロイメントの作成
from watson_machine_learning_client.deployment import WebService
service = WebService(wml_credentials)
service.create(
experiment_run_id=pipeline_optimizer._engine._current_run_id,
model=best_pipeline,
deployment_name="COVID-19 AutoAI WebService")
正常に処理されると以下のようなメッセージが表示されます。
Preparing an AutoAI Deployment...
Published model uid: ad36b2be-0394-4ca1-9697-336b3ea49d63
Deploying model ad36b2be-0394-4ca1-9697-336b3ea49d63 using V4 client.
#######################################################################################
Synchronous deployment creation for uid: 'ad36b2be-0394-4ca1-9697-336b3ea49d63' started
#######################################################################################
initializing.......
ready
------------------------------------------------------------------------------------------------
Successfully finished deployment creation, deployment_uid='a8993acd-0519-48ae-9245-cc17bd41f35a'
------------------------------------------------------------------------------------------------
配置済みのオブジェクトはprint関数で、その内容が表示できます。
print(service)
name: COVID-19 AutoAI WebService, id: a8993acd-0519-48ae-9245-cc17bd41f35a, scoring_url: https://us-south.ml.cloud.ibm.com/v4/deployments/a8993acd-0519-48ae-9245-cc17bd41f35a/predictions, asset_id: ad36b2be-0394-4ca1-9697-336b3ea49d63
ウェブサービスのスコアリング
デプロイされたパイプライン上で score() を呼び出すことでスコアリングリクエストを行うことができます。
predictions = service.score(payload=holdout_df.drop(['Cases'], axis=1).iloc[:10])
predictions
{'predictions': [{'fields': ['prediction'],
'values': [[17298.03515625],
[39230.00390625],
[57713.87890625],
[-248.7548828125],
[-2589.3232421875],
[36067.33203125],
[15313.1142578125],
[21764.03125],
[52552.86328125],
[49318.40234375]]}]}
予測値と実測値の比較
予測値と実測値の比較をしてみます。
full_df = training_df.append(test_df)
predicted_cases = model.predict(full_df.drop(['Cases'], axis=1).values)
df = pd.DataFrame(predicted_cases, columns=['Predicted'])
df['Cases'] = full_df.Cases.values
df['Day'] = full_df.Day.values
df = df.sort_values(by=['Day'])
df
plotlyを使用して可視化する
最後に予測値と実測値の可視化をしてみます。
このサンプルではplotly
というライブラリを利用しています。
!pip install -U plotly
import plotly.graph_objects as go
import plotly.offline as pyo
pyo.init_notebook_mode()
fig = go.Figure()
fig.add_trace(go.Scatter(x=df.Day, y=df.Cases, mode='markers', name='Actual train'))
fig.add_trace(go.Scatter(x=holdout_df.Day, y=holdout_df.Cases, mode='markers', marker_size=10, name='Actual holdout'))
fig.add_trace(go.Scatter(x=test_df.Day, y=test_df.Cases, mode='markers', marker_size=10, name='Actual test'))
fig.add_trace(go.Scatter(x=df.Day, y=df.Predicted, mode='lines', name='Predicted'))
fig.update_layout(title="COVID19 AutoAI model for Japan",
xaxis_title="day",
yaxis_title="confirmed cases count",
font=dict(family="Courier New, monospace", size=18, color="#7f7f7f"))
fig.show()
結果は以下のとおりです。
お疲れ様でした。以上で、チュートリアルは完了となります。