LoginSignup
3
4

More than 3 years have passed since last update.

AutoAIでお手軽機械学習(その5) API編

Last updated at Posted at 2020-09-01

はじめに

「AutoAIでお手軽機械学習」シリーズの第5弾です。
AutoAIは、元々UIで機械学習モデルを作るツールなのですが、最近APIも用意されて、Pythonからモデル生成機能を呼び出すことが可能になりました。
当記事は、その事例の紹介となります。
前4つの記事は以下のとおりです。

元ネタ

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()

こんな感じの出力が得られます。

スクリーンショット 2020-09-01 18.15.38.png

日本の感染者数を時系列形式で抽出

次のコードで日本の感染者数を時系列形式で入手します。

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

最終結果はこんな表データになります。

スクリーンショット 2020-09-01 18.17.32.png

Cloud Object Storageに新しいデータセットをcsvとしてアップロードする

APIでモデルを作るため、こうやって作った学習データをCSVファイルにする必要があります。さらに、このCSVファイルをIBM Cloudの別サービスであるCloud Object Storageにアップロードします。
具体的なコードは以下のとおりです。
project_idproject_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

スクリーンショット 2020-09-01 18.41.52.png

可視化

また、次のコードで、パイプライン間の比較をグラフで行うこともできます。

%matplotlib inline

summary.holdout_r2.plot();

結果は以下のとおりです。

スクリーンショット 2020-09-01 18.44.14.png

最適なパイプラインモデルを取得する

次のコードにより、最適なパイプラインをNotebook上に取得することができます。
また、'Pipeline_1'のような参照方法でそれ以外のパイプラインも取得できます。

best_pipeline = pipeline_optimizer.get_pipeline()
pipeline1 = pipeline_optimizer.get_pipeline(pipeline_name='Pipeline_1')

パイプラインの可視化

Notebook上に取得したパイプラインはvisualizeという関数を持っていて、処理プロセスの可視化が可能です。
コードと、結果を以下に示します。

最適なパイプラインの可視化

best_pipeline.visualize()

スクリーンショット 2020-09-01 18.49.08.png

最初のパイプラインの可視化

pipeline1.visualize()

スクリーンショット 2020-09-01 18.49.36.png

パイプラインのコード化

パイプラインは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

スクリーンショット 2020-09-01 19.06.02.png

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()

結果は以下のとおりです。

スクリーンショット 2020-09-01 19.15.31.png

お疲れ様でした。以上で、チュートリアルは完了となります。

3
4
1

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
3
4