10.4 Testando MLflow
Agora que temos um servidor MLflow configurado e rodando, podemos testar todos os seus componentes, incluindo o registro de modelos, que não funciona com um sistema de arquivos somente. Faremos isso por meio do exemplo de classificador de produtos que estivemos trabalhando desde o início deste livro.
10.4.1 Criando um projeto MLflow
Crie uma pasta, chamada classificador-produtos-mlflow
, e um ambiente virtual, definido no arquivo python_env.yaml
:
(Obs: se estiver utilizando Windows, utilize WSL, pois os ambientes virtuais no mlflow não funcionam bem no Windows)
Agora vamos criar o código de treinamento do modelo. É o mesmo código que já estivemos trabalhando até agora, apenas adaptado para rodar de uma forma mais simples, fora do notebook. Mas funcionaria dentro do notebook também, desde que seja utilizado o kernel do ambiente Conda.
Faça o download do dataset (produtos.csv) e salve-o na pasta também.
Crie um arquivo chamado train.py
, que tem o mesmo conteúdo de antes, porém em um único script. Também acrescentamos alguns parâmetros simples de configuração, e um código de registro da execução no MLflow:
Os comentários no código explicam o seu funcionamento em detalhes.
Vamos configurar um projeto MLflow, para facilitar a reproducibilidade. Crie um arquivo chamado MLproject
, com o seguinte conteúdo:
Podemos agora executar o projeto localmente e testá-lo. Para isso, precisamos criar um novo ambiente, de preferência em uma nova pasta (exemplo: ambiente-mlflow
). Não é preciso instalar nada além do MLflow, pois ele irá criar/recriar o ambiente a cada execução, se necessário. Também precisamos indicar ao MLflow onde está o servidor, por meio de variáveis de ambiente:
Lembre-se, no Windows PowerShell a definição de variáveis de ambiente é diferente:
Agora execute o comando mlflow run <pasta do projeto>
, apontando para a pasta classificador-produtos-mlflow
criada anteriormente. O comando irá procurar, na pasta indicada, pelo arquivo MLproject
, e irá disparar a execução.
Poderíamos rodar com python train.py
, mas aí precisaríamos ativar o ambiente definido em python_env.yaml
manualmente. Também perderíamos as vantagens do empacotamento de projetos, que incluem, por exemplo, o rastreamento automático dos parâmetros definidos no arquivo MLproject
.
Se não quiser executar agora, não tem problema. Faremos um ciclo DevOps completo a seguir, e a execução poderá ser feita daqui a pouco. Caso execute, você verá o resultado da execução aparecendo na interface do MLflow.
10.4.2 Subindo o projeto para o GitLab e executando experimentos
Vamos configurar um projeto no GitLab para poder controlar as versões cuidadosamente e testar nosso empacotamento. Crie um projeto no GitLab chamado classificador-produtos-mlflow
e inicialize com o conteúdo da pasta com o projeto (lembre-se de excluir o conteúdo da pasta .venv
, se tiver criado, pois ela é enorme e não deve ser versionada). Para facilitar os testes, crie o projeto com visibilidade pública.
Vamos rodar. Se não tiver feito ainda, abra um novo terminal e crie uma nova pasta/ambiente conforme as instruções no final da última seção. Se possível, para testar a reproducibilidade, crie tudo numa pasta limpa. Ou melhor ainda, tente em uma máquina diferente, se preferir, que tenha acesso de rede à máquina onde o MLflow está rodando. Neste caso, não esqueça de substituir o endereço definido na variável de ambiente pelo da máquina que está rodando o MLflow, e de verificar as conexões de firewall da rede.
Execute utilizando os seguintes comandos. Teste um, primeiro, para ver se deu certo, e os restantes depois, para criar várias execuções. Vamos também mudar o nome do experimento para diferenciar da execução anterior:
Não esqueça de substituir o endereço do repositório GitLab pelo que você criou, e o parâmetro main
pelo nome do branch que você definiu. Vai demorar um tempinho até que o projeto seja transferido, o ambiente seja recriado, e o experimento, executado.
Podemos ver o resultado das execuções na interface visual. Abra o endereço no navegador: http://localhost:5000
:
Experimente navegar pela interface e ver os resultados obtidos, as visualizações disponíveis. Veja como os commits no GitLab aparecem nessa interface também, para possibilitar a identificação da versão do código que originou cada experimento. Aparentemente, podemos retreinar com um tamanho de teste 0.25, pois o gráfico nos indica que há uma possibilidade de melhoria aqui. Experimente com esse parâmetro, se quiser.
10.4.3 Registrando modelos
Agora podemos registrar um modelo. Na tela de visualização dos experimentos, ordene pela métrica de acurácia, decrescentemente, e depois selecione o experimento clicando sobre o link indicado na figura.
Na visualização dos detalhes da execução, é possível conferir o comando executado, os parâmetros, as métricas, o dataset, e demais registros. É também possível registrar o modelo. Faça isso clicando no botão "Register Model".
Na janela aberta, escolha a opção "Create New Model" e escolha um nome para ele. No caso, escolhemos "classificador-produtos".
Quando uma execução gera um modelo, isso fica indicado na interface principal, por meio de um link.
Também é possível ver todos os modelos registrados clicando na aba "Models", no topo da página:
Note como, neste caso, só temos um modelo e uma versão. Em breve criaremos outra versão do modelo.
10.4.4 Subindo uma API HTTP para servir o modelo registrado
Obs: O conteúdo desta seção encontra-se desatualizado. Os exemplos podem não funcionar corretamente nas versões mais recentes das ferramentas
Agora vamos servir esse modelo como uma API HTTP, utilizando o servidor embutido do MLflow. Faremos isso usando Docker.
Na pasta mlflow-server
, que criamos na seção anterior, crie uma pasta chamada classificador-produtos
. Dentro dela, crie um Dockerfile
:
Essa imagem servirá para rodarmos apenas o MLflow para subir o modelo como uma API, então precisamos apenas prepará-la. Veja como não há nada exceto a instalação do mlflow em uma imagem miniconda, e o script wait-for-it.sh
(o mesmo que já utilizamos antes). Agora modifique o arquivo compose.yml
:
Iniciaremos um novo serviço, responsável por subir a API com o modelo registrado. Veja como definimos o endereço do servidor do MLflow na variável de ambiente MLFLOW_TRACKING_URI
. Isso é a única coisa necessária para que possamos recuperar o modelo.
Veja agora o conteúdo de entrypoint
:
bash ./wait-for-it.sh mlflow:5000 -t 90
: espera que o MLflow esteja funcionando para subir a APImlflow models serve
: comando do MLflow para servir um modelo-m 'models:/classificador-produtos/1'
: indica ao MLflow que é para recuperar o modelo chamadoclassificador-produtos
em sua versão 1 (a única que temos até agora, que registramos há pouco)-p 8080 -h 0.0.0.0
: escuta na porta 8080 requisições de qualquer origem
Interrompa a execução do docker compose
e rode-o novamente. Lembre-se de incluir a opção --build
para forçar a reconstrução das imagens, se necessário.
Acompanhe enquanto os serviços são executados um a um. Veja como o serviço da API demora para subir. Isso acontece pois ele irá criar todo o ambiente Conda novamente para hospedar o modelo, agora dentro do contêiner Docker. Para isso, irá instalar as dependências, entre as tarefas de criação do ambiente.
Quando estiver tudo rodando, podemos fazer um teste, enviando uma requisição POST:
Fazemos uma requisição com conteúdo text/csv
pois estamos enviando texto. O MLflow tem suporte a esse formato.
10.4.5 Utilizando modelos em tarefas offline
No mesmo ambiente onde o mlflow foi instalado anteriormente, crie um arquivo chamado batch.py
:
O código é extremamente simples, e ilustra como o registro de modelos facilita a busca e uso de modelos. Execute-o e veja as predições sendo produzidas em lote (batch). Poderíamos fazer o mesmo que fizemos na Seção 2.1, salvando as predições em um banco de dados.
10.4.6 Utilizando versões Staging e Production (está sendo descontinuado)
Também é possível trabalhar com versões preparadas como Staging e Production. Dessa forma, os usuários dos modelos não precisam se preocupar com qual é a melhor versão. Basta saber que é a versão em produção. Fica a cargo dos desenvolvedores e avaliadores dos modelos decidir qual é a melhor versão. Vamos fazer isso agora. Mas antes, vamos criar uma nova versão. Vamos fazer a já famigerada mudança para ignorar acentos no treinamento. No projeto classificador-produtos
, que é onde fazemos o treinamento, vamos fazer as modificações necessárias. Se tiver apagado a pasta, faça uma clonagem do repositório do GitLab novamente.
Primeiro, vamos ajustar o arquivo python_env.yaml
:
Agora vamos modificar o código de train.py
:
Para treinar novamente, basta fazer um novo commit:
Agora, no terminal com o ambiente do mlflow, execute o comando que faz mais seis treinamentos com a nova versão (nem testaremos com a opção sem nomes, pois já vimos que são todas piores). Caso necessário, reative o mesmo ambiente de antes e exporte as variáveis de ambiente necessárias:
A nova execução irá demorar pois, lembre-se, modificamos o ambiente (python_env.yaml
), que precisará ser recriado antes da execução. Ao término da execução, teremos seis novas execuções para analisar. Veja como elas tem uma versão de código diferente, pois fizemos a alteração no GitLab, e isso fica registrado no MLflow.
Aparentemente, nossa alteração não alterou a acurácia dos modelos, portanto podemos mais uma vez apenas selecionar a opção com maior acurácia:
Veja como a outra execução já está registrada como modelo, na versão 1. Agora vamos registrar essa nova execução como a versão 2 desse mesmo modelo:
Ao escolher o mesmo modelo que antes, será criada a versão 2. Clique na aba "Models" no topo da página, e depois em "classificador-produtos" para ver as duas versões:
Como discutido anteriormente, poderíamos simplesmente nos referir aos números das versões para utilizar esses modelos, seja ao subir uma API ou ao realizar uma tarefa em batch, como já fizemos até agora. Mas podemos também usar o conceito de Stage. Vamos colocar a versão 1 como Production e a versão 2 como Staging. Isso pode ser feito clicando-se na versão e escolhendo a opção "Transition to":
Obs: pode ser necessário desabilitar a opção "New model registry UI", caso esteja habilitada, pois esta função está sendo depreciada. Pode ser que, no momento da leitura, esta opção nem exista mais. Neste caso, vá para a seção seguinte.
Faça isso agora. Coloque a versão 1 em estágio de Production e a versão 2 em estágio de Staging.
Agora vamos modificar o arquivo batch.py
para recuperar os modelos utilizando fases ao invés de números:
O resultado irá mostrar os resultados de cada versão. Veja como a versão de Staging prediz corretamente a categoria sem acentos. Vamos trocar as versões para ver como é fácil? Na interface do MLflow, troque as versões de Staging para Production e vice-versa. Cuidado para não arquivar automaticamente as versões ao fazer as alterações (será exibida uma opção para fazer isso, desmarque). Caso tenha arquivado, porém, basta resgatá-las e reativá-las com as transições desejadas.
Re-execute o script e veja que as mudanças se refletiram sem a necessidade de mudar o código. Ou seja, os usuários dos modelos não precisam sempre ficar sabendo das escolhas dos melhores modelos, podem apenas utilizar a versão marcada como Production ou Staging, confiando nos desenvolvedores dos modelos.
10.4.7 Utiliando aliases (substitui as versões Staging e Production)
Ao invés de utilizar os estágios predefinidos pelo MLFlow (Nenhum, Staging, Production e Archived), atualmente é possível definir seus próprios rótulos para cada modelo. Além de trazer a possibilidade de adicionar mais estágios, caso necessário, é possível dar mais do que um rótulo para uma mesma versão de modelo. Obviamente, não é possível que um mesmo rótulo seja atribuído a mais de uma versão, já que o objetivo é oferecer uma forma mais amigável de se encontrar uma versão de um modelo, dentre as várias registradas.
Para ilustrar, acesse a interface do MLFlow e habilite a opção "New model registry UI", caso ainda não esteja habilitada.
Em seguida, crie alguns rótulos para as duas versões dos modelos. Neste exemplo, utilizaremos testes
e produção
para marcar dois estágios diferentes de evolução de um modelo, mas também utilizaremos rótulos para marcar o que quisermos, no caso treinamento-com-acentos
e treinamento-sem-acentos
, para indicar a diferença entre essas versões:
Agora volte ao código batch.py
para mudar a forma como os modelos são encontrados, utilizando os rótulos recém-criados. Note como o padrão da URL muda, ao invés de /
, utilizamos @
para separar o nome da versão:
Veja como é possível recuperar a mesma versão utilizando dois rótulos diferentes.
Esse exemplo não segue exatamente a recomendação da documentação do MLFlow, que sugere o registro de modelos diferentes para produção e testes, e não apenas diferentes versões. Dessa forma, é possível ganhar ainda mais variedade no versionamento.
Por exemplo, ao invés de termos um modelo e duas versões para produção e testes:
models:/classificador-produtos/Staging
models:/classificador-produtos/Production
Sugere-se dois modelos com NOMES diferentes (ambientes diferentes, versões de códigos diferentes, etc), e rótulos para indicar um grau a mais de refinamento:
models:/prod.classificador-produtos@champion
models:/stag.classificador-produtos@treinado-sem-acentos
Definir uma política consistente de nomes e rótulos traz grande flexibilidade ao ciclo de vida MLOps, facilitando, por exemplo, a nomeação de versões, testes A/B, e até mesmo o controle de acesso separado por versões, algo que não foi abordado aqui mas que está detalhado na documentação da ferramenta.
10.4.8 Considerações finais
O MLflow é uma ferramenta que pode ser muito útil para diferentes cenários, desde pequenas equipes até grandes empresas. Não é uma ferramenta que resolve todos os problemas de MLOps, mas ela ajuda em diferentes momentos. Além de ser de fácil instalação e configuração, o MLflow pode ser utilizado em partes. Caso queira usar somente o componente de rastreamento de experimentos, é possível. Caso queira usar o componente de projetos, também é possível. O registro de modelos também facilita bastante a vida quando a quantidade de modelos e versões é muito grande.
Há muitas outras funções e possibilidades de configuração e uso do MLflow. A documentação oficial é bastante rica e cheia de exemplos. Vale a pena estudar!
Last updated