Snowpark ML Ops: Model Registry

Nota

A API do registro de modelo descrito neste tópico está disponível no pacote Snowpark ML versão 1.2.0 e posterior.

Como parte do Snowpark ML Operations (MLOps), o registro de modelo do Snowpark permite que os clientes gerenciem com segurança modelos e seus metadados no Snowflake, independentemente da origem. O registro de modelo do Snowpark armazena modelos de machine learning como objetos de nível de esquema de primeira classe no Snowflake para que possam ser facilmente encontrados e usados por outras pessoas em sua organização. Você pode criar registros e armazenar modelos neles usando Snowpark ML. Os modelos podem ter diversas versões e você pode designar uma versão como padrão.

Depois de armazenar um modelo, você pode invocar seus métodos (equivalentes a funções ou procedimentos armazenados) para executar operações de modelo, como inferência, em um warehouse virtual do Snowflake.

Dica

Consulte Introdução ao aprendizado de máquina com Snowpark ML para ver um exemplo de fluxo de trabalho completo no Snowpark ML, incluindo o registro do modelo.

Os três objetos principais na API do registro de modelo do Snowpark são:

  • snowflake.ml.registry.Registry: gerencia modelos dentro de um esquema.

  • snowflake.ml.model.Model: representa um modelo.

  • snowflake.ml.model.ModelVersion: representa uma versão de um modelo.

Para obter informações detalhadas sobre essas classes, consulte a Referência da API do Snowpark ML.

O registro de modelo do Snowpark oferece suporte aos seguintes tipos de modelos.

  • Snowpark ML Modeling

  • scikit-learn

  • XGBoost

  • PyTorch

  • TensorFlow

  • MLFlow PyFunc

  • Pipeline do HuggingFace

Este tópico descreve como executar operações de registro em Python usando Snowpark ML. Você também pode realizar diversas operações de registro em SQL. Para obter mais informações, consulte Comandos de modelo.

Diferenças da versão preliminar privada

Anteriormente, a Snowflake disponibilizou um registro de modelo de forma privada para clientes selecionados. O recurso de registro descrito neste tópico apresenta alterações significativas na funcionalidade e APIs em comparação com a versão preliminar privada. Mais notavelmente, a funcionalidade de registro do modelo agora está hospedada nativamente no Snowflake usando um novo objeto em nível de esquema.

Nota

Esta versão de versão preliminar pública ainda não oferece suporte à implantação de modelos no Snowpark Container Services (SPCS). Se você depende dessa funcionalidade, continue usando o registro de versão preliminar privada por enquanto.

Para obter detalhes sobre as diferenças entre essas duas APIs, consulte Snowpark ML Ops: migração da API da versão preliminar do registro de modelo.

Privilégios obrigatórios

Para criar um modelo, você deve possuir o esquema onde o modelo foi criado ou ter o privilégio CREATE MODEL nele. Para usar um modelo, você deve possuir o modelo ou ter o privilégio USAGE nele.

Abertura do registro de modelo do Snowpark

Os modelos são objetos Snowflake de primeira classe e podem ser organizados em um banco de dados e esquema junto com outros objetos Snowflake. O registro de modelo do Snowpark é uma classe Python para gerenciar modelos dentro de um esquema. Assim, qualquer esquema Snowflake pode ser usado como registro. Não é necessário inicializar ou preparar um esquema para essa finalidade. Snowflake recomenda a criação de um ou mais esquemas dedicados para essa finalidade, como ML.REGISTRY. Você pode criar o esquema usando CREATE SCHEMA.

Antes de poder criar ou modificar modelos no registro, você deve abrir o registro. A abertura do registro retorna uma referência a ele, que você pode usar para adicionar novos modelos e obter referências a modelos existentes.

from snowflake.ml.registry import Registry

reg = Registry(session=sp_session, database_name="ML", schema_name="REGISTRY")
Copy

Nota

Durante esta versão preliminar pública, os objetos Model não oferecem suporte à replicação ou clonagem.

Registro de modelos e versões

Adicionar um modelo ao registro é chamado de registro em log do modelo. Registre em log um modelo chamando o método log_model do registro. Esse método:

  • Serializa o modelo, um objeto Python, e cria um objeto de modelo Snowflake a partir dele.

  • Adiciona metadados, como uma descrição, ao modelo conforme especificado na chamada log_model.

Nota

Você não pode adicionar tags a um modelo quando ele é adicionado ao registro, porque tags são atributos do modelo e log_model adiciona uma versão específica do modelo. Você pode atualizar as tags do modelo depois de registrar a primeira versão do modelo em log.

Cada modelo pode ter qualquer número de versões. Para registrar versões adicionais do modelo em log, chame log_model novamente com o mesmo model_name, mas com um version_name diferente.

No exemplo abaixo, clf, abreviação de “classificador”, é o objeto do modelo Python, que já foi criado em outro lugar no seu código. Você pode adicionar um comentário e tags no momento do registro, conforme mostrado aqui. A combinação de nome e versão deve ser exclusiva no esquema. Você pode especificar listas de conda_dependencies; os pacotes especificados serão implantados com o modelo.

mv = reg.log_model(clf,
                   model_name="my_model",
                   version_name="1",
                   conda_dependencies=["scikit-learn"],
                   comment="My awesome ML model",
                   metrics={"score": 96},
                   sample_input_data=train_features)
Copy

Os argumentos de log_model são descritos aqui.

Argumentos exigidos

Argumento

Descrição

model

O objeto de modelo Python de um tipo de modelo compatível. Deve ser serializável (“selecionável”).

model_name

O nome do modelo, usado com version_name para identificar o modelo no registro. O nome não pode ser alterado após o modelo ter sido registrado em log.

version_name

Cadeia de caracteres especificando a versão do modelo, usada com model_name para identificar o modelo no registro.

Nota

A combinação do nome do modelo e da versão deve ser exclusiva no esquema.

Argumentos opcionais

Argumento

Descrição

code_paths

Lista de caminhos para diretórios de código a serem importados ao carregar ou implantar o modelo.

comment

Comentário, por exemplo, uma descrição do modelo.

conda_dependencies

Lista de pacotes Conda exigidos pelo seu modelo. Este argumento especifica nomes de pacotes e versões opcionais em formato Conda, ou seja, "[channel::]package [operator version]". Se você não especificar um canal, o canal Snowflake será assumido.

ext_modules

Lista de módulos externos para combinar com o modelo. Compatível com scikit-learn, Snowpark ML, PyTorch, TorchScript e modelos personalizados.

metrics

Dicionário contendo métricas vinculadas à versão do modelo.

options

Dicionário contendo opções para criação de modelos. As seguintes opções estão disponíveis para todos os tipos de modelo:

  • embed_local_ml_library: se uma cópia da biblioteca local do Snowpark ML deve ser incorporada ao modelo. Padrão: False.

  • relax_version: se deve relaxar as restrições de versão das dependências. Isso substitui os especificadores de versão como ==x.y.z por especificadores como <=x.y, <(x+1). Padrão: False. Disponível desde a versão 1.2.1 do pacote Snowpark ML.

  • method_options: um dicionário de opções por método, onde a chave é o nome de um método e o valor é um dicionário contendo uma ou mais das opções descritas aqui. As opções disponíveis são:

    • case_sensitive: indica se o método e sua assinatura diferenciam maiúsculas de minúsculas. Os métodos que diferenciam maiúsculas de minúsculas devem ser colocados entre aspas duplas quando usados em SQL. Esta opção também permite caracteres não alfabéticos em nomes de métodos. Padrão: False.

    • max_batch_size: tamanho máximo do lote que o método aceitará quando chamado no warehouse. Padrão: None (o tamanho do lote é determinado automaticamente)

Tipos de modelos individuais podem oferecer suporte a opções adicionais. Consulte Notas sobre tipos de modelos específicos.

pip_requirements

Lista de especificações de pacote para os pacotes PyPI exigidos pelo seu modelo.

python_version

A versão do Python na qual o modelo será executado. O padrão é None, que designa a versão mais recente disponível no warehouse.

sample_input_data

Um DataFrame contendo dados de entrada de amostra. Os nomes dos recursos exigidos pelo modelo e seus tipos são extraídos deste DataFrame. Este argumento ou signatures devem ser fornecidos para todos os modelos, exceto os modelos Snowpark ML e MLFlow.

signatures

Modele assinaturas de métodos como um mapeamento do nome do método de destino para assinaturas de entrada e saída. Este argumento ou sample_input_data devem ser fornecidos para todos os modelos, exceto os modelos Snowpark ML e MLFlow.

log_model retorna um objeto snowflake.ml.model.ModelVersion, que representa a versão do modelo que foi adicionado ao registro.

Uma vez registrado, o modelo em si não pode ser modificado (embora você possa alterar seus metadados). Para excluir um modelo e todas as suas versões, use o método excluir_modelo do registro.

Exclusão de modelos

Use o método delete_model do registro para excluir um modelo e todas as suas versões.

reg.delete_model("mymodel")
Copy

Como obter modelos do registro

Para obter informações sobre cada modelo, use o método show_models.

model_df = reg.show_models()
Copy

O resultado de show_models é um pandas DataFrame. As colunas disponíveis são mostradas abaixo.

Coluna

Descrição

created_on

Data e hora em que o modelo foi criado.

nome

Nome do modelo.

database_name

Banco de dados no qual o modelo é armazenado.

schema_name

Esquema no qual o modelo é armazenado.

proprietário

Função proprietária do modelo.

comentário

Comentário para o modelo.

versões

Matriz JSON listando versões do modelo.

nome_da_versão_padrão

Versão do modelo utilizado quando se refere ao modelo sem versão.

Para obter uma lista dos modelos no registro, cada um como uma instância Model, use o método models.

model_list = reg.models()
Copy

Para obter uma referência a um modelo específico do registro por nome, use o método get_model do registro. Este método retorna uma instância Model.

m = reg.get_model("MyModel")
Copy

Nota

As instâncias Model não são cópias do objeto de modelo Python original registrado, mas referências ao objeto de modelo subjacente no registro.

Depois de ter uma referência a um modelo, seja um da lista retornada pelo método models ou um recuperado usando get_model, você poderá trabalhar com seus metadados e suas versões.

Visualização e atualização dos metadados de um modelo

Você pode visualizar e atualizar os atributos de metadados de um modelo no registro, incluindo comentários, tags e métricas.

Recuperação e atualização de comentários

Use o atributo comment do modelo para recuperar e atualizar o comentário do modelo.

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

Nota

O atributo description é um alias para comment. O código acima também pode ser escrito:

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

Recuperação e atualização de tags

Tags são metadados usados para registrar a finalidade de um modelo, algoritmo, conjunto de dados de treinamento, estágio do ciclo de vida ou outras informações que você escolher. Você pode definir tags quando o modelo for registrado ou a qualquer momento posteriormente. Você também pode atualizar os valores das tags existentes ou remover totalmente as tags.

Nota

Os nomes de todas as tags (e potencialmente seus possíveis valores) devem ser definidos antecipadamente usando CREATE TAG. Consulte Marcação de objetos.

Para obter todas as tags de um modelo como um dicionário Python, use show_tags.

print(m.show_tags())
Copy

Para adicionar uma nova tag ou alterar o valor de uma tag existente, use set_tag.

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

Para recuperar o valor de uma tag, use get_tag:

m.get_tag("live_version")
Copy

Para remover uma tag, use unset_tag.

model.unset_tag("live_version")
Copy

Como trabalhar com versões de modelo

Um modelo pode ter qualquer número de versões, cada uma identificada por uma cadeia de caracteres. Você pode usar qualquer convenção de nomenclatura de versão que desejar. Registrar um modelo na verdade registra uma versão específica do modelo. Para registrar versões adicionais de um modelo, chame log_model novamente com o mesmo model_name, mas com um version_name diferente.

Uma versão de um modelo é representada por uma instância da classe snowflake.ml.model.ModelVersion.

Para obter uma lista de todas as versões de um modelo, chame o método versions do objeto modelo. O resultado é uma lista de instâncias ModelVersion.

version_list = m.versions()
Copy

Para obter informações sobre cada modelo como DataFrame, chame o método show_versions do modelo.

version_df = m.show_versions()
Copy

O DataFrame resultante contém as colunas a seguir.

Coluna

Descrição

created_on

Data e hora em que a versão do modelo foi criada.

nome

Nome da versão.

database_name

Banco de dados no qual a versão está armazenada.

schema_name

Esquema no qual a versão está armazenada.

model_name

Nome do modelo ao qual esta versão pertence.

is_default_version

Valor booleano que indica se esta versão é a versão padrão do modelo.

functions

Matriz JSON dos nomes das funções disponíveis nesta versão.

metadata

Objeto JSON contendo metadados como pares chave-valor ({} se nenhum metadado for especificado).

user_data

Objeto JSON da seção user_data do manifesto de definição do modelo ({} se nenhum dado do usuário for especificado).

Exclusão das versões do modelo

Você pode excluir uma versão do modelo usando o método delete_version do modelo.

m.delete_version("rc1")
Copy

Versão padrão

Uma versão de um modelo pode ser designada como modelo padrão. Recupere ou defina o atributo default do modelo para obter a versão padrão atual (como um objeto ModelVersion) ou para alterá-la (usando uma cadeia de caracteres).

default_version = m.default
m.default = "2"
Copy

Como obter uma referência para uma versão do modelo

Para obter uma referência a uma versão específica de um modelo como uma instância ModelVersion, use o método version do modelo. Use o atributo default do modelo para obter a versão padrão do modelo.

mv = m.version("1")
mv = m.default
Copy

Depois de ter uma referência a uma versão específica de um modelo (como a variável mv em nosso exemplo acima), você pode recuperar ou atualizar seus comentários ou métricas e chamar os métodos (funções) do modelo, conforme mostrado nas seções a seguir.

Recuperação e atualização de comentários

Assim como acontece com os modelos, as versões do modelo podem ter comentários, que podem ser acessados e definidos por meio do atributo comment ou description da versão do modelo.

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

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

Recuperação e atualização de métricas

Métricas são pares chave-valor usados para rastrear a precisão da previsão e outras características da versão do modelo. Você pode definir métricas ao criar uma versão do modelo ou defini-las usando o método set_metric. Um valor de métrica pode ser qualquer objeto Python que possa ser serializado para JSON, incluindo números, cadeias de caracteres, listas e dicionários. Ao contrário das tags, os nomes das métricas e os valores possíveis não precisam ser definidos antecipadamente.

Uma métrica de precisão de teste pode ser gerada usando accuracy_score do sklearn:

from sklearn import metrics

test_accuracy = metrics.accuracy_score(test_labels, prediction)
Copy

A matriz de confusão pode ser gerada de forma semelhante usando o sklearn:

test_confusion_matrix = metrics.confusion_matrix(test_labels, prediction)
Copy

Então podemos definir esses valores como métricas da seguinte maneira.

# 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

Para recuperar as métricas de uma versão do modelo como um dicionário Python, use show_metrics.

metrics = mv.show_metrics()
Copy

Para excluir uma métrica, chame delete_metric.

mv.delete_metric("test_accuracy")
Copy

Como chamar métodos de modelo

As versões do modelo podem ter métodos, que são funções anexadas que podem ser executadas para realizar inferência ou outras operações do modelo. As versões de um modelo podem ter métodos diferentes e as assinaturas desses métodos também podem ser diferentes.

Para chamar um método de uma versão do modelo, use mv.run, especificando o nome da função a ser chamada e passando um DataFrame contendo os dados de inferência e quaisquer outros parâmetros necessários. O método é executado em um warehouse Snowflake.

Nota

Invocar um método executa-o no warehouse especificado na sessão que você está usando para se conectar ao registro. Consulte Especificação de um warehouse.

O exemplo a seguir ilustra a execução do método predict de um modelo. O método predict deste modelo não requer nenhum parâmetro além dos dados de inferência (test_features aqui). Se assim fosse, eles seriam passados como argumentos adicionais após os dados de inferência.

remote_prediction = mv.run(test_features, function_name="predict")
Copy

Para ver quais métodos podem ser chamados em um determinado modelo, chame mv.show_functions. O valor de retorno deste método é uma lista de objetos ModelFunctionInfo. Cada um desses objetos inclui os seguintes atributos:

  • name: o nome da função que pode ser chamada em Python ou SQL.

  • target_method: o nome do método original no modelo Python registrado original.

Como trabalhar com o Model Registry em SQL

Como os modelos são objetos de primeira classe no nível do esquema, o Snowflake SQL oferece comandos para trabalhar com eles. Eles são:

Nota

Embora o Snowflake SQL inclua comandos para criar modelos e versões, eles devem ser usados pela API Python do registro de modelo do Snowpark. Registre os modelos em Python conforme mostrado em Registro de modelos e versões.

Como chamar métodos de modelo em SQL

Você pode chamar ou invocar métodos de um modelo em SQL usando a sintaxe model_name!method_name(...). Os métodos disponíveis em um modelo são determinados pela classe de modelo Python subjacente. Por exemplo, muitos tipos de modelos usam um método denominado predict para inferência.

Para invocar um método da versão mais recente de um modelo, use a sintaxe mostrada aqui, passando argumentos para o método, se houver, entre parênteses, e passando o nome da tabela que contém os dados de inferência na cláusula FROM.

SELECT <model_name>!<method_name>(...) FROM <table_name>;
Copy

Para invocar um método de uma versão específica de um modelo, primeiro crie um alias para a versão específica do modelo e, em seguida, invoque o método desejado por meio do alias.

WITH <model_version_alias> AS MODEL <model_name> VERSION <version>
    SELECT <model_version_alias>!<method_name>(...) FROM <table_name>;
Copy

Considerações sobre custo

O uso do registro de modelo do Snowpark ML incorre em custos padrão baseados no consumo do Snowflake. Isso inclui:

  • Custo de armazenamento de artefatos, metadados e funções do modelo. Consulte Exploração do custo de armazenamento para obter informações gerais sobre custos de armazenamento.

  • Custo de cópia de arquivos entre estágios para o Snowflake. Consulte COPY FILES.

  • Custo de operações de objetos de modelo sem servidor por meio da interface Snowsight UI ou SQL ou Python, como mostrar modelos e versões de modelos e alterar comentários, tags e métricas do modelo.

  • Custos de computação do warehouse, que variam de acordo com o tipo de modelo e a quantidade de dados usados na inferência. Consulte Explicação dos custos de computação para obter informações gerais sobre os custos de computação do Snowflake. Os custos de computação do warehouse são incorridos para:

    • Operações de criação de modelo e versão.

    • Invocar os métodos de um modelo.

Notas sobre tipos de modelos específicos

Esta seção fornece informações adicionais sobre como registrar tipos específicos de modelos no registro de modelo do Snowpark.

ML Snowpark

O registro oferece suporte a modelos criados usando as APIs de modelagem do Snowpark ML (modelos derivados de snowpark.ml.modeling.framework.base.BaseEstimator). As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

target_methods

Uma lista dos nomes dos métodos disponíveis no objeto modelo. Os modelos Snowpark ML têm os seguintes métodos de destino por padrão, assumindo que o método existe: predict, transform, predict_proba, predict_log_proba, decision_function

Você não precisa especificar sample_input_data ou signatures ao registrar um modelo Snowpark ML; estes são inferidos automaticamente durante o ajuste.

Exemplo

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

O registro oferece suporte a modelos criados usando scikit-learn (modelos derivados de sklearn.base.BaseEstimator ou sklearn.pipeline.Pipeline). As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

target_methods

Uma lista dos nomes dos métodos disponíveis no objeto modelo. Os modelos scikit-learn têm os seguintes métodos de destino por padrão, assumindo que o método existe: predict, transform, predict_proba, predict_log_proba, decision_function

Você deve especificar o parâmetro sample_input_data ou signatures ao registrar um modelo scikit-learn para que o registro conheça as assinaturas dos métodos de destino.

Exemplo

from sklearn import datasets, ensemble

iris_X, iris_y = datasets.load_iris(return_X_y=True, as_frame=True)
model = ensemble.RandomForestClassifier(random_state=42)
model.fit(iris_X, iris_y)
model_ref = registry.log_model(
    model,
    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

O registro oferece suporte a modelos criados usando XGBoost (modelos derivados de xgboost.XGBModel ou xgboost.Booster). As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

target_methods

Uma lista dos nomes dos métodos disponíveis no objeto modelo. Os modelos derivados de XGBModel têm os seguintes métodos de destino por padrão, assumindo que o método existe: predict, predict_proba, apply. Os modelos derivados de Booster possuem o método predict por padrão.

cuda_version

A versão do tempo de execução CUDA a ser usada ao implantar em uma plataforma com GPU; o padrão é 11.7. Se definido manualmente como None, o modelo não poderá ser implementado em uma plataforma com GPU.

Você deve especificar o parâmetro sample_input_data ou signatures ao registrar um modelo XGBoost para que o registro conheça as assinaturas dos métodos de destino.

Exemplo

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

O registro oferece suporte aos modelos PyTorch (classes derivadas de torch.nn.Module ou torch.jit.ModuleScript) se o método forward do modelo aceitar uma ou mais instâncias torch.Tensor como entrada e retornar um torch.Tensor ou uma tupla delas. O registro converte entre pandas DataFrames e tensores ao chamar o modelo e retornar os resultados. Os tensores correspondem às colunas no dataframe.

Por exemplo, suponha que seu modelo aceite dois tensores como este:

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

Se você quiser passar torch.Tensor([[1,2],[3,4]]) como tensor_1 e torch.Tensor([[5,6], [7,8]]) como tensor_2, crie um DataFrame como segue para passar para o modelo.

import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
Copy

Então o tensors DataFrame fica assim.

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

Da mesma forma, se seu modelo retornar dois tensores, como (torch.Tensor([[1,2],[3,4]]), torch.Tensor([[5,6], [7,8]])), o resultado será um DataFrame como o acima.

Ao fornecer dados de entrada de amostra para um modelo PyTorch, você deve fornecer uma lista de tensores (que serão convertidos em pandas DataFrame) ou em DataFrame. Uma lista pode conter um único tensor, mas um tensor por si só não é aceito.

Registro do modelo

As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

target_methods

Uma lista dos nomes dos métodos disponíveis no objeto modelo. O padrão dos modelos PyTorch é forward.

cuda_version

A versão do tempo de execução CUDA a ser usada ao implantar em uma plataforma com GPU; o padrão é 11.7. Se definido manualmente como None, o modelo não poderá ser implementado em uma plataforma com GPU.

Você deve especificar o parâmetro sample_input_data ou signatures ao registrar um modelo PyTorch para que o registro conheça as assinaturas dos métodos de destino.

Exemplo

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

Modelos que estendem tensorflow.Module ou tensorflow.keras.Model são suportados quando aceitam e retornam tensores e são compiláveis ou compilados.

  • O método __call__ para um tensorflow.Module ou o método call para um tensorflow.keras.Model aceita um ou mais tensorflow.Tensor ou tensorflow.Variable como entrada e retorna um tensorflow.Tensor ou tensorflow.Variable ou uma tupla de um dos esses tipos.

  • Se seu modelo estender Module, ele deverá ser compilável, o que significa que o método __call__ é decorado com @tensorflow.function; consulte a documentação do tf.function. Se estender Model, deverá ser compilado; consulte a documentação de compilação.

O registro converte entre pandas DataFrames e tensores ao chamar o modelo e retornar os resultados. Os tensores correspondem às colunas no dataframe.

Por exemplo, suponha que seu modelo aceite dois tensores como este:

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

Se você quiser passar tf.Tensor([[1,2],[3,4]]) como tensor_1 e tf.Tensor([[5,6], [7,8]]) como tensor_2, crie um DataFrame como segue para passar para o modelo.

import pandas as pd
tensors = pd.DataFrame([[[1,2],[5,6]],[[3,4],[7,8]]])
Copy

Então o tensors DataFrame fica assim.

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

Da mesma forma, se seu modelo retornar dois tensores, como (tf.Tensor([[1,2],[3,4]]), tf.Tensor([[5,6], [7,8]])), o resultado será um DataFrame como o acima.

Ao fornecer dados de entrada de amostra para um modelo TensorFlow, você deve fornecer uma lista de tensores (que serão convertidos em pandas DataFrame) ou em DataFrame. Uma lista pode conter um único tensor, mas um tensor por si só não é aceito.

Registro do modelo

As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

target_methods

Uma lista dos nomes dos métodos disponíveis no objeto modelo. O padrão dos modelos TensorFlow é forward.

cuda_version

A versão do tempo de execução CUDA a ser usada ao implantar em uma plataforma com GPU; o padrão é 11.7. Se definido manualmente como None, o modelo não poderá ser implementado em uma plataforma com GPU.

Você deve especificar o parâmetro sample_input_data ou signatures ao registrar um modelo TensorFlow para que o registro conheça as assinaturas dos métodos de destino.

Exemplo

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

Modelos MLFlow que fornecem um tipo PyFunc são suportados. Se o seu modelo MLFlow tiver uma assinatura, o argumento signature será inferido do modelo. Caso contrário, você deverá fornecer signature ou sample_input_data.

As seguintes opções adicionais podem ser usadas no dicionário options ao chamar log_model.

Opção

Descrição

model_uri

O URI dos artefatos do modelo MLFlow. Deve ser fornecido se não estiver disponível nos metadados do modelo como model.metadata.get_model_info().model_uri.

ignore_mlflow_metadata

Se True, os metadados do modelo não serão importados para o objeto de modelo no registro. Padrão: False

ignore_mlflow_dependencies

Se True, as dependências nos metadados do modelo serão ignoradas, o que é útil devido às limitações disponíveis do pacote nos warehouses do Snowflake. Padrão: False

Exemplo

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

Pipeline do Hugging Face

O registro oferece suporte a classes de modelo Hugging Face definidas como transformadores que derivam de transformers.Pipeline. O código a seguir é um exemplo de registro de um modelo compatível.

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

Importante

Um modelo baseado em huggingface_pipeline.HuggingFacePipelineModel contém apenas dados de configuração; os pesos do modelo são baixados do Hugging Face Hub sempre que o modelo é usado.

O registro de modelo atualmente oferece suporte à implementação de modelos apenas em warehouses. Os warehouses não oferecem suporte ao acesso à rede externa sem configuração especial. Mesmo que as integrações de acesso externo necessárias tenham sido criadas, neste momento não há como especificar quais integrações um modelo específico precisa.

A prática recomendada atual é usar transformers.Pipeline conforme mostrado no exemplo acima. Isso baixa os pesos do modelo para o seu sistema local e carrega o modelo inteiro para o warehouse. Isso resulta em um modelo independente que não precisa de acesso à internet.

O registro infere o argumento signatures desde que o pipeline contenha apenas tarefas da lista a seguir.

  • conversational

  • fill-mask

  • question-answering

  • summarization

  • table-question-answering

  • text2text-generation

  • text-classification (alias sentiment-analysis)

  • text-generation

  • token-classification (alias ner)

  • translation

  • translation_xx_to_yy

  • zero-shot-classification

Para ver a assinatura inferida, use o método show_functions. O seguinte, por exemplo, é o resultado de lmv.show_functions() onde lmv é o modelo registrado acima.

{'name': '__CALL__',
  'target_method': '__call__',
  'signature': ModelSignature(
                      inputs=[
                          FeatureSpec(dtype=DataType.STRING, name='inputs')
                      ],
                      outputs=[
                          FeatureSpec(dtype=DataType.STRING, name='outputs')
                      ]
                  )}]
Copy

Com essas informações, você pode chamar o modelo da seguinte forma.

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

Notas de uso

  • Muitos modelos Hugging Face são grandes e não cabem em um warehouse padrão. Use um warehouse otimizado para Snowpark ou escolha uma versão menor do modelo. Por exemplo, em vez de usar o modelo Llama-2-70b-chat-hf, tente Llama-2-7b-chat-hf.

  • Os warehouses Snowflake não têm GPUs. Use apenas modelos Hugging Face otimizados para CPU.

  • Alguns transformadores Hugging Face retornam uma matriz de dicionários por linha de entrada. O registro converte essa saída em uma cadeia de caracteres contendo uma representação JSON da matriz. Por exemplo, a saída de resposta a perguntas com múltiplas saídas é semelhante a esta:

    [{"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

Você deve especificar o parâmetro sample_input_data ou signatures ao registrar um modelo Hugging Face para que o registro conheça as assinaturas dos métodos de destino.

Exemplo

# 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

Resultado:

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