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.
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")
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)
Os argumentos de log_model
são descritos aqui.
Argumentos exigidos
Argumento |
Descrição |
---|---|
|
O objeto de modelo Python de um tipo de modelo compatível. Deve ser serializável (“selecionável”). |
|
O nome do modelo, usado com |
|
Cadeia de caracteres especificando a versão do modelo, usada com |
Nota
A combinação do nome do modelo e da versão deve ser exclusiva no esquema.
Argumentos opcionais
Argumento |
Descrição |
---|---|
|
Lista de caminhos para diretórios de código a serem importados ao carregar ou implantar o modelo. |
|
Comentário, por exemplo, uma descrição do modelo. |
|
Lista de pacotes Conda exigidos pelo seu modelo. Este argumento especifica nomes de pacotes e versões opcionais em formato Conda, ou seja, |
|
Lista de módulos externos para combinar com o modelo. Compatível com scikit-learn, Snowpark ML, PyTorch, TorchScript e modelos personalizados. |
|
Dicionário contendo métricas vinculadas à versão do modelo. |
|
Dicionário contendo opções para criação de modelos. As seguintes opções estão disponíveis para todos os tipos de modelo:
Tipos de modelos individuais podem oferecer suporte a opções adicionais. Consulte Notas sobre tipos de modelos específicos. |
|
Lista de especificações de pacote para os pacotes PyPI exigidos pelo seu modelo. |
|
A versão do Python na qual o modelo será executado. O padrão é |
|
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 |
|
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 |
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")
Como obter modelos do registro¶
Para obter informações sobre cada modelo, use o método show_models
.
model_df = reg.show_models()
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()
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")
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"
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"
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()
Para obter informações sobre cada modelo como DataFrame, chame o método show_versions
do modelo.
version_df = m.show_versions()
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 ( |
user_data |
Objeto JSON da seção |
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")
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"
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
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"
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)
A matriz de confusão pode ser gerada de forma semelhante usando o sklearn:
test_confusion_matrix = metrics.confusion_matrix(test_labels, prediction)
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)
Para recuperar as métricas de uma versão do modelo como um dicionário Python, use show_metrics
.
metrics = mv.show_metrics()
Para excluir uma métrica, chame delete_metric
.
mv.delete_metric("test_accuracy")
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")
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>;
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>;
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 |
---|---|
|
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: |
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')
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 |
---|---|
|
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: |
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"')
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 |
---|---|
|
Uma lista dos nomes dos métodos disponíveis no objeto modelo. Os modelos derivados de |
|
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 |
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:])
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)
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]]])
Então o tensors
DataFrame fica assim.
0 1
0 [1, 2] [5, 6]
1 [3, 4] [7, 8]
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 |
---|---|
|
Uma lista dos nomes dos métodos disponíveis no objeto modelo. O padrão dos modelos PyTorch é |
|
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 |
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])
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 umtensorflow.Module
ou o métodocall
para umtensorflow.keras.Model
aceita um ou maistensorflow.Tensor
outensorflow.Variable
como entrada e retorna umtensorflow.Tensor
outensorflow.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 estenderModel
, 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
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]]])
Então o tensors
DataFrame fica assim.
0 1
0 [1, 2] [5, 6]
1 [3, 4] [7, 8]
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 |
---|---|
|
Uma lista dos nomes dos métodos disponíveis no objeto modelo. O padrão dos modelos TensorFlow é |
|
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 |
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])
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 |
---|---|
|
O URI dos artefatos do modelo MLFlow. Deve ser fornecido se não estiver disponível nos metadados do modelo como |
|
Se |
|
Se |
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)
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')
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
(aliassentiment-analysis
)text-generation
token-classification
(aliasner
)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')
]
)}]
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"]))
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
, tenteLlama-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.\""}]
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.", ""],
]
)
)
Resultado:
0 [{"label": "negative", "score": 0.8106237053871155}, {"label": "neutral", "score": 0.16587384045124054}]
1 [{"label": "neutral", "score": 0.9263970851898193}, {"label": "positive", "score": 0.05286872014403343}]