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 Model Registryは、以下のタイプのモデルをサポートしています。

このトピックでは、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, ...})
    
    Copy

以下の制限は、モデルおよびモデルのバージョンに適用されます。

モデル

  • 最大1000バージョン

モデルのバージョン

  • 最大10メソッド

  • 最大10件のインポート

  • メソッドあたりの最大引数は500

  • 最大100 KB のメタデータ(メトリクスを含む)

  • 最大合計モデルサイズ5GB

  • conda.yml および log_model が内部的に生成するその他のマニフェストファイルを含む、最大構成ファイルサイズは250 KB です。(例えば、モデルに多くの関数があり、すべての関数が多くの引数を持つ場合、この制限を超える可能性があります)。

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")
Copy

モデルおよびバージョンの登録

レジストリへのモデルの追加は、モデルの ログ と呼ばれます。レジストリの 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)
Copy

ここで log_model の引数を説明します。

必要な引数

引数

説明

model

サポートされているモデル型のPythonモデルオブジェクト。シリアル化可能(「ピクル化可能」)である必要があります。

model_name

モデルの名前。レジストリでモデルを識別するために version_name と一緒に使用されます。モデルがログされた後に、名前を変更することはできません。 有効なSnowflake識別子である必要があります

注釈

モデル名とバージョンの組み合わせは、スキーマ内で一意にする必要があります。

オプションの引数

引数

説明

version_name

モデルのバージョンを指定する文字列。レジストリでモデルを識別するために model_name と一緒に使用されます。 有効なSnowflake識別子である必要があります。見つからない場合は、人間が読めるバージョン名が自動的に生成されます。

code_paths

モデルをロードまたは展開する際にインポートするコードディレクトリへのパスのリスト。

comment

コメント、たとえばモデルの説明など。

conda_dependencies

モデルに必要なCondaパッケージのリスト。この引数は Conda形式、つまり "[channel::]package [operator version]" でパッケージ名とオプションのバージョンを指定します。チャネルを指定しない場合は、Snowflakeチャネルになります。

ext_modules

モデルと一緒にピクルする外部モジュールのリスト。scikit-learn、Snowpark ML、 PyTorch、 TorchScript、およびカスタムモデルのサポート。

metrics

モデルバージョンにリンクされたメトリクスを含むディクショナリ。

options

モデル作成のオプションを含むディクショナリ。次のオプションはすべてのモデル型で利用できます:

  • embed_local_ml_library: ローカルSnowpark ML ライブラリのコピーをモデルに埋め込むかどうか。デフォルト: False

  • relax_version: 依存関係のバージョン制約を緩和するかどうか。これは、 ==x.y.z のようなバージョン指定子を <=x.y, <(x+1) のような指定子に置き換えます。デフォルト: True

  • method_options: メソッドごとのオプションのディクショナリ。キーはメソッド名で、値はここで説明する1つ以上のオプションを含むディクショナリです。利用可能なオプションは以下のとおりです。

    • case_sensitive: メソッドとその署名で大文字と小文字を区別するかどうかを示します。大文字と小文字を区別するメソッドを SQL で使用する場合は、二重引用符で囲む必要があります。このオプションでは、メソッド名にアルファベット以外の文字も使用できます。デフォルト: False

    • max_batch_size: ウェアハウスでメソッドが呼び出されたときに、そのメソッドが受け入れる最大バッチサイズ。デフォルト: None (バッチサイズは自動的に決定)

個々のモデル型によっては、追加オプションをサポートしている場合もあります。 特定のモデル型に関する注意事項 をご参照ください。

pip_requirements

モデルで必要な PyPI パッケージのパッケージ仕様のリスト。

python_version

モデル内で実行するPythonのバージョン。デフォルトは None で、ウェアハウスで利用可能な最新バージョンを示します。

sample_input_data

サンプルの入力データを含む DataFrame 。この DataFrame から、モデルが必要とする特徴量名とその型が抽出されます。Snowpark ML と MLFlow 以外のモデルおよびHugging Faceパイプラインでは、この引数か signatures のどちらかを提供する必要があります。

signatures

メソッド署名を、ターゲットメソッド名から入力と出力の署名へのマッピングとしてモデル化します。Snowpark ML と MLFlow 以外のモデルおよびHugging Faceパイプラインでは、この引数か sample_input_data のどちらかを提供する必要があります。

task

モデルが解決しようとする問題を定義するタスク。未指定の場合、モデルクラスからモデルタスクを推測するベストエフォートがなされるか、 type_hints.Task.UNKNOWN に設定されます。すべてのタスクオプションについて snowflake.ml.model.type_hints をチェックします。

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/';
Copy

出力は似ています。

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'
Copy

あるいはSnowpark Pythonと同等です。

session.file.get('snow://model/my_model/versions/V3/MANIFEST.yml', 'model_artifacts')
Copy

注釈

モデルのアーティファクトの名前と構成は、モデルのタイプによって異なり、変更されることがあります。上記のアーティファクトリストの例は、あくまで説明用であり、権威あるものではありません。

モデルの削除

レジストリの delete_model メソッドを使用して、モデルとそのすべてのバージョンを削除します。

reg.delete_model("mymodel")
Copy

Tip

DROP MODEL を使用して、SQL のモデルを削除することもできます。

レジストリからのモデルの取得

各モデルの情報を得るには、 show_models メソッドを使用します。

model_df = reg.show_models()
Copy

Tip

SQL で、 SHOW MODELS を使ってモデルのリストを取得します。

show_models の結果は、pandas DataFrame です。利用可能なカラムはこちらです。

説明

created_on

モデルが作成された日時。

name

モデルの名前。

database_name

モデルが格納されているデータベース。

schema_name

モデルが格納されているスキーマ。

owner

モデルを所有するロールの名前。

comment

モデルのコメント。

versions

モデルのバージョンをリストした JSON 配列。

default_version_name

バージョンを指定せずにモデルを参照する場合に使用されるモデルのバージョン。

代わりにレジストリにあるモデルのリストを、それぞれ Model インスタンスとして取得するには models メソッドを使用します。

model_list = reg.models()
Copy

レジストリから特定のモデルへの参照を名前で取得するには、レジストリの get_model メソッドを使用します。

m = reg.get_model("MyModel")
Copy

注釈

Model インスタンスは、ログされた元のPythonモデルオブジェクトのコピーではなく、レジストリ内の基になるモデルオブジェクトへの参照です。

models メソッドで返されたリストのモデル、または get_model を使用して取得したモデルへの参照があると、 そのメタデータそのバージョン を操作することができます。

モデルのメタデータの表示および更新

レジストリ内のモデルのメタデータ属性(名前、コメント、タグ、メトリックなど)を表示したり、更新したりすることができます。

コメントの取得および更新

モデルのコメントを取得したり、更新したりするには、モデルの comment 属性を使用します。

print(m.comment)
m.comment = "A better description than the one I provided originally"
Copy

注釈

description 属性は、 comment の同義語です。先のコードもこのように書くことができます。

print(m.description)
m.description = "A better description than the one I provided originally"
Copy

Tip

ALTER MODEL を使って、 SQL にモデルのコメントを設定することもできます。

タグの取得および更新

タグは、モデルの目的、アルゴリズム、トレーニングデータセット、ライフサイクルステージ、その他選択した情報を記録するために使用されるメタデータです。タグは、モデルの登録時または登録後いつでも設定することができます。また、既存のタグの値を更新したり、タグを完全に削除したりすることもできます。

注釈

まず、 CREATE TAG を使って、すべてのタグの名前(と、その可能性のある値)を定義する必要があります。 オブジェクトのタグ付け をご参照ください。

モデルのすべてのタグをPythonディクショナリとして取得するには、 show_tags を使用します。

print(m.show_tags())
Copy

新しいタグを追加したり、既存のタグの値を変更したりするには、 set_tag を使用します。

m.set_tag("live_version", "v1")
Copy

タグの値を取得するには、 get_tag を使用します。

m.get_tag("live_version")
Copy

タグを削除するには、 unset_tag を使用します。

m.unset_tag("live_version")
Copy

Tip

ALTER MODEL を使って、 SQL にモデルのコメントを設定することもできます。

モデル名の変更

モデルの名前を変更したり移動したりするには、 rename メソッドを使用します。モデルを別のデータベースまたはスキーマに移動するには、新しい名前として完全修飾名を指定します。

m.rename("MY_MODEL_TOO")
Copy

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

代わりに DataFrame として各モデルの情報を取得するには、モデルの show_versions メソッドを呼び出します。

version_df = m.show_versions()
Copy

できあがった DataFrame には以下の列が含まれます。

説明

created_on

モデルバージョンが作成された日時

name

バージョンの名前。

database_name

バージョンが格納されているデータベース。

schema_name

バージョンが格納されているスキーマ。

model_name

このバージョンが属するモデルの名前。

is_default_version

このバージョンがモデルのデフォルトバージョンであるかどうかを示すブール値。

functions

このバージョンで使用可能な関数名の JSON 配列。

metadata

JSON メタデータをキーと値のペアとして含むオブジェクト(メタデータが指定されていない場合は {})。

user_data

モデル定義マニフェストの user_data セクションからの JSON オブジェクト(ユーザーデータが指定されていない場合は {})。

モデルバージョンの削除

モデルの delete_version メソッドを使用してモデルのバージョンを削除できます。

m.delete_version("rc1")
Copy

Tip

ALTER MODEL ... DROP VERSION を使用して、 SQL のモデルバージョンを削除することもできます。

デフォルトバージョン

モデルのバージョンをデフォルトモデルとして指定することができます。モデルの default 属性を取得または設定して、現在のデフォルトバージョンを(ModelVersion オブジェクトとして)取得するか、変更(文字列を使用して)します。

default_version = m.default
m.default = "v2"
Copy

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
Copy

モデルの特定バージョン(この例の変数 mv など)への参照を取得すると、そのコメントやメトリクスを取得または更新し、以下のセクションで示すようにモデルのメソッド(または関数)を呼び出すことができます。

コメントの取得および更新

モデルと同様に、モデルのバージョンはコメントを持つことができ、モデルのバージョンの comment または description 属性を介してアクセスし、設定することができます。

print(mv.comment)
print(mv.description)

mv.comment = "A model version comment"
mv.description = "Same as setting the comment"
Copy

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

混同行列はsklearnを使用して同様に生成できます。

test_confusion_matrix = metrics.confusion_matrix(test_labels, prediction)
Copy

そして、これらの値をメトリクスとして設定することができます:

# 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)
Copy

モデルバージョンのメトリクスをPythonディクショナリとして取得するには、 show_metrics を使用します。

metrics = mv.show_metrics()
Copy

メトリクスを削除するには、 delete_metric を呼び出します。

mv.delete_metric("test_accuracy")
Copy

Tip

また、 ALTER MODEL ... MODIFY VERSION を使用して、 SQL でモデルバージョンのメトリクス(メタデータとして格納される)を変更することもできます。

モデル説明の取得

モデルレジストリは、 Shapley値 を計算することで、モデルの結果を説明し、どの入力機能が予測に最も寄与しているかを伝えることができます。このプレビュー機能は、Snowflake 8.31以降で作成されたすべてのモデルビューで、基本モデルの explain メソッドを通じてデフォルトで利用できます。Pythonの SQL 、またはモデルビューの run メソッドから explain を呼び出せます。

この機能の詳細については、 モデルの説明可能性 をご参照ください。

モデルバージョンのエクスポート

モデルのファイルをローカルディレクトリにエクスポートするには、 mv.export を使用します。ディレクトリが存在しない場合は作成されます。

mv.export("~/mymodel/")
Copy

デフォルトでは、エクスポートされるファイルには、コード、モデルをロードする環境、モデルの重みが含まれます。ウェアハウスでモデルを実行するために必要なファイルもエクスポートするには、 export_mode = ExportMode.FULL を指定します。

mv.export("~/mymodel/", export_mode=ExportMode.FULL)
Copy

モデルバージョンの読み込み

mv.load を使って、もともとレジストリに追加されていたオリジナルのPythonモデルオブジェクトを読み込みます。そうすれば、Pythonのコードで定義したのと同じように、推論にそのモデルを使うことができます。

clf = mv.load()
Copy

モデルの適切な関数を保証するために、ターゲットの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)
Copy

そして、このファイルから新しいconda環境を作成します。

conda env create --name newenv --file=~/conda.yml
conda activate newenv
Copy

オプションの options 引数は、モデルを読み込むためのオプションの辞書です。現在、この引数は use_gpu オプションのみをサポートしています。

オプション

説明

デフォルト

use_gpu

bool

GPU 固有のロードロジックを有効にします。

False

次の例は、 options 引数の使い方を示しています。

clf = mv.load(options={"use_gpu": True})
Copy

モデルメソッドの呼び出し

モデルのバージョンは、推論や他のモデル操作を実行するための付属関数である メソッド を持つことができます。モデルのバージョンは異なるメソッドを持つことができ、これらのメソッドの署名も異なる場合があります。

モデルバージョンのメソッドを呼び出すには、 mv.run を使用し、呼び出す関数名を指定し、推論データとその他の必要なパラメーターを含むSnowparkまたはpandas DataFrame を渡します。このメソッドは、Snowflakeウェアハウスで実行されます。

メソッドの戻り値は、渡されたDataFrameのタイプに応じて、Snowparkまたはpandas DataFrameです。Snowpark DataFrames は遅延評価されるため、DataFrame の collectshowto_pandas メソッドが呼び出されたときのみメソッドが実行されます。

注釈

メソッドを起動すると、レジストリへの接続に使用しているセッションで指定されたウェアハウスでメソッドが実行されます。 ウェアハウスサイズの指定 をご参照ください。

次の例は、モデルの predict メソッドの実行を示しています。このモデルの predict メソッドは、推論データ(ここでは test_features)以外にパラメーターを必要としません。必要な場合は、推論データの後に追加の引数として渡されることになります。

remote_prediction = mv.run(test_features, function_name="predict")
remote_prediction.show()   # assuming test_features is Snowpark DataFrame
Copy

指定されたモデルでどのメソッドが呼び出せるかを確認するには、 mv.show_functions を呼び出します。このメソッドの返り値は、 ModelFunctionInfo オブジェクトのリストです。これらの各オブジェクトには以下の属性が含まれます。

  • name: Pythonまたは SQL から呼び出せる関数名。

  • target_method:元のログモデルのPythonメソッド名。

Tip

SQLでモデルメソッドを呼び出すこともできます。 モデルメソッド をご参照ください。

モデルの共有

モデル・レジストリは2種類のモデルを保存できます。これらの区別は、 SHOW MODELS の出力にある MODEL_TYPE 列を使用して行うことができます。

  • CORTEX_FINETUNED: ユーザーコードを含まない Cortex Fine-tuning で生成されたモデル。この種のモデルを共有するには、 Data Sharing を使用します。

  • USER_MODEL: Snowpark ML モデリングクラス を使用して開発されたモデルなど、ユーザーコードを含むモデル。これらのモデルは現在、共有することはできません。ユーザーコードを含むモデルを共有する機能は、将来のリリースで利用可能になる予定です。

コストの考慮事項

Snowflake モデルレジストリを使用すると、標準的なSnowflake消費ベースのコストが発生します。これらには次が含まれます。

  • モデルのアーティファクト、メタデータ、および関数を格納するためのコスト。ストレージコストに関する一般情報については、 ストレージコストの調査 をご参照ください。

  • ステージ間のファイルをSnowflakeにコピーするコスト。 COPY FILES をご参照ください。

  • モデルやモデルのバージョンの表示、モデルのコメント、タグ、メトリクスの変更など、 Snowsight UI や SQL 、Pythonインターフェイスを介したサーバーレスモデルオブジェクト操作のコスト。

  • ウェアハウスコンピューティングコスト。コストは、モデルの型や学習予測に使用するデータ量によって異なります。Snowflakeのコンピューティングコストに関する一般的な情報については、 コンピューティングコストについて をご参照ください。ウェアハウスのコンピューティングコストは、次のような場合に発生します。

    • モデルおよびバージョンの作成操作。

    • モデルのメソッドの呼び出し

特定のモデル型に関する注意事項

このセクションでは、特定の型のモデルをSnowflakeモデルレジストリにログするための追加情報を提供します。

Snowpark ML

レジストリは、 Snowpark ML Modeling APIssnowpark.ml.modeling.framework.base.BaseEstimator から派生したモデル)を使用して作成されたモデルをサポートしています。以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

target_methods

モデルオブジェクトで利用可能なメソッドの名前のリスト。Snowpark ML モデルは、メソッドが存在すると仮定して、デフォルトで以下のターゲットメソッドを持ちます。 predicttransformpredict_probapredict_log_probadecision_function

Snowpark ML モデルをログする際に sample_input_datasignatures を指定する必要はありません。これらはフィッティングの際に自動的に推測されます。

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')
Copy

scikit-learn

レジストリは、scikit-learnを使用して作成されたモデル(sklearn.base.BaseEstimator または sklearn.pipeline.Pipeline から派生したモデル)をサポートしています。以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

target_methods

モデルオブジェクトで利用可能なメソッド名。メソッドが存在すると仮定して、scikit-learnモデルはデフォルトで以下のターゲットメソッドを持ちます。 predicttransformpredict_probapredict_log_probadecision_function

scikit-learnモデルをログする場合は、 sample_input_datasignatures のどちらかのパラメーターを指定する必要があります。

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"')
Copy

XGBoost

レジストリは、 XGBoost を使用して作成されたモデル(xgboost.XGBModel または xgboost.Booster から派生したモデル)をサポートしています。以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

target_methods

モデルオブジェクトで利用可能なメソッドの名前のリスト。 XGBModel から派生したモデルは、メソッドが存在すると仮定して、デフォルトで predictpredict_proba のターゲットメソッドを持ちます。(v1.4.0以前は apply も含まれていました。) Booster から派生したモデルはデフォルトで predict メソッドを持ちます。

cuda_version

GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で None に設定した場合、モデルは GPU を持つプラットフォームには展開できません。

レジストリがターゲットメソッドの署名を知ることができるように、 XGBoost モデルをログするときには sample_input_datasignatures のどちらかのパラメーターを指定する必要があります。

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:])
Copy

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

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]]])
Copy

そうすると、 tensors DataFrame は次のようになります。

        0       1
0  [1, 2]  [5, 6]
1  [3, 4]  [7, 8]
Copy

同様に、モデルが (torch.Tensor([[1,2],[3,4]]), torch.Tensor([[5,6], [7,8]])) のような2つのテンソルを返す場合、結果は前述のような DataFrame になります。

PyTorch モデルのサンプル入力データを提供する場合は、テンソルのリスト(pandasの DataFrame に変換される)または DataFrame を提供する必要があります。リストに単一のテンソルを含むことはできますが、テンソル自体は認められません。

モデルのログ

以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

target_methods

モデルオブジェクトで利用可能なメソッドの名前のリスト。PyTorch モデルのデフォルトは forward です。

cuda_version

GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で None に設定した場合、モデルは GPU を持つプラットフォームには展開できません。

PyTorch モデルをログする場合は、 sample_input_datasignatures のどちらかのパラメーターを指定する必要があります。

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])
Copy

TensorFlow

tensorflow.Module または tensorflow.keras.Model を拡張するモデルは、テンソルを受け取って返す場合、またコンパイル可能またはコンパイルされる場合にサポートされます。

  • tensorflow.Module__call__ メソッドまたは tensorflow.keras.Modelcall メソッドは、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
Copy

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]]])
Copy

そうすると、 tensors DataFrame は次のようになります。

        0       1
0  [1, 2]  [5, 6]
1  [3, 4]  [7, 8]
Copy

同様に、モデルが (tf.Tensor([[1,2],[3,4]]), tf.Tensor([[5,6], [7,8]])) のような2つのテンソルを返す場合、結果は前述のような DataFrame になります。

TensorFlow モデルのサンプル入力データを提供する場合は、テンソルのリスト(pandasの DataFrame に変換される)または DataFrame を提供する必要があります。リストに単一のテンソルを含むことはできますが、テンソル自体は認められません。

モデルのログ

以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

target_methods

モデルオブジェクトで利用可能なメソッドの名前のリスト。TensorFlow モデルのデフォルトは forward です。

cuda_version

GPU を持つプラットフォームへの展開時に使用する CUDA ランタイムのバージョン。デフォルトで11.7。手動で None に設定した場合、モデルは GPU を持つプラットフォームには展開できません。

TensorFlow モデルをログする場合は、 sample_input_datasignatures のどちらかのパラメーターを指定する必要があります。

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])
Copy

MLFlow

PyFunc フレーバーを提供する MLFlow モデルがサポートされています。MLFlow モデルに署名がある場合、 signature 引数はモデルから推測されます。署名がない場合は、 signaturesample_input_data のどちらかを提供する必要があります。

以下の追加オプションは、 options ディクショナリで log_model を呼び出すときに使用できます。

オプション

説明

model_uri

MLFlow モデルのアーティファクトの URI。モデルのメタデータで model.metadata.get_model_info().model_uri として提供されていない場合は、提供する必要があります。

ignore_mlflow_metadata

True の場合、モデルのメタデータはレジストリのモデルオブジェクトにインポートされません。デフォルト: False

ignore_mlflow_dependencies

True の場合、モデルのメタデータ内の依存関係は無視されます。これは、Snowflakeウェアハウスで利用可能なパッケージを制限するために便利です。デフォルト: False

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

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')
Copy

重要

huggingface_pipeline.HuggingFacePipelineModel に基づくモデルは構成データのみを含み、モデルの重みはモデルが使用されるたびにHugging Faceハブからダウンロードされます。

モデルレジストリは現在、ウェアハウスへのモデル展開のみをサポートしています。ウェアハウスは、 特別な構成 がない場合は外部ネットワークアクセスをサポートしません。必要な外部アクセス統合が作成されていたとしても、特定のモデルに必要な統合を指定する方法は今のところありません。

現在のベストプラクティスは、上記の例のように transformers.Pipeline を使用することです。これにより、モデルの重みがローカルシステムにダウンロードされ、モデル全体がウェアハウスにアップロードされます。その結果、インターネット接続を必要としない自己完結型モデルができます。

レジストリは、パイプラインが以下のリストから1つのタスクを含む場合にのみ、 signatures 引数を推測します。

  • conversational

  • fill-mask

  • question-answering

  • summarization

  • table-question-answering

  • text2text-generation

  • text-classificationsentiment-analysis とも呼ばれます)

  • text-generation

  • token-classificationner とも呼ばれます)

  • 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')
                      ]
                  )}]
Copy

この情報があると、次のようにモデルを呼び出すことができます。

import pandas as pd
remote_prediction = lmv.run(pd.DataFrame(["Hello, how are you?"], columns=["inputs"]))
Copy

使用上の注意

  • 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.\""}]
    
    Copy

レジストリがターゲットメソッドの署名を知ることができるように、Hugging Faceモデルをログする場合は、 sample_input_datasignatures のどちらかのパラメーターを指定する必要があります。

# 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.", ""],
        ]
    )
)
Copy

結果:

0  [{"label": "negative", "score": 0.8106237053871155}, {"label": "neutral", "score": 0.16587384045124054}]
1  [{"label": "neutral", "score": 0.9263970851898193}, {"label": "positive", "score": 0.05286872014403343}]
Copy