リアルタイム機械学習ノートブック(アルファ)の管理

重要

リアルタイム機械学習は、まだすべてのユーザーが利用できるわけではありません。 この機能はアルファベットで、まだテスト中です。 このドキュメントは変更される可能性があります。

次のガイドでは、リアルタイム機械学習アプリケーションを作成するために必要な手順について説明します。 Real-time ML PythonノートパソコンのAdobeを使って、モデルのトレーニング、DSLの作成、DSLのエッジへの公開、リクエストのスコアリングを行います。 リアルタイム機械学習モデルの導入に進むにつれて、データセットのニーズに合わせてテンプレートを変更することが期待されます。

リアルタイム機械学習ノートブックの作成

Adobe Experience PlatformのUIで、データサイエンス​内から「ノートブック」を選択します。 次に、JupyterLab​を選択し、環境の読み込みに時間をかけます。

JupyterLabを開く

JupyterLabランチャーが表示されます。 「Real-Time Machine Learning」まで下にスクロールし、Real-time XML​ノートブックを選択します。 データセットの例が記載されたノートブックセルを含むテンプレートが開きます。

空白のPython

ノードの読み込みと検出

モデルに必要なすべてのパッケージを読み込むことで開始します。 ノードのオーサリングに使用する予定のパッケージが読み込まれていることを確認します。

メモ

インポートのリストは、作成するモデルによって異なる場合があります。 新しいノードが時間の経過と共に追加されるので、このリストは変更されます。 使用可能なノードの完全なリストについては、ノードリファレンスガイドを参照してください。

from pprint import pprint
import pandas as pd
import numpy as np
import json
import uuid
from shutil import copyfile
from pathlib import Path
from datetime import date, datetime, timedelta
from platform_sdk.dataset_reader import DatasetReader

from rtml_nodelibs.nodes.standard.preprocessing.json_to_df import JsonToDataframe
from rtml_sdk.edge.utils import EdgeUtils
from rtml_sdk.graph.utils import GraphBuilder
from rtml_nodelibs.nodes.standard.ml.onnx import ONNXNode
from rtml_nodelibs.core.nodefactory import NodeFactory as nf
from rtml_nodelibs.nodes.standard.preprocessing.pandasnode import Pandas
from rtml_nodelibs.nodes.standard.preprocessing.one_hot_encoder import OneHotEncoder
from rtml_nodelibs.nodes.standard.ml.artifact_utils import ModelUpload
from rtml_nodelibs.core.nodefactory import NodeFactory as nf
from rtml_nodelibs.core.datamsg import DataMsg

次のコードセルは、使用可能なノードのリストを出力します。

# Discover Nodes
pprint(nf.discover_nodes())

注記のリスト

リアルタイム機械学習モデルのトレーニング

次のいずれかのオプションを使用して、Pythonコードを記述し、データの読み取り、前処理、分析を行います。 次に、独自のMLモデルをトレーニングし、ONNX形式にシリアル化して、Real-time Machine Learningモデルストアにアップロードする必要があります。

独自のモデルのトレーニング

開始を設定します。

メモ

リアルタイムML​テンプレートでは、車保険のCSVデータセットがGithubから取得されます。

トレーニングデータの読み込み

Adobe Experience Platform内のデータセットを使用する場合は、下のセルのコメントを解除します。 次に、DATASET_IDを適切な値に置き換える必要があります。

rtmlデータセット

JupyterLabノートブックのデータセットにアクセスするには、JupyterLabの左側のナビゲーションにある「データ」タブを選択します。 Datasets​ディレクトリと​スキーマ​ディレクトリが表示されます。 「データセット」を選択して右クリックし、使用するデータセットのドロップダウンメニューから「ノートブックのデータを探索」オプションを選択します。 ノートブックの下部に実行可能コードのエントリが表示されます。 このセルにはdataset_idが入っています。

データセットアクセス

完了したら、右クリックして、ノートブックの下部で生成したセルを削除します。

トレーニングのプロパティ

表示されたテンプレートを使用して、config_properties内のトレーニングプロパティを変更します。

config_properties = {
    "train_records_limit":1000000,
    "n_estimators": "80",
    "max_depth": "5",
    "ten_id": "_experienceplatform"  
}

モデルの準備

リアルタイムML​テンプレートを使用する場合は、MLモデルの分析、事前処理、トレーニング、評価を行う必要があります。 これは、データ変換を適用し、トレーニングパイプラインを構築することで行います。

データ変換

リアルタイムML​テンプレート​データ変換​セルは、独自のデータセットを使用できるように変更する必要があります。 通常は、列名の変更、データのロールアップ、データの準備/機能の設計に関係します。

メモ

次の例は、[ ... ]を使用して読みやすくまとめたものです。 表示して、完全なコードセルの​リアルタイムML​テンプレートのデータ変換セクションを展開してください。

df1.rename(columns = {config_properties['ten_id']+'.identification.ecid' : 'ecid',
                     [ ... ]}, inplace=True)
df1 = df1[['ecid', 'km', 'cartype', 'age', 'gender', 'carbrand', 'leasing', 'city', 
       'country', 'nationality', 'primaryuser', 'purchase', 'pricequote', 'timestamp']]
print("df1 shape 1", df1.shape)
#########################################
# Data Rollup
######################################### 
df1['timestamp'] = pd.to_datetime(df1.timestamp)
df1['hour'] = df1['timestamp'].dt.hour.astype(int)
df1['dayofweek'] = df1['timestamp'].dt.dayofweek

df1.loc[(df1['purchase'] == 'yes'), 'purchase'] = 1
df1.purchase.fillna(0, inplace=True)
df1['purchase'] = df1['purchase'].astype(int)

[ ... ]

print("df1 shape 2", df1.shape)

#########################################
# Data Preparation/Feature Engineering
#########################################      

df1['carbrand'] = df1['carbrand'].str.lower()
df1['country'] = df1['country'].str.lower()
df1.loc[(df1['carbrand'] == 'vw'), 'carbrand'] = 'volkswagen'

[ ... ]

df1['age'].fillna(df1['age'].median(), inplace=True)
df1['gender'].fillna('notgiven', inplace=True)

[ ... ]

df1['city'] = df1.groupby('country')['city'].transform(lambda x : x.fillna(x.mode()))
df1.dropna(subset = ['pricequote'], inplace=True)
print("df1 shape 3", df1.shape)
print(df1)

#grouping
grouping_cols = ['carbrand', 'cartype', 'city', 'country']

for col in grouping_cols:
    df_idx = pd.DataFrame(df1[col].value_counts().head(6))

    def grouping(x):
        if x in df_idx.index:
            return x
        else:
            return "Others"
    df1[col] = df1[col].apply(lambda x: grouping(x))

def age(x):
    if x < 20:
        return "u20"
    elif x > 19 and x < 29:
    [ ... ]
    else: 
        return "Others"

df1['age'] = df1['age'].astype(int)
df1['age_bucket'] = df1['age'].apply(lambda x: age(x))

df_final = df1[['hour', 'dayofweek','age_bucket', 'gender', 'city',  
   'country', 'carbrand', 'cartype', 'leasing', 'pricequote', 'purchase']]
print("df final", df_final.shape)

cat_cols = ['age_bucket', 'gender', 'city', 'dayofweek', 'country', 'carbrand', 'cartype', 'leasing']
df_final = pd.get_dummies(df_final, columns = cat_cols)

指定したセルを実行して、結果の例を表示します。 carinsurancedataset.csvデータセットから返される出力テーブルは、定義した変更を返します。

データ変換の例

トレーニングパイプライン

次に、トレーニングパイプラインを作成する必要があります。 これは、ONNXファイルを変換して生成する必要がある以外は、他のトレーニングパイプラインファイルと同様です。

前のセルで定義したデータ変換を使用して、テンプレートを変更します。 以下に示すコードは、機能パイプラインでONNXファイルを生成する際に使用します。 リアルタイムML​テンプレートをパイプラインコードの完全なセルに表示してください。

#for generating onnx
def generate_onnx_resources(self):        
    install_dir = os.path.expanduser('~/my-workspace')
    print("Generating Onnx")
        
    from skl2onnx import convert_sklearn
    from skl2onnx.common.data_types import FloatTensorType
        
    # ONNX-ification
    initial_type = [('float_input', FloatTensorType([None, self.feature_len]))]

    print("Converting Model to Onnx")
    onx = convert_sklearn(self.model, initial_types=initial_type)
             
    with open("model.onnx", "wb") as f:
        f.write(onx.SerializeToString())
            
    print("Model onnx created")

トレーニングパイプラインを完了し、データ変換を使用してデータを変更したら、次のセルを使用してトレーニングを実行します。

model = train(config_properties, df_final)

ONNXモデルの生成とアップロード

トレーニングの実施が完了したら、ONNXモデルを生成し、トレーニングを受けたモデルをReal-time Machine Learningモデルストアにアップロードする必要があります。 次のセルを実行すると、ONNXモデルは、他のすべてのノートブックと共に左側のレールに表示されます。

import os
import skl2onnx, subprocess

model.generate_onnx_resources()
メモ

model_path文字列値(model.onnx)を変更して、モデルの名前を変更します。

model_path = "model.onnx"
メモ

次のセルは編集も削除もできず、Real-time Machine Learningアプリケーションが動作するために必要です。

model = ModelUpload(params={'model_path': model_path})
msg_model = model.process(None, 1)
model_id = msg_model.model['model_id']
 
print("Model ID : ", model_id)

ONNXモデル

トレーニングを受けたONNXモデルをアップロード

JupyterLabノートブックにある「アップロード」ボタンを使用して、トレーニングを受けたONNXモデルをData Science Workspaceノートブック環境にアップロードします。

アップロードアイコン

次に、リアルタイムML​ノートブックのmodel_path文字列値を、ONNXモデル名と一致するように変更します。 完了したら、Set model path​セルを実行し、Upload your model to RTML Model Store​セルを実行します。 成功した場合、モデルの場所とモデルIDはどちらも応答に返されます。

自分のモデルのアップロード

ドメイン固有言語(DSL)の作成

この節では、DSLの作成について概説します。 ONNXノードと共に、データの前処理を含むノードを作成します。 次に、ノードとエッジを用いてDSLグラフを作成する。 エッジは、タプルベースのフォーマット(node_1、node_2)を使用してノードを接続します。 グラフにサイクルは含めないでください。

重要

ONNXノードの使用は必須です。 ONNXノードがないと、アプリケーションは失敗します。

ノードオーサリング

メモ

使用するデータのタイプに基づいて複数のノードを持つ場合があります。 次の例は、リアルタイムML​テンプレート内の1つのノードのみを示しています。 リアルタイムML​テンプレート​ノードオーサリング​のセクションを完全なコードセルに表示してください。

以下のPandasノードは、"import": "map"を使用して、メソッド名をパラメーター内の文字列として読み込み、次にパラメーターをmap関数として入力します。 以下の例では、{'arg': {'dataLayerNull': 'notgiven', 'no': 'no', 'yes': 'yes', 'notgiven': 'notgiven'}}を使用してこれを行います。 マップを配置した後、inplaceTrueまたはFalseに設定するオプションがあります。 変換をインプレイスで適用するかどうかに基づいて、inplaceTrueまたはFalseに設定します。 デフォルトでは"inplace": Falseは新しい列を作成します。 新しい列名の提供のサポートは、以降のリリースで追加されるように設定されています。 最後の行colsは、1つの列名または列のリストにすることができます。 変換を適用する列を指定します。 この例ではleasingが指定されています。 使用可能なノードとその使用方法について詳しくは、ノードリファレンスガイドを参照してください。

# Renaming leasing column using Pandas Node
leasing_mapper_node = Pandas(params={'import': 'map',
                                'kwargs': {'arg': {
                                    'dataLayerNull': 'notgiven', 
                                    'no': 'no', 
                                    'yes': 'yes', 
                                    'notgiven': 'notgiven'}},
                                'inplace': True,
                                'cols': 'leasing'})

DSLグラフの作成

ノードを作成した後、次の手順は、ノードを連結してグラフを作成することです。

開始を行います。

nodes = [json_df_node, 
        to_datetime_node,
        hour_node,
        dayofweek_node,
        age_fillna_node,
        carbrand_fillna_node,
        country_fillna_node,
        cartype_primary_nationality_km_fillna_node,
        carbrand_mapper_node,
        cartype_mapper_node,
        country_mapper_node,
        gender_mapper_node,
        leasing_mapper_node,
        age_to_int_node,
        age_bins_node,
        dummies_node, 
        onnx_node]

次に、ノードをエッジで接続します。 各タプルはEdge接続です。

ヒント

ノードは互いに線形的に依存しているので(各ノードは前のノードの出力に依存しています)、単純なPythonリストの理解を使ってリンクを作成できます。 ノードが複数の入力に依存する場合は、独自の接続を追加してください。

edges = [(nodes[i], nodes[i+1]) for i in range(len(nodes)-1)]

ノードを接続したら、グラフを作成します。 下のセルは必須で、編集または削除できません。

dsl = GraphBuilder.generate_dsl(nodes=nodes, edges=edges)
pprint(json.loads(dsl))

完了すると、各ノードとそれらにマッピングされたパラメーターを含むedgeオブジェクトが返されます。

エッジリターン

Edgeに公開(ハブ)

メモ

リアルタイム機械学習は、Adobe Experience Platformハブに一時的に導入され、管理されます。 詳しくは、リアルタイム機械学習アーキテクチャの概要セクションを参照してください。

DSLグラフを作成したら、Edgeにグラフを配信できます。

重要

頻繁にEdgeに発行しないでください。これはEdgeノードに大きな負荷を与える可能性があります。 同じモデルを複数回パブリッシュすることはお勧めしません。

edge_utils = EdgeUtils()
(edge_location, service_id) = edge_utils.publish_to_edge(dsl=dsl)
print(f'Edge Location: {edge_location}')
print(f'Service ID: {service_id}')

DSLの更新とEdgeへの再公開(オプション)

DSLを更新する必要がない場合は、スコアにスキップできます。

メモ

次のセルは、Edgeに公開された既存のDSLを更新する場合にのみ必要です。

モデルは開発を続ける可能性が高い。 新しいサービスを作成する代わりに、既存のサービスを新しいモデルで更新できます。 更新したいノードを定義し、新しいIDを割り当ててから、新しいDSLをEdgeに再度アップロードすることができます。

次の例では、ノード0は新しいIDで更新されます。

# Update the id of Node 0 with a random uuid.

dsl_dict = json.loads(dsl)
print(f"ID of Node 0 in current DSL: {dsl_dict['edge']['applicationDsl']['nodes'][0]['id']}")

new_node_id = str(uuid.uuid4())
print(f'Updated Node ID: {new_node_id}')

dsl_dict['edge']['applicationDsl']['nodes'][0]['id'] = new_node_id

更新されたノード

ノードIDを更新した後、更新されたDSLをEdgeに再公開できます。

# Republish the updated DSL to Edge
(edge_location_ret, service_id, updated_dsl) = edge_utils.update_deployment(dsl=json.dumps(dsl_dict), service_id=service_id)
print(f'Updated dsl: {updated_dsl}')

更新されたDSLが返されます。

更新されたDSL

スコアリング

Edgeに投稿した後、スコアリングはクライアントからのPOSTリクエストによって行われます。 通常、これはMLスコアを必要とするクライアントアプリケーションから実行できます。 ポストマンからもできる。 リアルタイムML​テンプレートは、EdgeUtilsを使用してこのプロセスを示します。

メモ

スコアリング開始の前に、少しの処理時間が必要です。

# Wait for the app to come up
import time
time.sleep(20)

トレーニングで使用したのと同じスキーマを使用して、サンプルスコアリングデータが生成されます。 このデータは、スコアリングデータフレームを作成し、スコアリングディクショナリに変換するために使用されます。 リアルタイムML​テンプレートを完全なコードセルに表示してください。

スコアリングデータ

エッジエンドポイントに対するスコア

リアルタイムML​テンプレート内の次のセルを使用して、Edgeサービスに対してスコアを付けます。

エッジに対するスコア

スコアリングが完了すると、Edge URL、ペイロード、およびEdgeからのスコア出力が返されます。

Edgeからデプロイ済みのアプリをリスト

Edge上に現在デプロイされているアプリのリストを生成するには、次のコードセルを実行します。 このセルは編集または削除できません。

services = edge_utils.list_deployed_services()
print(services)

返される応答は、デプロイ済みのサービスの配列です。

[
    {
        "created": "2020-05-25T19:18:52.731Z",
        "deprecated": false,
        "id": "40eq76c0-1c6f-427a-8f8f-54y9cdf041b7",
        "type": "edge",
        "updated": "2020-05-25T19:18:52.731Z"
    }
]

デプロイ済みのアプリケーションまたはサービスIDをEdgeから削除する(オプション)

注意

このセルは、デプロイ済みのEdgeアプリケーションを削除するために使用します。 デプロイ済みのEdgeアプリケーションを削除する必要がない場合は、次のセルを使用しないでください。

if edge_utils.delete_from_edge(service_id=service_id):
    print(f"Deleted service id {service_id} successfully")
else:
    print(f"Failed to delete service id {service_id}")

次の手順

上記のチュートリアルに従うことで、ONNXモデルのトレーニングとReal-time Machine Learningモデルストアへのアップロードに成功しました。 さらに、リアルタイム機械学習モデルにスコアを割り当て、導入しています。 モデルオーサリングに使用できるノードの詳細については、ノードリファレンスガイドを参照してください。

このページ