Registro de modelo Snowflake¶
Nota
A API do registro de modelos descrita neste tópico está geralmente disponível a partir da versão 1.5.0 do pacote.
O Registro de modelo Snowflake permite que você gerencie com segurança modelos e seus metadados no Snowflake, independentemente da origem. O registro de modelo armazena modelos de aprendizado de máquina como objetos ao nível de esquema de primeira classe no Snowflake para que eles possam ser facilmente encontrados e usados por outras pessoas em sua organização. É possível criar registros e armazenar modelos neles usando classes Python na biblioteca de ML Snowpark. Os modelos podem ter diversas versões e você pode designar uma versão como padrão.
Após 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 Snowflake.
Dica
Para ver um exemplo de um fluxo de trabalho de ponta a ponta Snowpark ML, incluindo o Snowflake Model Registry, consulte Introdução ao aprendizado de máquina com o Snowpark ML.
Se você tiver modelos no Microsoft Azure Machine Learning ou no Amazon SageMaker, consulte Implantação dos modelos do Azure ML e SageMaker para Snowpark ML.
As classes mais importantes na API Python Snowflake Model Registry 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.
O Snowflake Model Registry oferece suporte aos seguintes tipos de modelos.
scikit-learn
XGBoost
LightGBM
CatBoost
PyTorch
TensorFlow
MLFlow PyFunc
Transformador de sentença
Pipeline do Hugging Face
Outros tipos de modelo via a classe
snowflake.ml.model.CustomModel
(consulte Armazenamento de modelos personalizados no registro do modelo Snowflake)
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; consulte Comandos 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. O privilégio USAGE permite que os beneficiários usem o modelo para inferência sem poder ver nenhum de seus componentes internos.
Se a função de um usuário tiver USAGE em um modelo, ele aparece em uma página de registro de modelos do Snowsight. Para obter mais detalhes, consulte Privilégios de controle de acesso.
Nota
Atualmente, os modelos não oferecem suporte à replicação.
Limitações e problemas atuais¶
O Registro de modelo Snowflake atualmente tem as seguintes limitações:
O registro não pode ser usado em Snowflake Native Apps.
Os modelos não podem ser compartilhados ou clonados e são ignorados durante a replicação.
Versões 1.5.0 e 1.5.1 do pacote snowflake-ml-python
têm os seguintes problemas conhecidos. Até que esses problemas sejam resolvidos, use a solução alternativa fornecida.
Na versão 8.23 e anteriores do Snowflake, a biblioteca não funciona em procedimentos armazenados de direitos do proprietário. Em vez disso, use procedimentos armazenados de direitos do chamador.
Em procedimentos armazenados, o registro de um modelo requer a incorporação de uma cópia da biblioteca do Snowpark ML local no modelo. Especifique a opção
embed_local_ml_library
na chamadalog_model
, conforme mostrado:registry.log_model(..., options={"embed_local_ml_library": True, ...})
Os seguintes limites se aplicam a modelos e versões de modelo.
Modelos |
|
---|---|
Versões do modelo |
|
Abertura do registro de modelo do Snowflake¶
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 Snowflake fornece 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")
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. Este método serializa o modelo – um objeto Python – e cria um objeto modelo Snowflake a partir dele. Este método também adiciona metadados, como uma descrição, ao modelo, conforme especificado na chamada log_model
.
Cada modelo pode ter versões ilimitadas. Para registrar versões adicionais do modelo em log, chame log_model
novamente com o mesmo model_name
, mas com um version_name
diferente.
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, criando um modelo apenas quando adiciona sua primeira versão. Você pode atualizar as tags do modelo depois de registrar a primeira versão do modelo em log.
No exemplo a seguir, clf
, abreviação de “classificador”, é o objeto do modelo Python, que já foi criado em outro lugar em seu código. Você pode adicionar um comentário 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="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)
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 |
Nota
A combinação do nome do modelo e da versão deve ser exclusiva no esquema.
Argumentos opcionais
Argumento |
Descrição |
---|---|
|
Cadeia de caracteres especificando a versão do modelo, usada com |
|
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 com métricas vinculadas à versão do modelo. |
|
Dicionário com opções para criação de modelo. 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 com os dados de entrada de amostra. Os nomes dos recurso 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 |
|
A tarefa que define o problema que o modelo pretende resolver. Se não for especificado, o melhor esforço será feito para inferir a tarefa do modelo a partir da classe do modelo ou ela será definida como |
log_model
retorna um objeto snowflake.ml.model.ModelVersion
, que representa a versão do modelo que foi adicionado ao registro.
Após o registro, 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.
Como trabalhar com artefatos de modelo¶
Depois que um modelo é registrado, seus artefatos (os arquivos que dão suporte ao modelo, incluindo seus objetos Python serializados e vários arquivos de metadados, como seu manifesto) ficam disponíveis em um estágio interno. Os artefatos não podem ser modificados, mas você pode visualizar ou baixar os artefatos dos modelos que possui.
Nota
Ter o privilégio USAGE em um modelo não permite que você acesse seus artefatos; a propriedade é necessária.
Você pode acessar artefatos do modelo de um estágio usando, por exemplo, o comando GET ou seu equivalente em Snowpark Python, FileOperation.get.
No entanto, você não pode abordar artefatos de modelo usando a sintaxe usual do caminho de estágio. Em vez disso, use um snow://
URL, uma maneira mais geral de especificar a localização de objetos no Snowflake. Por exemplo, uma versão dentro de um modelo pode ser especificada por um URL do formulário snow://model/<nome_do_modelo>/versions/<nome_da_versão>/
.
Sabendo o nome do modelo e a versão que você deseja, você pode usar o comando LIST para visualizar os artefatos do modelo da seguinte forma:
LIST 'snow://model/my_model/versions/V3/';
A saída é semelhante a:
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
Para recuperar um desses artefatos, use o comando SQL GET.
GET 'snow://model/model_my_model/versions/V3/MANIFEST.yml'
Ou o equivalente com Snowpark Python:
session.file.get('snow://model/my_model/versions/V3/MANIFEST.yml', 'model_artifacts')
Nota
Os nomes e a organização dos artefatos de um modelo podem variar dependendo do tipo do modelo e podem mudar. A lista de artefatos do exemplo anterior tem a intenção de ser ilustrativa, não autoritativa.
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")
Dica
Você também pode excluir modelos em SQL usando DROP MODEL.
Como obter modelos do registro¶
Para obter informações sobre cada modelo, use o método show_models
:
model_df = reg.show_models()
Dica
Em SQL, use SHOW MODELS para obter uma lista de modelos.
O resultado de show_models
é um pandas DataFrame. As colunas disponíveis estão listadas aqui:
Coluna |
Descrição |
---|---|
|
Data e hora em que o modelo foi criado. |
|
Nome do modelo. |
|
Banco de dados no qual o modelo é armazenado. |
|
Esquema no qual o modelo é armazenado. |
|
Função proprietária do modelo. |
|
Comentário para o modelo. |
|
Matriz JSON listando versões do modelo. |
|
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.
m = reg.get_model("MyModel")
Nota
As instâncias de Model
não são cópias do objeto de modelo Python original registrado; elas são referências ao objeto de modelo subjacente no registro.
Após ter uma referência para um modelo, seja um da lista retornada pelo método models
ou uma recuperada usando get_model
, é possível trabalhar com seus metadados e suas versões.
Exibição e atualização dos metadados de um modelo¶
Você pode visualizar e atualizar os atributos de metadados de um modelo no registro, incluindo seu nome, comentário, 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 sinônimo de comment
. O código anterior também pode ser escrito desta forma:
print(m.description)
m.description = "A better description than the one I provided originally"
Dica
Você também pode definir o comentário de um modelo em SQL usando ALTER MODEL.
Renomeação de um modelo¶
Use o método rename
para renomear ou mover um modelo. Especifique um nome totalmente qualificado como o novo nome para mover o modelo para um banco de dados ou esquema diferente.
m.rename("MY_MODEL_TOO")
Dica
Você também pode renomear um modelo em SQL usando ALTER MODEL.
Como trabalhar com versões de modelo¶
Um modelo pode ter versões ilimitadas, 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.
Dica
Em SQL, use SHOW VERSIONS IN MODEL para ver as versões de um modelo.
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 um DataFrame, chame o método show_versions
do modelo.
version_df = m.show_versions()
O DataFrame resultante contém as colunas a segui:
Coluna |
Descrição |
---|---|
|
Data e hora em que a versão do modelo foi criada. |
|
Nome da versão. |
|
Banco de dados no qual a versão está armazenada. |
|
Esquema no qual a versão está armazenada. |
|
Nome do modelo ao qual esta versão pertence. |
|
Valor booleano que indica se esta versão é a versão padrão do modelo. |
|
Matriz JSON dos nomes das funções disponíveis nesta versão. |
|
Objeto JSON contendo metadados como pares chave-valor ( |
|
Objeto JSON da seção |
Exclusão das versões do modelo¶
É possível excluir uma versão do modelo usando o método do modelo delete_version
:
m.delete_version("rc1")
Dica
Também é possível excluir uma versão do modelo em SQL usando ALTER MODEL … DROP VERSION.
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 = "v2"
Dica
Em SQL, use ALTER MODEL para definir a versão padrão.
Aliases da versão de modelo¶
É possível atribuir um alias a uma versão do modelo usando o comando SQL ALTER MODEL. Você pode usar um alias sempre que um nome de versão for necessário, como ao obter uma referência a uma versão de modelo, em Python ou em SQL. Um determinado alias pode ser atribuído a apenas uma versão de modelo por vez.
Além dos aliases que você cria, os seguintes aliases de sistema estão disponíveis em todos os modelos:
DEFAULT
refere-se à versão padrão do modelo.FIRST
refere-se à versão mais antiga do modelo em termos de tempo de criação.LAST
refere-se à versão mais recente do modelo no momento da criação.
Os nomes de alias que você criar não devem ser iguais a nenhum nome de versão ou alias existente no modelo, incluindo aliases do sistema.
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:
m = reg.get_model("MyModel")
mv = m.version("v1")
mv = m.default
Após ter uma referência a uma versão específica de um modelo (como a variável mv
neste exemplo), é possível recuperar ou atualizar seus comentários ou métricas e chamar os métodos (ou 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"
Dica
Também é possível alterar o comentário de uma versão do modelo em SQL usando ALTER MODEL … MODIFY VERSION.
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 é possível definir esses valores como métricas:
# 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")
Dica
Também é possível modificar as métricas de uma versão do modelo (que são armazenadas como metadados) em SQL usando ALTER MODEL … MODIFY VERSION.
Recuperação de explicações do modelo¶
O registro do modelo é capaz de explicar os resultados de um modelo, informando quais recursos de entrada contribuem mais para as previsões, calculando os valores de Shapley. Este recurso de versão está disponível por padrão em todas as exibições de modelo criadas no Snowflake 8.31 e posteriores por meio do método explain
do modelo subjacente. É possível chamar explain
de SQL ou por meio de um método run
de exibição de modelo em Python.
Para obter detalhes sobre esse recurso, consulte Explicabilidade do modelo.
Exportação de uma versão do modelo¶
Use mv.export
para exportar os arquivos de um modelo para um diretório local; o diretório é criado se não existir:
mv.export("~/mymodel/")
Por padrão, os arquivos exportados incluem o código, o ambiente para carregar o modelo e os pesos do modelo. Para exportar também os arquivos necessários para executar o modelo em um warehouse, especifique export_mode = ExportMode.FULL
:
mv.export("~/mymodel/", export_mode=ExportMode.FULL)
Carregamento da versão do modelo¶
Use mv.load
para carregar o objeto do modelo Python original que foi adicionado originalmente ao registro. É possível então usar o modelo para inferência como se o tivesse definido em seu código Python:
clf = mv.load()
Para garantir a funcionalidade adequada de um modelo carregado do registro, o ambiente Python de destino (ou seja, as versões do interpretador Python e de todas as bibliotecas) deve ser idêntico ao ambiente do qual o modelo foi registrado. Especifique force=True
na chamada load
para forçar o carregamento do modelo mesmo que o ambiente seja diferente.
Dica
Para garantir que seu ambiente seja o mesmo onde o modelo está hospedado, baixe uma cópia do ambiente conda do registro do modelo:
conda_env = session.file.get("snow://model/<modelName>/versions/<versionName>/runtimes/python_runtime/env/conda.yml", ".")
open("~/conda.yml", "w").write(conda_env)
Em seguida, crie um novo ambiente conda a partir deste arquivo:
conda env create --name newenv --file=~/conda.yml
conda activate newenv
O argumento options
opcional é um dicionário de opções para carregar o modelo. Atualmente, o argumento oferece suporte apenas à opção use_gpu
.
Opção |
Tipo |
Descrição |
Padrão |
---|---|---|---|
|
|
Habilita a lógica de carregamento específica da GPU. |
|
O exemplo a seguir ilustra o uso do argumento options
:
clf = mv.load(options={"use_gpu": True})
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 de modelo, use mv.run
, especificando o nome da função a ser chamada e passando um DataFrame Snowpark ou pandas que contenha os dados de inferência e quaisquer outros parâmetros necessários. O método é executado em um warehouse Snowflake.
O valor de retorno do método é um DataFrame Snowpark ou panda, dependendo do tipo de DataFrame passado. DataFrames Snowpark são avaliados lentamente, então o método é executado somente quando o método do DataFrame collect
, show
ou to_pandas
for chamado.
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")
remote_prediction.show() # assuming test_features is Snowpark DataFrame
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 Python no modelo registrado original.
Dica
Você também pode chamar métodos de modelo em SQL. Consulte Métodos de modelo.
Considerações sobre custo¶
O uso do registro de modelo do Snowflake incorre em custos padrão baseados no consumo do Snowflake. Isso inclui:
Custo de armazenamento de artefatos, metadados e funções do modelo. Para obter informações gerais sobre os custos de armazenamento, consulte Exploração do custo 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 mostra os modelos e versões de modelo e alteração de 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. Para obter informações gerais sobre os custos de computação do Snowflake, consulte Explicação dos custos de computação. Os custos de computação do warehouse são incorridos para:
Operações de criação de modelo e versão
Invocação dos 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 Snowflake.
Snowpark ML¶
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
quando você 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
quando você 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)
clf = ensemble.RandomForestClassifier(random_state=42)
clf.fit(iris_X, iris_y)
model_ref = registry.log_model(
clf,
model_name="RandomForestClassifier",
version_name="v1",
sample_input_data=iris_X,
options={
"method_options": {
"predict": {"case_sensitive": True},
"predict_proba": {"case_sensitive": True},
"predict_log_proba": {"case_sensitive": True},
}
},
)
model_ref.run(iris_X[-10:], function_name='"predict_proba"')
XGBoost¶
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
quando você 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 este para passar ao 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, é necessário fornecer uma lista de tensores (que serão convertidos em DataFrame pandas) ou um 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
quando você 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 este para passar ao 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, é necessário fornecer uma lista de tensores (que serão convertidos em DataFrame pandas) ou um 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
quando você 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
quando você 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¶
Nota
Para obter detalhes sobre a entrada e saída esperadas de tipos específicos de pipelines Hugging Face, consulte Assinaturas inferidas para pipelines 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
somente se o pipeline contiver uma tarefa da seguinte lista:
conversational
fill-mask
question-answering
summarization
table-question-answering
text2text-generation
text-classification
(também chamado desentiment-analysis
)text-generation
token-classification
(também chamado dener
)translation
translation_xx_to_yy
zero-shot-classification
O argumento sample_input_data
é completamente ignorado para modelos Hugging Face. Especifique o argumento signatures
ao registrar um modelo Hugging Face que não está na lista acima, para que o registro saiba as assinaturas dos métodos de destino.
Para ver a assinatura inferida, use o método show_functions
. O código a seguir, 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, é possível 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}]