Machine Learning Designer の Python スクリプトコンポーネントを使用して、依存関係パッケージをインストールし、カスタム Python 関数を実行します。
コンポーネントの場所
[Python Script] コンポーネントは、Machine Learning Designer コンポーネントリストの [UserDefinedScript] フォルダーにあります。
前提条件
-
DLC の権限が付与されていること。 詳細については、「クラウドサービスの依存関係と権限:DLC」をご参照ください。
-
Python スクリプトコンポーネントは、DLC コンピューティングリソースで実行されます。 DLC コンピューティングリソースをワークスペースに関連付けます。 ワークスペースの管理。
-
Python スクリプトコンポーネントはコードを OSS に保存します。 OSS バケットを作成する必要があります。 詳細については、「バケットの作成」をご参照ください。
重要OSS バケットは、Machine Learning Designer および DLC と同じリージョンにある必要があります。
-
RAM ユーザーは、ワークスペースで アルゴリズム開発 ロールを持っている必要があります。 詳細については、「ワークスペースメンバーの管理」をご参照ください。 MaxCompute をデータソースとして使用するには、[MaxCompute Developer] ロールも付与する必要があります。
コンポーネントの設定
-
入力ポート
Python スクリプトコンポーネントには 4 つの入力ポートがあります。 これらを OSS パスまたは MaxCompute テーブルからのデータに接続します。
-
OSS パス入力
上流コンポーネントの OSS パスからの入力は、スクリプトが実行されるノードにマウントされます。 システムはマウントされたファイルパスを引数として渡します。 たとえば、
--input1 /ml/input/data/input1は最初の入力ポートのパスを指定します。 スクリプト内でローカルファイルとして/ml/input/data/input1からマウントされたファイルを読み取ります。 -
MaxCompute テーブル入力
MaxCompute テーブル入力はマウントされません。 システムはテーブル情報を URI 引数として渡します。 たとえば、
python main.py --input1 odps://some-project-name/tables/tableは、最初の入力ポートの MaxCompute テーブルを示します。 コードテンプレートのparse_odps_url関数を使用して、ProjectName、TableName、Partitionなどのメタデータを解析します。 詳細については、「使用例」をご参照ください。
-
-
出力ポート
Python スクリプトコンponentには 4 つの出力ポートがあります。 [OSS Output Port 1] と [OSS Output Port 2] は OSS パスに出力します。 [Table Output Port 1] と [Table Output Port 2] は MaxCompute テーブルに出力します。
-
OSS パス出力
[Code Config] タブの [Job output path] に設定された OSS パスは、
/ml/output/にマウントされます。 [OSS Output Port 1] と [OSS Output Port 2] は、/ml/output/output1と/ml/output/output2に対応します。 スクリプトでこれらのディレクトリにファイルを書き込み、下流コンポーネントに渡します。 -
MaxCompute テーブル出力
ワークスペースに MaxCompute プロジェクトがある場合、システムは一時テーブルの URI をスクリプトに渡します。例:
python main.py --output3 odps://<some-project-name>/tables/<output-table-name>。 PyODPS を使用してこのテーブルを作成してデータを書き込み、接続を介して下流コンポーネントに渡します。
-
-
パラメーター
[Code Config]
パラメーター
説明
[Job output path]
ジョブ出力用の OSS パス。
-
設定された OSS ディレクトリは、ジョブコンテナ内の
/ml/output/にマウントされます。/ml/output/に書き込まれたデータは、対応する OSS ディレクトリに永続化されます。 -
出力ポートの [OSS Output-1] と [OSS Output-2] は、
/ml/output/配下のサブパスoutput1とoutput2に対応します。 OSS 出力ポートが下流コンポーネントに接続されると、下流コンポーネントは対応するサブパスからデータを受信します。
[Code source]
(いずれかを選択)
[Literal code]
-
[Python code]:コードが保存される OSS パス。 エディターで記述されたコードはこのパスに保存されます。 デフォルトのファイル名は
main.pyです。重要初めて [Save] をクリックする前に、指定した OSS パスに同じ名前のファイルが含まれていないことを確認してください。 そうしない場合、既存のファイルは上書きされます。
-
Python コードエディター:エディターはデフォルトでサンプルコードを提供します。 詳細については、「使用例」をご参照ください。 エディターで直接コードを記述してください。
[Specify Git configuration]
-
[Git repository address]:Git リポジトリのアドレス。
-
[Code branch]:コードブランチ。 デフォルト値は [master] です。
-
[Code commit]:コミット ID。 ブランチよりも優先されます。 指定した場合、ブランチ設定は無視されます。
-
[Git username]:プライベートリポジトリにアクセスする必要がある場合に必須です。
-
[Git access token]:プライベートコードリポジトリにアクセスするために必要です。 詳細については、「付録:GitHub アカウントトークンの取得」をご参照ください。
[Select code source]
-
[Select code source repositories]:作成されたコード設定を選択します。 詳細については、「コード設定」をご参照ください。
-
[Code branch]:コードブランチ。 デフォルト値は [master] です。
-
[Code commit]:コミット ID。 ブランチよりも優先されます。 指定した場合、ブランチ設定は無視されます。
[Select OSS path]
[OSS Code Path] フィールドで、コードがアップロードされているパスを選択してください。
[Command]
実行するコマンド。例:
python main.py。説明システムはスクリプト名とポート接続に基づいて実行コマンドを生成します。 手動での設定は不要です。
[Advanced option]
-
[Third-party dependencies]:Python の
requirements.txt形式でサードパーティの依存関係を指定してください。 システムはノードが実行される前にこれらのライブラリをインストールします。cycler==0.10.0 # matplotlib 経由 kiwisolver==1.2.0 # matplotlib 経由 matplotlib==3.2.1 numpy==1.18.5 pandas==1.0.4 pyparsing==2.4.7 # matplotlib 経由 python-dateutil==2.8.1 # matplotlib、pandas 経由 pytz==2020.1 # pandas 経由 scipy==1.4.1 # seaborn 経由 -
[Enable container monitoring]:フォールトトレランス監視パラメーターの設定テキストボックスを表示します。
[Run Config]
パラメーター
説明
リソースグループを選択
パブリック DLC リソースグループを選択してください。
-
パブリックリソースグループの場合、[InstanceType] を設定してください。 [CPU] または [GPU] インスタンスを選択してください。 デフォルト:
ecs.c6.large。
デフォルトでは、現在のワークスペースのデフォルトの DLC クラウドネイティブリソースグループが使用されます。
VPC 設定
既存の Virtual Private Cloud (VPC) を選択してください。
セキュリティグループ
既存のセキュリティグループを選択してください。
[Advanced option]
このオプションを選択した場合は、次のパラメーターを設定してください。
-
[Instance count]:インスタンス数。 デフォルト値は 1 です。
-
[Job image URI]:ジョブイメージの URI。 デフォルトのイメージは XGBoost 1.6.0 を使用します。 ディープラーニングフレームワークが必要な場合は、イメージを変更してください。
-
[Job type]:コードが分散実行用に実装されている場合にのみ変更してください。 サポートされている値:
-
XGBoost/LightGBM Job
-
TensorFlow Job
-
PyTorch Job
-
MPI Job
-
-
使用例
デフォルトのサンプルコード
Python スクリプトコンポーネントは、デフォルトで次のサンプルコードを提供します。
import os
import argparse
import json
"""
Python スクリプトコンポーネントのサンプルコード
"""
# 現在のワークスペースのデフォルトの MaxCompute 実行環境。MaxCompute プロジェクト名とエンドポイントを含みます。
# この環境は、現在のワークスペースに MaxCompute プロジェクトが存在する場合にのみ挿入されます。
# 例:{"endpoint": "http://service.cn.maxcompute.aliyun-inc.com/api", "odpsProject": "lq_test_mc_project"}
ENV_JOB_MAX_COMPUTE_EXECUTION = "JOB_MAX_COMPUTE_EXECUTION"
def init_odps():
from odps import ODPS
# 現在のワークスペースのデフォルトの MaxCompute プロジェクトに関する情報。
mc_execution = json.loads(os.environ[ENV_JOB_MAX_COMPUTE_EXECUTION])
o = ODPS(
access_id="<YourAccessKeyId>",
secret_access_key="<YourAccessKeySecret>",
# プロジェクトが配置されているリージョンに基づいてエンドポイントを選択します。例:http://service.cn-shanghai.maxcompute.aliyun-inc.com/api
endpoint=mc_execution["endpoint"],
project=mc_execution["odpsProject"],
)
return o
def parse_odps_url(table_uri):
from urllib import parse
parsed = parse.urlparse(table_uri)
project_name = parsed.hostname
r = parsed.path.split("/", 2)
table_name = r[2]
if len(r) > 3:
partition = r[3]
else:
partition = None
return project_name, table_name, partition
def parse_args():
parser = argparse.ArgumentParser(description="PythonV2 コンポーネントスクリプトの例。")
parser.add_argument("--input1", type=str, default=None, help="コンポーネント入力ポート 1。")
parser.add_argument("--input2", type=str, default=None, help="コンポーネント入力ポート 2。")
parser.add_argument("--input3", type=str, default=None, help="コンポーネント入力ポート 3。")
parser.add_argument("--input4", type=str, default=None, help="コンポーネント入力ポート 4。")
parser.add_argument("--output1", type=str, default=None, help="OSS 出力ポート 1。")
parser.add_argument("--output2", type=str, default=None, help="OSS 出力ポート 2。")
parser.add_argument("--output3", type=str, default=None, help="MaxComputeTable 出力 1。")
parser.add_argument("--output4", type=str, default=None, help="MaxComputeTable 出力 2。")
args, _ = parser.parse_known_args()
return args
def write_table_example(args):
# 例:PAI が提供するパブリックテーブルから、テーブル出力ポート 1 (--output3) に指定された一時テーブルにデータをコピーする SQL 文を実行します。
output_table_uri = args.output3
o = init_odps()
project_name, table_name, partition = parse_odps_url(output_table_uri)
o.run_sql(f"create table {project_name}.{table_name} as select * from pai_online_project.heart_disease_prediction;")
def write_output1(args):
# 例:マウントされた OSS パス (OSS 出力ポート 1 のサブディレクトリ) にデータ結果を書き込み、結果は接続を介して下流コンポーネントに渡すことができます。
output_path = args.output1
os.makedirs(output_path, exist_ok=True)
p = os.path.join(output_path, "result.text")
with open(p, "w") as f:
f.write("TestAccuracy=0.88")
if __name__ == "__main__":
args = parse_args()
print("Input1={}".format(args.input1))
print("Output1={}".format(args.output1))
# write_table_example(args)
# write_output1(args)
共通関数の説明:
-
init_odps():MaxCompute テーブルデータを読み取るための ODPS インスタンスを初期化します。 [AccessKeyId] と [AccessKeySecret] を指定してください。 詳細については、「AccessKey ペアの取得」をご参照ください。 -
parse_odps_url(table_uri)は、入力された MaxCompute テーブル URI を解析し、プロジェクト名、テーブル名、およびパーティションを返します。table_uriのフォーマットはodps://${your_projectname}/tables/${table_name}/${pt_1}/${pt_2}/で、たとえばodps://test/tables/iris/pa=1/pb=1のようになります。ここで、pa=1/pb=1は多階層パーティションです。 -
parse_args():スクリプトに渡される引数を解析します。 入力データと出力データは、引数として実行スクリプトに渡されます。
例 1:他のコンポーネントとの連携
この例では、心臓病予測テンプレートを変更して、Python Script コンポーネントを他の Machine Learning Designer コンポーネントと組み合わせて使用する方法を示します。パイプライン構成:
-
心臓病予測テンプレートからパイプラインを作成して開いてください。 詳細については、「心臓病予測」をご参照ください。
-
Python スクリプトコンポーネントをキャンバスにドラッグし、
SMOTEに名前を変更して、次のコードを設定してください。重要imblearnライブラリはデフォルトイメージに含まれていません。 [Code Config] タブの [Third-party dependencies] フィールドにimblearnを追加してください。 ライブラリは、ノードが実行される前に自動的にインストールされます。import argparse import json import os from odps.df import DataFrame from imblearn.over_sampling import SMOTE from urllib import parse from odps import ODPS ENV_JOB_MAX_COMPUTE_EXECUTION = "JOB_MAX_COMPUTE_EXECUTION" def init_odps(): # 現在のワークスペースのデフォルトの MaxCompute プロジェクトに関する情報。 mc_execution = json.loads(os.environ[ENV_JOB_MAX_COMPUTE_EXECUTION]) o = ODPS( access_id="<Your_AccessKeyId>", secret_access_key="<Your_AccessKeySecret>", # プロジェクトが配置されているリージョンに基づいてエンドポイントを選択します。例:http://service.cn-shanghai.maxcompute.aliyun-inc.com/api endpoint=mc_execution["endpoint"], project=mc_execution["odpsProject"], ) return o def get_max_compute_table(table_uri, odps): parsed = parse.urlparse(table_uri) project_name = parsed.hostname table_name = parsed.path.split('/')[2] table = odps.get_table(project_name + "." + table_name) return table def run(): parser = argparse.ArgumentParser(description='PythonV2 コンポーネントスクリプトの例。') parser.add_argument( '--input1', type=str, default=None, help='コンポーネント入力ポート 1。' ) parser.add_argument( '--output3', type=str, default=None, help='MaxComputeTable 出力 1。' ) args, _ = parser.parse_known_args() print('Input1={}'.format(args.input1)) print('output3={}'.format(args.output3)) o = init_odps() imbalanced_table = get_max_compute_table(args.input1, o) df = DataFrame(imbalanced_table).to_pandas() sm = SMOTE(random_state=2) X_train_res, y_train_res = sm.fit_resample(df, df['ifhealth'].ravel()) new_table = o.create_table(get_max_compute_table(args.output3, o).name, imbalanced_table.schema, if_not_exists=True) with new_table.open_writer() as writer: writer.write(X_train_res.values.tolist()) if __name__ == '__main__': run()<Your_AccessKeyId> と <Your_AccessKeySecret> を独自の値に置き換えてください。 詳細については、「AccessKey ペアの取得」をご参照ください。
-
[SMOTE] コンポーネントを [Split] コンポーネントの下流に接続してください。 SMOTE は、少数派クラスの合成サンプルを作成することで、クラス分布のバランスをとるためにトレーニングデータをオーバーサンプリングします。
-
[SMOTE] コンポーネントからの新しいデータを [Logistic Regression for Binary Classification] コンポーネントに接続してトレーニングしてください。
-
トレーニング済みのモデルを、左側のブランチと同じ予測データおよび評価コンポーネントに接続して、並べて比較してください。 コンポーネントの実行後、可視化アイコン (
) をクリックして評価結果を表示してください。モデル評価の結果、オーバーサンプリングなしの [Binary Classification Evaluation] の ROC AUC は
0.924で、混同行列は true-0/predicted-0:43、true-0/predicted-1:6、true-1/predicted-0:9、true-1/predicted-1:33 でした。 SMOTE オーバーサンプリングありの [Binary Classification Evaluation-2] の ROC AUC は0.917で、混同行列は true-0/predicted-0:41、true-0/predicted-1:8、true-1/predicted-0:9、true-1/predicted-1:33 でした。追加のオーバーサンプリングではモデルのパフォーマンスが大幅に向上しないことから、元のサンプル分布とモデルがすでに効果的であったことがわかります。
例 2:DLC ジョブのオーケストレーション
Machine Learning Designer で複数の Python Script コンポーネントを接続して、DLC ジョブのパイプラインをオーケストレーションします。次の例では、実行順序を制御するために DAG で構成された 4 つの DLC ジョブを開始します。
DLC ジョブコードが上流ノードからデータを読み取ったり、下流ノードにデータを渡したりしない場合、接続はスケジューリングの依存関係と実行順序のみを表します。
ワークフローの DAG トポロジは、[DLC Job 1] → [DLC Job 2] → [DLC Job 3]、[DLC Job 1] → [DLC Job 4]、[DLC Job 2] → [DLC Job 4] です。 各 DLC ジョブノードの [Code Config] タブで、以下を設定してください。
-
[OSS Authorization]:OSS へのアクセスを承認してください。
-
[Job output path]:出力場所を指定してください。
-
[Code path]:例:
oss://xxx/python/。 -
[Code]:Python コードファイルを編集してください。 たとえば、DLC Job 4 は、内容が
import time; print("DLC task4"); time.sleep(5)であるmain4.pyに対応します。
パイプラインを DataWorks にデプロイして、スケジュール実行してください。 詳細については、「DataWorks を使用した Machine Learning Designer パイプラインのオフライン実行のスケジューリング」をご参照ください。
例 3:グローバル変数の受け渡し
-
グローバル変数を設定してください。
Machine Learning Designer パイプラインページで、キャンバスの空白領域をクリックし、右側のペインにある[グローバル変数]タブで変数を設定します。
例えば、変数名
arg1に値test1を、変数名arg2に値1234を追加します。変数は${variable_name}を使用して参照します。変数名は 1~20 文字で、文字で始まる必要があります。グローバル変数をオフラインスケジューリングで使用する場合、オフラインスケジューリングの設定にも同じ変数名を設定してください。 -
2 つの方法のいずれかで、グローバル変数を Python スクリプトコンポーネントに渡すことができます。
-
Python スクリプトコンポーネントノードをクリックし、[Code Config] タブで [Advanced option] を選択した後、[Command] フィールドでグローバル変数を入力パラメーターとして設定してください。 たとえば、
python main.py --arg1 ${arg1} --arg2 ${arg2}と入力すると、コマンドライン引数を通じてグローバル変数がスクリプトに渡されます。 -
Python コードを変更し、
argparseを使用して引数を解析してください。次のコードは、手順 1 で設定したグローバル変数を例として使用しています。 実際のグローバル変数に基づいてコードを更新してください。 [Code Config] タブのコード編集領域のコードを置き換えてください。
import os import argparse import json """ Python スクリプトコンポーネントのサンプルコード """ ENV_JOB_MAX_COMPUTE_EXECUTION = "JOB_MAX_COMPUTE_EXECUTION" def init_odps(): from odps import ODPS mc_execution = json.loads(os.environ[ENV_JOB_MAX_COMPUTE_EXECUTION]) o = ODPS( access_id="<YourAccessKeyId>", secret_access_key="<YourAccessKeySecret>", endpoint=mc_execution["endpoint"], project=mc_execution["odpsProject"], ) return o def parse_odps_url(table_uri): from urllib import parse parsed = parse.urlparse(table_uri) project_name = parsed.hostname r = parsed.path.split("/", 2) table_name = r[2] if len(r) > 3: partition = r[3] else: partition = None return project_name, table_name, partition def parse_args(): parser = argparse.ArgumentParser(description="PythonV2 コンポーネントスクリプトの例。") parser.add_argument("--input1", type=str, default=None, help="コンポーネント入力ポート 1。") parser.add_argument("--input2", type=str, default=None, help="コンポーネント入力ポート 2。") parser.add_argument("--input3", type=str, default=None, help="コンポーネント入力ポート 3。") parser.add_argument("--input4", type=str, default=None, help="コンポーネント入力ポート 4。") parser.add_argument("--output1", type=str, default=None, help="OSS 出力ポート 1。") parser.add_argument("--output2", type=str, default=None, help="OSS 出力ポート 2。") parser.add_argument("--output3", type=str, default=None, help="MaxComputeTable 出力 1。") parser.add_argument("--output4", type=str, default=None, help="MaxComputeTable 出力 2。") # 設定されたグローバル変数に基づいてコードを追加します。 parser.add_argument("--arg1", type=str, default=None, help="引数 1。") parser.add_argument("--arg2", type=int, default=None, help="引数 2。") args, _ = parser.parse_known_args() return args def write_table_example(args): output_table_uri = args.output3 o = init_odps() project_name, table_name, partition = parse_odps_url(output_table_uri) o.run_sql(f"create table {project_name}.{table_name} as select * from pai_online_project.heart_disease_prediction;") def write_output1(args): output_path = args.output1 os.makedirs(output_path, exist_ok=True) p = os.path.join(output_path, "result.text") with open(p, "w") as f: f.write("TestAccuracy=0.88") if __name__ == "__main__": args = parse_args() print("Input1={}".format(args.input1)) print("Output1={}".format(args.output1)) # 設定されたグローバル変数に基づいてコードを追加します。 print("Argument1={}".format(args.arg1)) print("Argument2={}".format(args.arg2)) # write_table_example(args) # write_output1(args)
-