- リリース ノート
- はじめる前に
- スタート アップ ガイド
- プロジェクト
- データセット
- ML パッケージ
- パイプライン
- ML スキル
- ML ログ
- AI Center での Document Understanding
- ライセンス
- 使い方
- 基本的なトラブルシューティング ガイド
データ サイエンティストは、Python か AutoML プラットフォームを使用して、事前トレーニング済みのモデルを構築します。これらのモデルは、RPA 開発者によってワークフロー内で使用されます。
ML パッケージを構造化する
パッケージは一連のわずかな要件に従う必要があります。これらの要件は、モデルのサービングに必要な要素とモデルのトレーニングに必要な要素に分割されます。
サービング コンポーネント
パッケージでは、少なくとも以下のものを提供する必要があります。
- ルートに main.py ファイルがあるフォルダー
- このファイルでは、少なくとも以下の 2 つの関数を実装する Main クラス
__init__(self): 引数は取らず、モデルとモデルのローカル データのいずれか、あるいはその両方をロードします (例:単語埋め込み)。predict(self, input): モデル サービング時に呼び出され、文字列を返す関数
- モデルの実行に必要な依存関係を含む requirements.txt という名前のファイル
パッケージのサービング コンポーネントを推論時のモデルとして考えます。サービング時には、提供された requirements.txt ファイルを使用してコンテナー イメージが作成されます。また、モデルへのエンドポイントとして predict 関数が使用されます。
トレーニングと評価コンポーネント
パッケージは推論に使用できるほか、必要に応じてマシン ラーニング モデルのトレーニングにも使用できます。これは、次の手順で行います。
- main.py ファイルと同じルート フォルダーにファイル train.py を用意します。
- このファイルでは、少なくとも以下の 4 つの関数を実装する Main という名前のクラスを提供します。
__init__を除き、以下の関数はすべて任意ですが、対応するパッケージで実行できるパイプラインの種類が制限されます。__init__(self): 引数は取らず、モデルとモデルのデータのいずれか、あるいはその両方をロードします (例:単語埋め込み)。train(self, training_directory): 任意に構築されたデータを含むディレクトリを入力として取ります。モデルのトレーニングに必要なコードをすべて実行します。この関数は、トレーニング パイプラインの実行時に常に呼び出されます。- c.
evaluate(self, evaluation_directory): 任意に構築されたデータを含むディレクトリを入力として取ります。モードの評価に必要なコードをすべて実行し、その評価に対する単一のスコアを返します。この関数は、評価パイプラインの実行時に常に呼び出されます。 save(self): 引数を取りません。この関数は、モデルを保持するためにtrain関数のそれぞれの呼び出しの後に呼び出されます。process_data(self, input_directory): 任意に構築されたデータを含むinput_directory入力を取ります。この関数はフル パイプラインの実行時にのみ呼び出されます。フル パイプラインの実行時に、この関数は任意のデータ変換を行い、データを分割できます。具体的には、環境変数training_data_directoryで指定したパスに保存されたデータがtrain関数の入力となり、環境変数evaluation_data_directoryで指定したパスに保存されたデータが上記のevaluation関数の入力となります。
データ型を処理する
To make AI Center easier to use within an RPA workflow, the package can be denoted to have one of three input types: String,File and Files (set during package upload time).
String データ
これは一連の文字列です。シリアル化できるデータは、すべてパッケージで使用できます。RPA ワークフローで使用する場合、カスタム アクティビティの使用などによってデータを Robot でシリアル化し、文字列として送信できます。パッケージ アップローダーでは、パッケージの入力の種類として json を選択している必要があります。
データの逆シリアル化は、predict 関数の中で実行されます。以下に、Python でデータを逆シリアル化する例をいくつか示します。
Robot sends raw string to ML Skill Activity
# E.g. skill_input='a customer complaint'`
def predict(self, skill_input):
example = skill_input # No extra processing
# Robot sends json formatted string to ML Skill Activity
# E.g skill_input='{'email': a customer complaint', 'date': 'mm:dd:yy'}'
def predict(self, skill_input):
import json
example = json.loads(skill_input)
# Robot sends json formatted string with number array to ML Skill Activity
# E.g. skill_input='[10, 15, 20]'
def predict(self, skill_input):
import json
import numpy as np
example = np.array(json.loads(skill_input))
# Robot sends json formmatted pandas dataframe
# E.g. skill_input='{"row 1":{"col 1":"a","col 2":"b"},
# "row 2":{"col 1":"c","col 2":"d"}}'
def predict(self, skill_input):
import pandas as pd
example = pd.read_json(skill_input)
Robot sends raw string to ML Skill Activity
# E.g. skill_input='a customer complaint'`
def predict(self, skill_input):
example = skill_input # No extra processing
# Robot sends json formatted string to ML Skill Activity
# E.g skill_input='{'email': a customer complaint', 'date': 'mm:dd:yy'}'
def predict(self, skill_input):
import json
example = json.loads(skill_input)
# Robot sends json formatted string with number array to ML Skill Activity
# E.g. skill_input='[10, 15, 20]'
def predict(self, skill_input):
import json
import numpy as np
example = np.array(json.loads(skill_input))
# Robot sends json formmatted pandas dataframe
# E.g. skill_input='{"row 1":{"col 1":"a","col 2":"b"},
# "row 2":{"col 1":"c","col 2":"d"}}'
def predict(self, skill_input):
import pandas as pd
example = pd.read_json(skill_input)
File データ
これにより、このモデルを呼び出す ML スキル アクティビティ にファイル パスを要求することを通知します。具体的には、このアクティビティがファイル システムからファイルを読み取り、シリアル化したバイト文字列として predict 関数に送信します。したがって、RPA 開発者はワークフロー自体でファイルを読み取ってシリアル化することなく、ファイルにパスを渡すことができます。
ワークフローでは、アクティビティへの入力はファイルへのパスだけです。アクティビティがファイルを読み取ってシリアル化し、ファイル バイトを predict 関数に送信します。データの逆シリアル化は predict 関数でも実行されます。一般的には、以下のようにファイル形式のオブジェクトに直接バイトを読み込みます。
ML Package has been uploaded with *file* as input type. The ML Skill Activity
# expects a file path. Any file type can be passed as input and it will be serialized.
def predict(self, skill_input):
import io
file_like = io.BytesIO(skill_input)
ML Package has been uploaded with *file* as input type. The ML Skill Activity
# expects a file path. Any file type can be passed as input and it will be serialized.
def predict(self, skill_input):
import io
file_like = io.BytesIO(skill_input)
上記のようにシリアル化されたバイトを読み取ることは、読み取りバイナリ フラグをオンにしてファイルを開くことと同じです。モデルをローカルでテストするには、ファイルをバイナリ ファイルとして読み取ります。以下に、イメージ ファイルを読み取ってローカルでテストする例を示します。
main.py where model input is an image
class Main(object):
...
def predict(self, skill_input):
import io
from PIL import Image
image = Image.open(io.BytesIO(skill_input))
...
if__name__ == '_main_':
# Test the ML Package locally
with open('./image-to-test-locally.png', 'rb') as input_file:
file_bytes = input_file.read()
m = Main()
print(m.predict(file bytes))
main.py where model input is an image
class Main(object):
...
def predict(self, skill_input):
import io
from PIL import Image
image = Image.open(io.BytesIO(skill_input))
...
if__name__ == '_main_':
# Test the ML Package locally
with open('./image-to-test-locally.png', 'rb') as input_file:
file_bytes = input_file.read()
m = Main()
print(m.predict(file bytes))
以下に、csv ファイルを読み取って、predict 関数の pandas データフレームを使用する例を示します。
main.py where model input is a csv file
class Main(object):
...
def predict(self, skill_input):
import pandas as pd
data frame = pd.read_csv(io.BytesIO(skill_input))
...
if name == '_main_':
# Test the ML Package locally
with open('./csv—to—test—locally.csv', 'rb') as input_file:
bytes = input_file.read()
m = Main()
print(m.predict(bytes))
main.py where model input is a csv file
class Main(object):
...
def predict(self, skill_input):
import pandas as pd
data frame = pd.read_csv(io.BytesIO(skill_input))
...
if name == '_main_':
# Test the ML Package locally
with open('./csv—to—test—locally.csv', 'rb') as input_file:
bytes = input_file.read()
m = Main()
print(m.predict(bytes))
Files データ
これにより、このモデルを呼び出す ML スキル アクティビティ がファイル パスのリストを要求することを AI Center に通知します。前のケースと同様に、このアクティビティによって各ファイルが読み込まれ、シリアル化されたうえで、バイト文字列のリストが predict 関数に送信されます。
ファイルのリストをスキルに送信できます。ワークフローでは、アクティビティへの入力は、ファイルへのパスをコンマで区切った文字列です。
パッケージのアップロード時にデータ サイエンティストが入力の種類としてファイルのリストを選択します。その場合、データ サイエンティストは、送信されたファイルをそれぞれ逆シリアル化しなければなりません (前述のとおり)。predict 関数への入力は、バイトのリストであり、そのリストの各要素はファイルのバイト文字列です。
任意のデータを保持する
train.py では、実行されたすべてのパイプラインが、パイプライン出力と呼ばれる任意のデータを保持できます。環境変数のアーティファクトからディレクトリ パスに書き込まれるデータはすべて保持されます。パイプラインの詳細ページに移動することによって、このデータをいつでも確認できます。通常、トレーニング/評価ジョブのあらゆる種類のグラフと統計情報は artifacts ディレクトリに保存され、パイプラインの実行後に UI からアクセスできます。
train.py where some historical plot are saved in ./artifacts directory during Full Pipeline execution
# Full pipeline (using process_data) will automatically split data.csv in 2/3 train.csv (which will be in the directory passed to the train function) and 1/3 test.csv
import pandas as pd
from sklearn.model_selection import train_test_split
class Main(object):
...
def process_data(self, data_directory):
d = pd.read_csv(os.path.join(data_directory, 'data.csv'))
d = self.clean_data(d)
d_train, d_test = train_test_split(d, test_size=0.33, random_state=42)
d_train.to_csv(os.path.join(data_directory , 'training', 'train.csv'), index=False)
d_test.to_csv (os.path.join(data__directory , 'test' , 'test.csv'), index=False)
self.save_artifacts(d_train, 'train_hist.png', os.environ["artifacts"])
self.save_artifacts(d_test, 'test_hist.png', os.environ["artifacts"])
...
def save_artifacts(self, data, file_name, artifact_directory):
plot = data.hist()
fig = plot[0][0].get_figure()
fig.savefig(os.path.join(artifact_directory, file_name))
...
train.py where some historical plot are saved in ./artifacts directory during Full Pipeline execution
# Full pipeline (using process_data) will automatically split data.csv in 2/3 train.csv (which will be in the directory passed to the train function) and 1/3 test.csv
import pandas as pd
from sklearn.model_selection import train_test_split
class Main(object):
...
def process_data(self, data_directory):
d = pd.read_csv(os.path.join(data_directory, 'data.csv'))
d = self.clean_data(d)
d_train, d_test = train_test_split(d, test_size=0.33, random_state=42)
d_train.to_csv(os.path.join(data_directory , 'training', 'train.csv'), index=False)
d_test.to_csv (os.path.join(data__directory , 'test' , 'test.csv'), index=False)
self.save_artifacts(d_train, 'train_hist.png', os.environ["artifacts"])
self.save_artifacts(d_test, 'test_hist.png', os.environ["artifacts"])
...
def save_artifacts(self, data, file_name, artifact_directory):
plot = data.hist()
fig = plot[0][0].get_figure()
fig.savefig(os.path.join(artifact_directory, file_name))
...
TensorFlow を使用する
モデルの開発時には、サービスの提供に使用するのと同じスレッドに TensorFlow グラフを読み込む必要があります。それには、既定のグラフを使用する必要があります。
以下に、必要な変更の例を示します。
import tensorflow as tf
class Main(object):
def __init__(self):
self.graph = tf.get_default_graph() # Add this line
...
def predict(self, skill_input):
with self.graph.as_default():
...
import tensorflow as tf
class Main(object):
def __init__(self):
self.graph = tf.get_default_graph() # Add this line
...
def predict(self, skill_input):
with self.graph.as_default():
...
GPU の使用状況に関する情報
When GPU is enabled at skill creation time, it is deployed on an image with NVIDIA GPU driver 418, CUDA Toolkit 10.0 and CUDA Deep Neural Network Library (cuDNN) 7.6.5 runtime library.
例
トレーニングがないシンプルな Ready-to-Serve ML モデル
この例では、業務上の問題にモデルの再トレーニングは必要ありません。したがって、サービングするシリアル化したモデル IrisClassifier.sav をパッケージに置く必要があります。
-
初期プロジェクト ツリー (main.py と requirements.txt がないもの)
IrisClassifier/ - IrisClassifier.savIrisClassifier/ - IrisClassifier.sav -
ルート フォルダーに追加する main.py の例:
from sklearn.externals import joblib import json class Main(object): def __init__(self): self.model = joblib.load('IrisClassifier.sav') def predict(self, X): X = json.loads(X) result = self.model.predict_proba(X) return json.dumps(result.tolist())from sklearn.externals import joblib import json class Main(object): def __init__(self): self.model = joblib.load('IrisClassifier.sav') def predict(self, X): X = json.loads(X) result = self.model.predict_proba(X) return json.dumps(result.tolist()) -
requirements.txt を追加します。
scikit-learn==0.19.0scikit-learn==0.19.0注:There are some constraints that need to be respected on pip libraries. Make sure that you can install libraries under the following constraint files:
itsdangerous<2.1.0 Jinja2<3.0.5 Werkzeug<2.1.0 click<8.0.0itsdangerous<2.1.0 Jinja2<3.0.5 Werkzeug<2.1.0 click<8.0.0これをテストするには、新しい環境で次のコマンドを使用し、すべてのライブラリが適切にインストールされることを確認します。
pip install -r requirements.txt -c constraints.txtpip install -r requirements.txt -c constraints.txt -
最終的なフォルダー構造は以下のとおりです。
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txtIrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt
Simple ready-to-serve model with training enabled
この例では、業務上の問題はモデルの再トレーニングが必要です。上記のパッケージに構築することで、以下が得られます。
-
初期プロジェクト ツリー (サービング専用パッケージ):
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txtIrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt -
ルート フォルダーに追加する train.py の例:
import pandas as pd import joblib class Main(object): def __init__(self): self.model_path = './IrisClassifier.sav' self.model = joblib.load(self.model_path) def train(self, training_directory): (X,y) = self.load_data(os.path.join(training_directory, 'train.csv')) self.model.fit(X,y) def evaluate(self, evaluation_directory): (X,y) = self.load_data(os.path.join(evaluation_directory, 'evaluate.csv')) return self.model.score(X,y) def save(self): joblib.dump(self.model, self.model_path) def load_data(self, path): # The last column in csv file is the target column for prediction. df = pd.read_csv(path) X = df.iloc[:, :-1].get_values() y = df.iloc[:, 'y'].get_values() return X,yimport pandas as pd import joblib class Main(object): def __init__(self): self.model_path = './IrisClassifier.sav' self.model = joblib.load(self.model_path) def train(self, training_directory): (X,y) = self.load_data(os.path.join(training_directory, 'train.csv')) self.model.fit(X,y) def evaluate(self, evaluation_directory): (X,y) = self.load_data(os.path.join(evaluation_directory, 'evaluate.csv')) return self.model.score(X,y) def save(self): joblib.dump(self.model, self.model_path) def load_data(self, path): # The last column in csv file is the target column for prediction. df = pd.read_csv(path) X = df.iloc[:, :-1].get_values() y = df.iloc[:, 'y'].get_values() return X,y -
必要に応じて requirements.txt を編集します。
pandas==1.0.1 scikit-learn==0.19.0pandas==1.0.1 scikit-learn==0.19.0 -
最終的なフォルダー (パッケージ) 構造は以下のとおりです。
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.pyIrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.py注:これで、このモデルはまずサービングできるようになりました。この後、Robot または人間参加型プロセスを介して新しいデータ ポイントがシステムに追加されると、train.py を活用してトレーニング パイプラインと評価パイプラインを作成できます。