Snowflakeモデルレジストリ¶
注釈
このトピックで説明するモデルレジストリAPIは、パッケージバージョン1.5.0で一般的に利用可能です。
Snowflakeモデルレジストリを使用すると、派生元に関係なく、Snowflakeでモデルとそのメタデータを安全に管理できます。モデルレジストリは、機械学習モデルをSnowflakeのファーストクラスのスキーマレベルオブジェクトとして格納することにより、組織内の他の人たちが容易に見つけて使用できるようにします。Snowpark ML ライブラリのPythonクラスを使用してレジストリを作成し、そこにモデルを格納できます。モデルは複数のバージョンを持つことができ、1つのバージョンをデフォルトとして指定することができます。
モデルを格納したら、そのメソッド(関数やストアドプロシージャに相当)を呼び出して、推論などのモデル操作をSnowflake 仮想ウェアハウス で実行することができます。
Tip
Snowflake Model Registryなど、Snowpark ML のエンドツーエンドのワークフローの例については、 Snowparkを使用した機械学習入門 ML をご参照ください。
Microsoft Azure Machine LearningまたはAmazon SageMaker にモデルがある場合は、 Azure ML および SageMaker から Snowpark ML へのモデルの展開 をご参照ください。
Snowflake Model Registry Python API で最も重要なクラスは以下の通りです。
snowflake.ml.registry.Registry: スキーマ内のモデルを管理します。
snowflake.ml.model.Model: モデルを表します。
snowflake.ml.model.ModelVersion: モデルのバージョンを表します。
Snowflake Model Registryは、以下のタイプのモデルをサポートしています。
scikit-learn
XGBoost
LightGBM
CatBoost
PyTorch
TensorFlow
MLFlow PyFunc
センテンストランスフォーマー
Hugging Faceパイプライン
snowflake.ml.model.CustomModel
クラスを介した他のタイプのモデル( Snowflakeモデルレジストリへのカスタムモデルの保存 を参照)。
このトピックでは、Snowpark ML を使用して、Pythonでレジストリ操作を実行する方法について説明します。また、 SQL で多くのレジストリ操作を実行できます。 モデルコマンド をご参照ください。
必要な権限¶
モデルを作成するには、モデルを作成するスキーマを所有するか、そのスキーマに対する CREATE MODEL 権限を持っている必要があります。モデルを使用するには、そのモデルを所有しているか、そのモデルに対する USAGE 権限を持っている必要があります。USAGE権限により、付与対象者はモデルの内部を見ることなく推論を行うことができます。
ユーザーのロールがモデル上で USAGE、 Snowsightのモデルレジストリページ に表示されます。詳細については、 アクセス制御権限 をご参照ください。
注釈
現在、モデルは複製をサポートしていません。
現在の制限と問題¶
Snowflakeモデルレジストリには現在、以下の制限があります。
Snowflake Native Apps ではレジストリを使用できません。
モデルは共有したりクローン化したりすることはできず、複製中はスキップされます。
snowflake-ml-python
パッケージのバージョン1.5.0および1.5.1には以下の既知の問題があります。これらの問題が解決されるまでは、提供されている回避策を使用してください。
Snowflakeリリース8.23以前では、ライブラリは 所有者の権限ストアドプロシージャ では動作しません。代わりに、呼び出し元権限ストアドプロシージャを使用します。
ストアドプロシージャにおいて、モデルのログを取るには、ローカルのSnowpark MLライブラリのコピーをモデルに埋め込む必要があります。
log_model
の呼び出しで、embed_local_ml_library
オプションを以下のように指定します:registry.log_model(..., options={"embed_local_ml_library": True, ...})
以下の制限は、モデルおよびモデルのバージョンに適用されます。
モデル |
|
---|---|
モデルのバージョン |
|
Snowflakeモデルレジストリを開く¶
モデルはファーストクラスのSnowflakeオブジェクトであり、他のSnowflakeオブジェクトと一緒にデータベースやスキーマ内に編成することができます。Snowflakeモデルレジストリは、スキーマ内のモデルを管理するためのPythonクラスを提供します。したがって、どのSnowflakeスキーマもレジストリとして使用できます。この目的のために、スキーマを初期化したり準備したりする必要はありません。Snowflakeは、 ML.REGISTRY のように、この目的のために1つ以上の専用スキーマを作成することを推奨しています。スキーマは、 CREATE SCHEMA を使用して作成できます。
レジストリのモデルを作成または変更する前に、レジストリを開く必要があります。レジストリを開くと、そのレジストリへの参照が返され、それを使用して新しいモデルを追加したり、既存のモデルへの参照を取得したりすることができます。
from snowflake.ml.registry import Registry
reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
モデルおよびバージョンの登録¶
レジストリへのモデルの追加は、モデルの ログ と呼ばれます。レジストリの log_model
メソッドを呼び出してモデルをログします。Pythonオブジェクトであるモデルをシリアル化し、そこからSnowflakeモデルオブジェクトを作成します。説明などのメタデータを log_model
呼び出しで指定されたモデルに追加します。
各モデルは無制限にバージョンを持つことができます。モデルの追加バージョンをログするには、同じ model_name
で異なる version_name
を指定して log_model
を再度呼び出します。
タグがレジストリに追加されている場合は、モデルにタグを追加することはできません。タグはモデルの属性であり、 log_model
は特定のモデルのバージョンを追加し、最初のバージョン追加時にのみモデルを作成するからです。モデルの最初のバージョンをログした後に、 モデルのタグを更新する ことができます。
次の例では、 clf
は、「classifier,」の略で、コード内で既に作成されたPythonのモデルオブジェクトです。ここに示すように、登録時にコメントを追加することができます。名前とバージョンの組み合わせは、スキーマ内で一意にする必要があります。 conda_dependencies
リストを指定します。指定したパッケージはモデルと合わせて展開されます。
mv = reg.log_model(clf,
model_name="my_model",
version_name="v1",
conda_dependencies=["scikit-learn"],
comment="My awesome ML model",
metrics={"score": 96},
sample_input_data=train_features,
task=type_hints.Task.TABULAR_BINARY_CLASSIFICATION)
ここで log_model
の引数を説明します。
必要な引数
引数 |
説明 |
---|---|
|
サポートされているモデル型のPythonモデルオブジェクト。シリアル化可能(「ピクル化可能」)である必要があります。 |
|
モデルの名前。レジストリでモデルを識別するために |
注釈
モデル名とバージョンの組み合わせは、スキーマ内で一意にする必要があります。
オプションの引数
引数 |
説明 |
---|---|
|
モデルのバージョンを指定する文字列。レジストリでモデルを識別するために |
|
モデルをロードまたは展開する際にインポートするコードディレクトリへのパスのリスト。 |
|
コメント、たとえばモデルの説明など。 |
|
モデルに必要なCondaパッケージのリスト。この引数は Conda形式、つまり |
|
モデルと一緒にピクルする外部モジュールのリスト。scikit-learn、Snowpark ML、 PyTorch、 TorchScript、およびカスタムモデルのサポート。 |
|
モデルバージョンにリンクされたメトリクスを含むディクショナリ。 |
|
モデル作成のオプションを含むディクショナリ。次のオプションはすべてのモデル型で利用できます:
個々のモデル型によっては、追加オプションをサポートしている場合もあります。 特定のモデル型に関する注意事項 をご参照ください。 |
|
モデルで必要な PyPI パッケージのパッケージ仕様のリスト。 |
|
モデル内で実行するPythonのバージョン。デフォルトは |
|
サンプルの入力データを含む DataFrame 。この DataFrame から、モデルが必要とする特徴量名とその型が抽出されます。Snowpark ML と MLFlow 以外のモデルおよびHugging Faceパイプラインでは、この引数か |
|
メソッド署名を、ターゲットメソッド名から入力と出力の署名へのマッピングとしてモデル化します。Snowpark ML と MLFlow 以外のモデルおよびHugging Faceパイプラインでは、この引数か |
|
モデルが解決しようとする問題を定義するタスク。未指定の場合、モデルクラスからモデルタスクを推測するベストエフォートがなされるか、 |
log_model
は、レジストリに追加されたモデルのバージョンを表す snowflake.ml.model.ModelVersion
オブジェクトを返します。
一度登録されると、モデル自体を変更することはできません(メタデータを変更することはできます)。モデルとそのすべてのバージョンを削除するには、レジストリの delete_model メソッドを使用します。
モデルアーティファクトの操作¶
モデルがログに記録された後、その成果物(シリアライズされたPythonオブジェクトや、マニフェストなどの様々なメタデータファイルを含む、モデルをバックアップするファイル)は内部ステージで利用可能になります。アーティファクトを変更することはできませんが、所有するモデルのアーティファクトを表示またはダウンロードすることはできます。
注釈
モデルのUSAGE権限を持っていても、そのアーティファクトにアクセスすることはできません。
ステージからモデルアーティファクトにアクセスするには、例えば GET コマンド や、Snowpark Pythonの同等のコマンド FileOperation.get を使用します。
しかし、通常のステージパス構文を使ってモデルのアーティファクトを扱うことはできません。代わりに、 snow://
URL、Snowflakeのオブジェクトの位置を指定する、より一般的な方法を使用します。例えば、モデル内のバージョンは、 snow://model/<model_name>/versions/<version_name>/
という形式の URL で指定することができます。
モデルの名前と必要なバージョンを知っていれば、 LIST コマンド を使って、次のようにモデルのアーティファクトを表示することができます。
LIST 'snow://model/my_model/versions/V3/';
出力は似ています。
name size md5 last_modified
versions/V3/MANIFEST.yml 30639 2f6186fb8f7d06e737a4dfcdab8b1350 Thu, 18 Jan 2024 09:24:37 GMT
versions/V3/functions/apply.py 2249 e9df6db11894026ee137589a9b92c95d Thu, 18 Jan 2024 09:24:37 GMT
versions/V3/functions/predict.py 2251 132699b4be39cc0863c6575b18127f26 Thu, 18 Jan 2024 09:24:37 GMT
versions/V3/model.zip 721663 e92814d653cecf576f97befd6836a3c6 Thu, 18 Jan 2024 09:24:37 GMT
versions/V3/model/env/conda.yml 332 1574be90b7673a8439711471d58ec746 Thu, 18 Jan 2024 09:24:37 GMT
versions/V3/model/model.yaml 25718 33e3d9007f749bb2e98f19af2a57a80b Thu, 18 Jan 2024 09:24:37 GMT
これらのアーティファクトを取得するには、 SQL GET コマンドを使用します。
GET 'snow://model/model_my_model/versions/V3/MANIFEST.yml'
あるいはSnowpark Pythonと同等です。
session.file.get('snow://model/my_model/versions/V3/MANIFEST.yml', 'model_artifacts')
注釈
モデルのアーティファクトの名前と構成は、モデルのタイプによって異なり、変更されることがあります。上記のアーティファクトリストの例は、あくまで説明用であり、権威あるものではありません。
モデルの削除¶
レジストリの delete_model
メソッドを使用して、モデルとそのすべてのバージョンを削除します。
reg.delete_model("mymodel")
Tip
DROP MODEL を使用して、SQL のモデルを削除することもできます。
レジストリからのモデルの取得¶
各モデルの情報を得るには、 show_models
メソッドを使用します。
model_df = reg.show_models()
Tip
SQL で、 SHOW MODELS を使ってモデルのリストを取得します。
show_models
の結果は、pandas DataFrame です。利用可能なカラムはこちらです。
列 |
説明 |
---|---|
|
モデルが作成された日時。 |
|
モデルの名前。 |
|
モデルが格納されているデータベース。 |
|
モデルが格納されているスキーマ。 |
|
モデルを所有するロールの名前。 |
|
モデルのコメント。 |
|
モデルのバージョンをリストした JSON 配列。 |
|
バージョンを指定せずにモデルを参照する場合に使用されるモデルのバージョン。 |
代わりにレジストリにあるモデルのリストを、それぞれ Model
インスタンスとして取得するには models
メソッドを使用します。
model_list = reg.models()
レジストリから特定のモデルへの参照を名前で取得するには、レジストリの get_model
メソッドを使用します。
m = reg.get_model("MyModel")
注釈
Model
インスタンスは、ログされた元のPythonモデルオブジェクトのコピーではなく、レジストリ内の基になるモデルオブジェクトへの参照です。
models
メソッドで返されたリストのモデル、または get_model
を使用して取得したモデルへの参照があると、 そのメタデータ と そのバージョン を操作することができます。
モデルのメタデータの表示および更新¶
レジストリ内のモデルのメタデータ属性(名前、コメント、タグ、メトリックなど)を表示したり、更新したりすることができます。
コメントの取得および更新¶
モデルのコメントを取得したり、更新したりするには、モデルの comment
属性を使用します。
print(m.comment)
m.comment = "A better description than the one I provided originally"
注釈
description
属性は、 comment
の同義語です。先のコードもこのように書くことができます。
print(m.description)
m.description = "A better description than the one I provided originally"
Tip
ALTER MODEL を使って、 SQL にモデルのコメントを設定することもできます。
モデル名の変更¶
モデルの名前を変更したり移動したりするには、 rename
メソッドを使用します。モデルを別のデータベースまたはスキーマに移動するには、新しい名前として完全修飾名を指定します。
m.rename("MY_MODEL_TOO")
Tip
ALTER MODEL を使用して、SQL のモデル名を変更することもできます。
モデルバージョンの操作¶
モデルは無制限にバージョンを持つことができ、それぞれが文字列で識別されます。希望するバージョンの命名規則を使用することができます。モデルをログすることは、実際にはモデルの 特定のバージョン をログすることです。モデルの追加バージョンをログするには、同じ model_name
で異なる version_name
を指定して log_model
を再度呼び出します。
Tip
SQL で、モデルのバージョンを見るには SHOW VERSIONS IN MODEL を使います。
モデルのバージョンは、 snowflake.ml.model.ModelVersion
クラスのインスタンスで表されます。
モデルの全バージョンのリストを取得するには、モデルオブジェクトの versions
メソッドを呼び出します。結果は ModelVersion
インスタンスのリストです。
version_list = m.versions()
代わりに DataFrame として各モデルの情報を取得するには、モデルの show_versions
メソッドを呼び出します。
version_df = m.show_versions()
できあがった DataFrame には以下の列が含まれます。
列 |
説明 |
---|---|
|
モデルバージョンが作成された日時 |
|
バージョンの名前。 |
|
バージョンが格納されているデータベース。 |
|
バージョンが格納されているスキーマ。 |
|
このバージョンが属するモデルの名前。 |
|
このバージョンがモデルのデフォルトバージョンであるかどうかを示すブール値。 |
|
このバージョンで使用可能な関数名の JSON 配列。 |
|
JSON メタデータをキーと値のペアとして含むオブジェクト(メタデータが指定されていない場合は |
|
モデル定義マニフェストの |
モデルバージョンの削除¶
モデルの delete_version
メソッドを使用してモデルのバージョンを削除できます。
m.delete_version("rc1")
Tip
ALTER MODEL ... DROP VERSION を使用して、 SQL のモデルバージョンを削除することもできます。
デフォルトバージョン¶
モデルのバージョンをデフォルトモデルとして指定することができます。モデルの default
属性を取得または設定して、現在のデフォルトバージョンを(ModelVersion
オブジェクトとして)取得するか、変更(文字列を使用して)します。
default_version = m.default
m.default = "v2"
Tip
SQL では、 ALTER MODEL を使ってデフォルトのバージョンを設定します。
モデルバージョンのエイリアス¶
SQL ALTER MODEL コマンドを使って、モデルのバージョンにエイリアスを割り当てることができます。PythonやSQLでモデルのバージョンへの参照を取得するときなど、バージョン名が必要な場合はどこでもエイリアスを使うことができます。与えられたエイリアスは、一度に1つのモデル・バージョンにのみ割り当てることができます。
自分で作成したエイリアスに加えて、以下のシステムエイリアスはすべてのモデルで利用可能です。
DEFAULT
は、モデルのデフォルトバージョンを指します。FIRST
は、作成時間が最も古いモデルバージョンを指します。LAST
は、作成時間が最新のモデルバージョンを指します。
作成したエイリアス名は、システムエイリアスを含め、モデル内の既存のバージョン名やエイリアスと同じにできません。
モデルバージョンへの参照の取得¶
モデルの特定バージョンへの参照を ModelVersion
インスタンスとして取得するには、モデルの version
メソッドを使用します。モデルのデフォルトバージョンを取得するには、モデルの default
属性を使用します。
m = reg.get_model("MyModel")
mv = m.version("v1")
mv = m.default
モデルの特定バージョン(この例の変数 mv
など)への参照を取得すると、そのコメントやメトリクスを取得または更新し、以下のセクションで示すようにモデルのメソッド(または関数)を呼び出すことができます。
コメントの取得および更新¶
モデルと同様に、モデルのバージョンはコメントを持つことができ、モデルのバージョンの comment
または description
属性を介してアクセスし、設定することができます。
print(mv.comment)
print(mv.description)
mv.comment = "A model version comment"
mv.description = "Same as setting the comment"
Tip
ALTER MODEL ... MODIFY VERSION を使って、SQL のモデルバージョンのコメントを変更することもできます。
メトリクスの取得および更新¶
メトリクスは、予測精度やその他のモデルバージョンの特性を追跡するために使用されるキーと値のペアです。モデルバージョンの作成時にメトリクスを設定することも、 set_metric
メソッドを使用して設定することもできます。メトリクス値は、数値、文字列、リスト、ディクショナリなど、 JSON にシリアル化できる任意のPythonオブジェクトにすることができます。タグとは異なり、メトリクス名と可能な値を事前に定義する必要はありません。
テスト精度のメトリクスは、sklearnの accuracy_score
を使用して生成される場合があります。
from sklearn import metrics
test_accuracy = metrics.accuracy_score(test_labels, prediction)
混同行列はsklearnを使用して同様に生成できます。
test_confusion_matrix = metrics.confusion_matrix(test_labels, prediction)
そして、これらの値をメトリクスとして設定することができます:
# scalar metric
mv.set_metric("test_accuracy", test_accuracy)
# hierarchical (dictionary) metric
mv.set_metric("evaluation_info", {"dataset_used": "my_dataset", "accuracy": test_accuracy, "f1_score": f1_score})
# multivalent (matrix) metric
mv.set_metric("confusion_matrix", test_confusion_matrix)
モデルバージョンのメトリクスをPythonディクショナリとして取得するには、 show_metrics
を使用します。
metrics = mv.show_metrics()
メトリクスを削除するには、 delete_metric
を呼び出します。
mv.delete_metric("test_accuracy")
Tip
また、 ALTER MODEL ... MODIFY VERSION を使用して、 SQL でモデルバージョンのメトリクス(メタデータとして格納される)を変更することもできます。
モデル説明の取得¶
モデルレジストリは、 Shapley値 を計算することで、モデルの結果を説明し、どの入力機能が予測に最も寄与しているかを伝えることができます。このプレビュー機能は、Snowflake 8.31以降で作成されたすべてのモデルビューで、基本モデルの explain
メソッドを通じてデフォルトで利用できます。Pythonの SQL 、またはモデルビューの run
メソッドから explain
を呼び出せます。
この機能の詳細については、 モデルの説明可能性 をご参照ください。
モデルバージョンのエクスポート¶
モデルのファイルをローカルディレクトリにエクスポートするには、 mv.export
を使用します。ディレクトリが存在しない場合は作成されます。
mv.export("~/mymodel/")
デフォルトでは、エクスポートされるファイルには、コード、モデルをロードする環境、モデルの重みが含まれます。ウェアハウスでモデルを実行するために必要なファイルもエクスポートするには、 export_mode = ExportMode.FULL
を指定します。
mv.export("~/mymodel/", export_mode=ExportMode.FULL)
モデルバージョンの読み込み¶
mv.load
を使って、もともとレジストリに追加されていたオリジナルのPythonモデルオブジェクトを読み込みます。そうすれば、Pythonのコードで定義したのと同じように、推論にそのモデルを使うことができます。
clf = mv.load()
モデルの適切な関数を保証するために、ターゲットのPython環境(すなわち、Pythonインタプリターとすべてのライブラリのバージョン)は、モデルがログに記録された環境と同一でなければなりません。 load
の呼び出しで force=True
を指定すると、環境が異なっていてもモデルを強制的にロードします。
Tip
モデルがホストされている環境と同じであることを確認するために、モデルレジストリからconda環境のコピーをダウンロードします。
conda_env = session.file.get("snow://model/<modelName>/versions/<versionName>/runtimes/python_runtime/env/conda.yml", ".")
open("~/conda.yml", "w").write(conda_env)
そして、このファイルから新しいconda環境を作成します。
conda env create --name newenv --file=~/conda.yml
conda activate newenv
オプションの options
引数は、モデルを読み込むためのオプションの辞書です。現在、この引数は use_gpu
オプションのみをサポートしています。
オプション |
型 |
説明 |
デフォルト |
---|---|---|---|
|
|
GPU 固有のロードロジックを有効にします。 |
|
次の例は、 options
引数の使い方を示しています。
clf = mv.load(options={"use_gpu": True})
モデルメソッドの呼び出し¶
モデルのバージョンは、推論や他のモデル操作を実行するための付属関数である メソッド を持つことができます。モデルのバージョンは異なるメソッドを持つことができ、これらのメソッドの署名も異なる場合があります。
モデルバージョンのメソッドを呼び出すには、 mv.run
を使用し、呼び出す関数名を指定し、推論データとその他の必要なパラメーターを含むSnowparkまたはpandas DataFrame を渡します。このメソッドは、Snowflakeウェアハウスで実行されます。
メソッドの戻り値は、渡されたDataFrameのタイプに応じて、Snowparkまたはpandas DataFrameです。Snowpark DataFrames は遅延評価されるため、DataFrame の collect
、 show
、 to_pandas
メソッドが呼び出されたときのみメソッドが実行されます。
注釈
メソッドを起動すると、レジストリへの接続に使用しているセッションで指定されたウェアハウスでメソッドが実行されます。 ウェアハウスサイズの指定 をご参照ください。
次の例は、モデルの predict
メソッドの実行を示しています。このモデルの predict
メソッドは、推論データ(ここでは test_features
)以外にパラメーターを必要としません。必要な場合は、推論データの後に追加の引数として渡されることになります。
remote_prediction = mv.run(test_features, function_name="predict")
remote_prediction.show() # assuming test_features is Snowpark DataFrame
指定されたモデルでどのメソッドが呼び出せるかを確認するには、 mv.show_functions
を呼び出します。このメソッドの返り値は、 ModelFunctionInfo
オブジェクトのリストです。これらの各オブジェクトには以下の属性が含まれます。
name
: Pythonまたは SQL から呼び出せる関数名。target_method
:元のログモデルのPythonメソッド名。
Tip
SQLでモデルメソッドを呼び出すこともできます。 モデルメソッド をご参照ください。
コストの考慮事項¶
Snowflake モデルレジストリを使用すると、標準的なSnowflake消費ベースのコストが発生します。これらには次が含まれます。
モデルのアーティファクト、メタデータ、および関数を格納するためのコスト。ストレージコストに関する一般情報については、 ストレージコストの調査 をご参照ください。
ステージ間のファイルをSnowflakeにコピーするコスト。 COPY FILES をご参照ください。
モデルやモデルのバージョンの表示、モデルのコメント、タグ、メトリクスの変更など、 Snowsight UI や SQL 、Pythonインターフェイスを介したサーバーレスモデルオブジェクト操作のコスト。
ウェアハウスコンピューティングコスト。コストは、モデルの型や学習予測に使用するデータ量によって異なります。Snowflakeのコンピューティングコストに関する一般的な情報については、 コンピューティングコストについて をご参照ください。ウェアハウスのコンピューティングコストは、次のような場合に発生します。
モデルおよびバージョンの作成操作。
モデルのメソッドの呼び出し
特定のモデル型に関する注意事項¶
このセクションでは、特定の型のモデルをSnowflakeモデルレジストリにログするための追加情報を提供します。
Snowpark ML¶
レジストリは、 Snowpark ML Modeling APIs (snowpark.ml.modeling.framework.base.BaseEstimator
から派生したモデル)を使用して作成されたモデルをサポートしています。以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
モデルオブジェクトで利用可能なメソッドの名前のリスト。Snowpark ML モデルは、メソッドが存在すると仮定して、デフォルトで以下のターゲットメソッドを持ちます。 |
Snowpark ML モデルをログする際に sample_input_data
や signatures
を指定する必要はありません。これらはフィッティングの際に自動的に推測されます。
例¶
import pandas as pd
import numpy as np
from sklearn import datasets
from snowflake.ml.modeling.xgboost import XGBClassifier
iris = datasets.load_iris()
df = pd.DataFrame(data=np.c_[iris["data"], iris["target"]], columns=iris["feature_names"] + ["target"])
df.columns = [s.replace(" (CM)", "").replace(" ", "") for s in df.columns.str.upper()]
input_cols = ["SEPALLENGTH", "SEPALWIDTH", "PETALLENGTH", "PETALWIDTH"]
label_cols = "TARGET"
output_cols = "PREDICTED_TARGET"
clf_xgb = XGBClassifier(
input_cols=input_cols, output_cols=output_cols, label_cols=label_cols, drop_input_cols=True
)
clf_xgb.fit(df)
model_ref = registry.log_model(
clf_xgb,
model_name="XGBClassifier",
version_name="v1",
)
model_ref.run(df.drop(columns=label_cols).head(10), function_name='predict_proba')
scikit-learn¶
レジストリは、scikit-learnを使用して作成されたモデル(sklearn.base.BaseEstimator
または sklearn.pipeline.Pipeline
から派生したモデル)をサポートしています。以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
モデルオブジェクトで利用可能なメソッド名。メソッドが存在すると仮定して、scikit-learnモデルはデフォルトで以下のターゲットメソッドを持ちます。 |
scikit-learnモデルをログする場合は、 sample_input_data
か signatures
のどちらかのパラメーターを指定する必要があります。
例¶
from sklearn import datasets, ensemble
iris_X, iris_y = datasets.load_iris(return_X_y=True, as_frame=True)
clf = ensemble.RandomForestClassifier(random_state=42)
clf.fit(iris_X, iris_y)
model_ref = registry.log_model(
clf,
model_name="RandomForestClassifier",
version_name="v1",
sample_input_data=iris_X,
options={
"method_options": {
"predict": {"case_sensitive": True},
"predict_proba": {"case_sensitive": True},
"predict_log_proba": {"case_sensitive": True},
}
},
)
model_ref.run(iris_X[-10:], function_name='"predict_proba"')
XGBoost¶
レジストリは、 XGBoost を使用して作成されたモデル(xgboost.XGBModel
または xgboost.Booster
から派生したモデル)をサポートしています。以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
モデルオブジェクトで利用可能なメソッドの名前のリスト。 |
|
GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で |
レジストリがターゲットメソッドの署名を知ることができるように、 XGBoost モデルをログするときには sample_input_data
か signatures
のどちらかのパラメーターを指定する必要があります。
例¶
import xgboost
from sklearn import datasets, model_selection
cal_X, cal_y = datasets.load_breast_cancer(as_frame=True, return_X_y=True)
cal_X_train, cal_X_test, cal_y_train, cal_y_test = model_selection.train_test_split(cal_X, cal_y)
params = dict(n_estimators=100, reg_lambda=1, gamma=0, max_depth=3, objective="binary:logistic")
regressor = xgboost.train(params, xgboost.DMatrix(data=cal_X_train, label=cal_y_train))
model_ref = registry.log_model(
regressor,
model_name="xgBooster",
version_name="v1",
sample_input_data=cal_X_test,
options={
"target_methods": ["predict"],
"method_options": {
"predict": {"case_sensitive": True},
},
},
)
model_ref.run(cal_X_test[-10:])
PyTorch¶
モデルの forward
メソッドが1つ以上の torch.Tensor
インスタンスを入力として受け入れ、 torch.Tensor
またはそれらのタプルを返す場合、レジストリは、 PyTorch モデル(torch.nn.Module
または torch.jit.ModuleScript
から派生したクラス)をサポートします。レジストリは、モデルを呼び出して結果を返すときに、pandas DataFrames とテンソルの間で変換します。テンソルはデータフレームの列に対応します。
たとえば、モデルは次のような2つのテンソルを受け入れるとします。
import torch
class TorchModel(torch.nn.Module):
def __init__(self, n_input: int, n_hidden: int, n_out: int, dtype: torch.dtype = torch.float32) -> None:
super().__init__()
self.model = torch.nn.Sequential(
torch.nn.Linear(n_input, n_hidden, dtype=dtype),
torch.nn.ReLU(),
torch.nn.Linear(n_hidden, n_out, dtype=dtype),
torch.nn.Sigmoid(),
)
def forward(self, tensor_1: torch.Tensor, tensor_2: torch.Tensor) -> torch.Tensor:
return self.model(tensor_1) + self.model(tensor_2)
torch.Tensor([[1,2],[3,4]])
を tensor_1
として、また torch.Tensor([[5,6], [7,8]])
を tensor_2
として渡す場合は、以下のように DataFrame を作成してモデルに渡します。
import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
そうすると、 tensors
DataFrame は次のようになります。
0 1
0 [1, 2] [5, 6]
1 [3, 4] [7, 8]
同様に、モデルが (torch.Tensor([[1,2],[3,4]]), torch.Tensor([[5,6], [7,8]]))
のような2つのテンソルを返す場合、結果は前述のような DataFrame になります。
PyTorch モデルのサンプル入力データを提供する場合は、テンソルのリスト(pandasの DataFrame に変換される)または DataFrame を提供する必要があります。リストに単一のテンソルを含むことはできますが、テンソル自体は認められません。
モデルのログ¶
以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
モデルオブジェクトで利用可能なメソッドの名前のリスト。PyTorch モデルのデフォルトは |
|
GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で |
PyTorch モデルをログする場合は、 sample_input_data
か signatures
のどちらかのパラメーターを指定する必要があります。
例¶
import torch
import numpy as np
class TorchModel(torch.nn.Module):
def __init__(self, n_input: int, n_hidden: int, n_out: int, dtype: torch.dtype = torch.float32) -> None:
super().__init__()
self.model = torch.nn.Sequential(
torch.nn.Linear(n_input, n_hidden, dtype=dtype),
torch.nn.ReLU(),
torch.nn.Linear(n_hidden, n_out, dtype=dtype),
torch.nn.Sigmoid(),
)
def forward(self, tensor: torch.Tensor) -> torch.Tensor:
return self.model(tensor)
n_input, n_hidden, n_out, batch_size, learning_rate = 10, 15, 1, 100, 0.01
dtype = torch.float32
x = np.random.rand(batch_size, n_input)
data_x = torch.from_numpy(x).to(dtype=dtype)
data_y = (torch.rand(size=(batch_size, 1)) < 0.5).to(dtype=dtype)
model = TorchModel(n_input, n_hidden, n_out, dtype=dtype)
loss_function = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for _epoch in range(100):
pred_y = model.forward(data_x)
loss = loss_function(pred_y, data_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
model_ref = registry.log_model(
model,
model_name="torchModel",
version_name="v1",
sample_input_data=[data_x],
)
model_ref.run([data_x])
TensorFlow¶
tensorflow.Module
または tensorflow.keras.Model
を拡張するモデルは、テンソルを受け取って返す場合、またコンパイル可能またはコンパイルされる場合にサポートされます。
tensorflow.Module
の__call__
メソッドまたはtensorflow.keras.Model
のcall
メソッドは、1つ以上のtensorflow.Tensor
またはtensorflow.Variable
を入力として受け入れ、tensorflow.Tensor
またはtensorflow.Variable
、あるいはこれらの型のタプルを返します。モデルで
Module
を拡張している場合は、コンパイル可能である必要があります。これは、__call__
メソッドが@tensorflow.function
で装飾されていることを意味します。 tf.functionドキュメント をご参照ください。Model
を拡張している場合は、コンパイルする必要があります。 コンパイルドキュメント をご参照ください。
レジストリは、モデルを呼び出して結果を返すときに、pandas DataFrames とテンソルの間で変換します。テンソルはデータフレームの列に対応します。
たとえば、モデルは次のような2つのテンソルを受け入れるとします。
import tensorflow as tf
class KerasModel(tf.keras.Model):
def __init__(self, n_hidden: int, n_out: int) -> None:
super().__init__()
self.fc_1 = tf.keras.layers.Dense(n_hidden, activation="relu")
self.fc_2 = tf.keras.layers.Dense(n_out, activation="sigmoid")
def call(self, tensor_1: tf.Tensor, tensor_2: tf.Tensor) -> tf.Tensor:
input = tensor_1 + tensor_2
x = self.fc_1(input)
x = self.fc_2(x)
return x
tf.Tensor([[1,2],[3,4]])
を tensor_1
として、また tf.Tensor([[5,6], [7,8]])
を tensor_2
として渡す場合は、以下のように DataFrame を作成してモデルに渡します。
import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
そうすると、 tensors
DataFrame は次のようになります。
0 1
0 [1, 2] [5, 6]
1 [3, 4] [7, 8]
同様に、モデルが (tf.Tensor([[1,2],[3,4]]), tf.Tensor([[5,6], [7,8]]))
のような2つのテンソルを返す場合、結果は前述のような DataFrame になります。
TensorFlow モデルのサンプル入力データを提供する場合は、テンソルのリスト(pandasの DataFrame に変換される)または DataFrame を提供する必要があります。リストに単一のテンソルを含むことはできますが、テンソル自体は認められません。
モデルのログ¶
以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
モデルオブジェクトで利用可能なメソッドの名前のリスト。TensorFlow モデルのデフォルトは |
|
GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で |
TensorFlow モデルをログする場合は、 sample_input_data
か signatures
のどちらかのパラメーターを指定する必要があります。
例¶
import tensorflow as tf
import numpy as np
class KerasModel(tf.keras.Model):
def __init__(self, n_hidden: int, n_out: int) -> None:
super().__init__()
self.fc_1 = tf.keras.layers.Dense(n_hidden, activation="relu")
self.fc_2 = tf.keras.layers.Dense(n_out, activation="sigmoid")
def call(self, tensor: tf.Tensor) -> tf.Tensor:
input = tensor
x = self.fc_1(input)
x = self.fc_2(x)
return x
n_input, n_hidden, n_out, batch_size, learning_rate = 10, 15, 1, 100, 0.01
dtype = tf.float32
x = np.random.rand(batch_size, n_input)
data_x = tf.convert_to_tensor(x, dtype=dtype)
raw_data_y = tf.random.uniform((batch_size, 1))
raw_data_y = tf.where(raw_data_y > 0.5, tf.ones_like(raw_data_y), tf.zeros_like(raw_data_y))
data_y = tf.cast(raw_data_y, dtype=dtype)
model = KerasModel(n_hidden, n_out)
model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate), loss=tf.keras.losses.MeanSquaredError())
model.fit(data_x, data_y, batch_size=batch_size, epochs=100)
model_ref = registry.log_model(
model,
model_name="tfModel",
version_name="v1",
sample_input_data=[data_x],
)
model_ref.run([data_x])
MLFlow¶
PyFunc フレーバーを提供する MLFlow モデルがサポートされています。MLFlow モデルに署名がある場合、 signature
引数はモデルから推測されます。署名がない場合は、 signature
か sample_input_data
のどちらかを提供する必要があります。
以下の追加オプションは、 options
ディクショナリで log_model
を呼び出すときに使用できます。
オプション |
説明 |
---|---|
|
MLFlow モデルのアーティファクトの URI。モデルのメタデータで |
|
|
|
|
例¶
import mlflow
from sklearn import datasets, model_selection, ensemble
db = datasets.load_diabetes(as_frame=True)
X_train, X_test, y_train, y_test = model_selection.train_test_split(db.data, db.target)
with mlflow.start_run() as run:
rf = ensemble.RandomForestRegressor(n_estimators=100, max_depth=6, max_features=3)
rf.fit(X_train, y_train)
# Use the model to make predictions on the test dataset.
predictions = rf.predict(X_test)
signature = mlflow.models.signature.infer_signature(X_test, predictions)
mlflow.sklearn.log_model(
rf,
"model",
signature=signature,
)
run_id = run.info.run_id
model_ref = registry.log_model(
mlflow.pyfunc.load_model(f"runs:/{run_id}/model"),
model_name="mlflowModel",
version_name="v1",
conda_dependencies=["mlflow<=2.4.0", "scikit-learn", "scipy"],
options={"ignore_mlflow_dependencies": True}
)
model_ref.run(X_test)
Hugging Faceパイプライン¶
注釈
特定のタイプのHugging Faceパイプラインに期待される入出力の詳細については、 Hugging Faceパイプラインの推測署名 をご参照ください。
レジストリは、 transformers.Pipeline
から派生する 変換器 として定義されたHugging Faceモデルクラスをサポートしています。次のコードは、互換性のあるモデルをログする例です。
lm_hf_model = transformers.pipeline(
task="text-generation",
model="bigscience/bloom-560m",
token="...", # Put your HuggingFace token here.
return_full_text=False,
max_new_tokens=100,
)
lmv = reg.log_model(lm_hf_model, model_name='bloom', version_name='v560m')
重要
huggingface_pipeline.HuggingFacePipelineModel
に基づくモデルは構成データのみを含み、モデルの重みはモデルが使用されるたびにHugging Faceハブからダウンロードされます。
モデルレジストリは現在、ウェアハウスへのモデル展開のみをサポートしています。ウェアハウスは、 特別な構成 がない場合は外部ネットワークアクセスをサポートしません。必要な外部アクセス統合が作成されていたとしても、特定のモデルに必要な統合を指定する方法は今のところありません。
現在のベストプラクティスは、上記の例のように transformers.Pipeline
を使用することです。これにより、モデルの重みがローカルシステムにダウンロードされ、モデル全体がウェアハウスにアップロードされます。その結果、インターネット接続を必要としない自己完結型モデルができます。
レジストリは、パイプラインが以下のリストから1つのタスクを含む場合にのみ、 signatures
引数を推測します。
conversational
fill-mask
question-answering
summarization
table-question-answering
text2text-generation
text-classification
(sentiment-analysis
とも呼ばれます)text-generation
token-classification
(ner
とも呼ばれます)translation
translation_xx_to_yy
zero-shot-classification
sample_input_data
引数は、Hugging Faceモデルでは完全に無視されます。レジストリがターゲットメソッドのシグネチャを知ることができるように、上記のリストにないHugging Faceモデルをログに記録する際には signatures
引数を指定します。
推論された署名を表示するには、 show_functions
メソッドを使用します。たとえば、以下は lmv.show_functions()
の結果であり、 lmv
は上記でログしたモデルです。
{'name': '__CALL__',
'target_method': '__call__',
'signature': ModelSignature(
inputs=[
FeatureSpec(dtype=DataType.STRING, name='inputs')
],
outputs=[
FeatureSpec(dtype=DataType.STRING, name='outputs')
]
)}]
この情報があると、次のようにモデルを呼び出すことができます。
import pandas as pd
remote_prediction = lmv.run(pd.DataFrame(["Hello, how are you?"], columns=["inputs"]))
使用上の注意¶
Hugging Faceのモデルの多くは大型で、標準的なウェアハウスには収まりません。Snowparkに最適化されたウェアハウスを使用するか、モデルの小さいバージョンを選択します。たとえば、
Llama-2-70b-chat-hf
モデルを使用する代わりにLlama-2-7b-chat-hf
を試してみます。Snowflakeウェアハウスには GPUs はありません。CPU に最適化されたHugging Faceモデルのみを使用します。
Hugging Face変換器の中には、入力行ごとにディクショナリの配列を返すものがあります。レジストリはこのような出力を、配列の JSON 表現を含む文字列に変換します。たとえば、複数出力の質問と回答の出力は次のようになります。
[{"score": 0.61094731092453, "start": 139, "end": 178, "answer": "learn more about the world of athletics"}, {"score": 0.17750297486782074, "start": 139, "end": 180, "answer": "learn more about the world of athletics.\""}]
レジストリがターゲットメソッドの署名を知ることができるように、Hugging Faceモデルをログする場合は、 sample_input_data
か signatures
のどちらかのパラメーターを指定する必要があります。
例¶
# Prepare model
import transformers
import pandas as pd
finbert_model = transformers.pipeline(
task="text-classification",
model="ProsusAI/finbert",
top_k=2,
)
# Log the model
mv = registry.log_model(
finbert_model,
model_name="finbert",
version_name="v1",
)
# Use the model
mv.run(pd.DataFrame(
[
["I have a problem with my Snowflake that needs to be resolved asap!!", ""],
["I would like to have udon for today's dinner.", ""],
]
)
)
結果:
0 [{"label": "negative", "score": 0.8106237053871155}, {"label": "neutral", "score": 0.16587384045124054}]
1 [{"label": "neutral", "score": 0.9263970851898193}, {"label": "positive", "score": 0.05286872014403343}]