Parte 2 | Pipelines de machine learning com Kedro

Você fez o download dos seus dados de um banco de dados, depois fez a análise exploratória deles, removeu os dados inválidos, definiu o problema de predição, fez vários testes e, por fim, escolheu um modelo bacana, com acurácia acima de oito mil (com ajustes finos de hiperparâmetros, claro).

Mas e agora?
Como transformar esse notebook extremamente organizado em um produto?

Como me sinto trabalhando nos meus notebooks

Primeiramente, é difícil manter-se organizado utilizando um notebook. Existem ferramentas para a documentação, mas a vida pode seguir sem que se faça bom uso delas. Além disso, a estrutura dos notebooks tem algumas limitações dependendo do uso.

Normalmente, os seus resultados são extremamente úteis para análises únicas e pontuais, mas carecem de funcionalidades para uma utilização contínua. Nesse âmbito, integração, manutenção e desempenho são palavras-chave. Afinal, aplicações mais robustas precisam de frameworks mais robustos.

Os algoritmos que preveem o melhor horário para lhe enviar uma notificação não estão rodando em um notebook

Por isso, a sugestão do dia é Kedro que, segundo a definição disponível na documentação oficial, em tradução livre:

é uma estrutura Python de código aberto para a criação de código de ciência de dados reproduzível, sustentável e modular. Ele toma emprestado conceitos das melhores práticas de engenharia de software e os aplica ao código de aprendizado de máquina; os conceitos aplicados incluem modularidade, separação de interesses e controle de versão.

Esse parágrafo descreve de maneira quase musical o que é o Kedro. Vamos analisar os principais pontos por partes.

  • Estrutura Python de código aberto: o Kedro é gratuito e mantido pela sua comunidade, o que facilita sua utilização.
  • Código reproduzível: com Kedro, é possível criar pipelines de dados e utilizá-los para diferentes fontes de dados.
  • Código sustentável: a estrutura de Kedro facilita a manutenção nos códigos e o trabalho colaborativo de uma equipe sobre um mesmo pipeline.
  • Código modular: as funções podem ser usadas em partes diferentes do pipeline bem como em pipelines diferentes.

Portanto, a seguir, apresentamos um guia rápido de aplicação de Kedro, baseado na documentação oficial do módulo. Ao final, também mostraremos um projeto exemplo de aplicação.

1) Instalação

Para a instalação do Kedro, é altamente recomendável utilizar um ambiente virtual (virtual environment). Não entraremos nessa parte, mas há diversas fontes online ensinando como fazê-lo. Após ativar o ambiente virtual, a instalação do Kedro se dá, através do pacote PyPI, rode, em um terminal:

$ pip install kedro

Para verificar a instalação, rode:

$ kedro info

Se tudo der certo, você verá a seguinte imagem, seguida da versão instalada:

2) Criando seu primeiro projeto Kedro

Para criar o seu primeiro projeto Kedro, rode o seguinte comando em seu terminal:

$ kedro new

A seguir, você responderá a três perguntas: (1) qual é o nome do projeto (use um nome legível separado por underlines); (2) o nome da pasta do projeto (se você pular, o nome da pasta será o nome do projeto); (3) e o nome do pacote no seu projeto (esse último também pode ser pulado). Inicialize também o versionamento Git com:

$ git init

Obs.: neste post, não abordaremos os conceitos de Git, mas é altamente recomendável a utilização de Git para o controle de versionamento. O Kedro já inclui arquivos padrão de readme e gitignore. Lembre-se de que todas as pastas “local” serão ignoradas pelo Git.

3) Projeto Exemplo

Conforme citado no primeiro texto desta série, utilizaremos um projeto padrão para a aplicação dos frameworks que trabalharemos: o dataset completo dos Pokémons, cujos dados estão disponíveis no Kagle). O repositório para esse projeto pode ser encontrado neste link.

Os datasets podem ser encontrados em:

4) Estrutura padrão Kedro

O Kedro é definido por uma estrutura de nós e pipelines. Os nós são as funções que executam quaisquer operações nos dados. Um conjunto de nós executados em sequência é chamado de pipeline. Os pipelines mais comuns são os de data engineering e data science.

Os pipelines de dados e os nós realizando as operações

Na prática, o Kedro utiliza pastas padrão para definir seus nós e pipelines. As pastas padrão mais importantes do Kedro são:

  • /conf/ - contém os arquivos “catalog.yml” e “parameters.yml”, que são as configurações de todos os arquivos e parâmetros utilizados nos modelos; possui duas subpastas, base e local (que é ignorada pelo Git).
  • /src/ - contém os arquivos “nodes.py” e “pipeline.py”, que definem as funções (nos nós) e os pipelines que identificam quais as entradas e saídas de cada nó; a subpasta é o nome do projeto.
  • /data/ - o Kedro cria uma pasta para o salvamento dos dados (tanto crus quanto manipulados) e modelos; as subpastas padrão já são definidas e numeradas, na ordem em que os dados geralmente são utilizados em pipelines de ciência de dados.

As subpastas das pastas “conf” e “src” devem ter os nomes dos pipelines. Por exemplo, considere as seguintes subpastas:

- Guarda as informações sobre dados de entrada e saída (locais de salvamento, formato etc.) e parâmetros utilizados nas funções de data engineering.
Obs.: a pasta raiz (/conf/) guarda as informações sobre os dados ainda não processados.

- Guarda o arquivo de nodes com as funções executadas no data engineering do projeto, e o pipeline que define a ordem das operações.

O Kedro tem um arquivo específico para a definição dos pipelines e dos comandos a serem executados no terminal para executar pipelines específicos. O arquivo hooks declara todos os pipelines do projeto e é localizado neste caminho:

A função register_pipelines() dentro desse arquivo define todos os pipelines do projeto.

Obs: em versões anteriores do Kedro, o arquivo tinha o nome de hooks.py, porém a estrutura do arquivo é a mesma.

Pipelines e Nodes

O coração do projeto Kedro são os nós e os pipelines. Esses arquivos contêm toda a informação sobre como manipular os dados e em que ordem.

Conforme descrito anteriormente, os nós são as funções a serem aplicadas nos dados. E eles são de fato funções python stricto sensu. A principal vantagem da utilização de funções para as operações é a sua modularidade. Por exemplo: datasets com colunas iguais podem todos treinar os seus modelos da mesma forma e, portanto, o mesmo nó pode ser reutilizado em datasets diferentes. Um exemplo de arquivo node pode ser encontrado no arquivo:

Você pode perceber, por exemplo, que, no nó de pré processamento, há funções para a limpeza dos dados e operações básicas. Você pode navegar pelo repositório e entender passo a passo as operações que levam até o treinamento do modelo.

Agora que nós temos as funções, só é necessário lidar com entradas e saídas, e é aí que entra a mágica dos pipelines. O arquivo pipeline descreve a ordem dos nós a serem executados, seus nomes, a função (do arquivo nodes.py) que cada nó executará, os inputs e outputs dessa função.

O exemplo do pipeline de pré-processamento, o mesmo dos nós citados acima, encontra-se em:

Você pode perceber, ao entrar no arquivo pipelines.py, que os dados são apenas chamados pelo nome, e não há indicações de caminho de salvamento, por exemplo. O Kedro disponibiliza uma estrutura intuitiva para este fim: os arquivos de configuração catalog.yml e parameters.yml, conforme detalharemos a seguir.

Os arquivos catalog.yml e parameters.yml

O Kedro utiliza arquivos de extensão yml para as configurações do projeto. Os principais são os catalogs e os arquivos de parâmetros. Esse formato padrão é de fácil leitura, e sua padronização permite uma interação muito mais fácil para todos os profissionais do projeto.

Esses arquivos também proporcionam uma modularidade que permite a integração entre os diversos ambientes do projeto: desenvolvimento, produção e até no ambiente de testes dos notebooks. Assim, garante-se que toda a equipe esteja trabalhando nos mesmos arquivos, e que não será necessário buscá-los em algum diretório (nem correr o risco de acessar o arquivo errado).

O catalog contém informações de salvamento e, por consequência, de importação de arquivos. Ele especifica o caminho do arquivo e o seu tipo, e também pode incluir outras informações, como as credenciais de acesso (que estarão salvas em outro arquivo yml, o credentials). Por exemplo, no caminho pokemon_ml_project/conf/base/catalog.yml, encontra-se a localização do dataset cru:

Esse arquivo especifica o nome do dataset no contexto do Kedro, o tipo e o caminho do salvamento. Uma vez declarado em qualquer catalog do projeto, o próprio Kedro é capaz de lidar com os arquivos no contexto dos arquivos de pipeline, conforme tratamos na seção anterior. Nesse caso, o arquivo é salvo como um dataset pandas em csv, mas há uma longa lista de tipos de arquivos suportados por Kedro, e ela está disponível na documentação oficial.

Assim, para chamar o arquivo data/01_raw/pokemon.csv, só precisamos chamar “pokemon_database”, e o Kedro trata de lidar com o resto.

Já o parameters.yml possibilita alterar parâmetros das funções de forma fácil, como por exemplo hiperparâmetros para o ajuste fino de um modelo de machine learning. Um exemplo dos parâmetros, no caminho  que se encontra no caminho:

Nesse arquivo, podemos ver a descrição de alguns parâmetros comuns em ML, como a fração de treino e teste, e os parâmetros mais comuns em um modelo de classificação por árvore de decisão. Esses são argumentos das funções nodes do Kedro, e serão passados aos modelos dentro dos nós.

Jupyter notebooks em kedro

Outra pasta padrão é a de notebooks. O Kedro possui integração com jupyter, e o usuário pode utilizar os notebooks para análises exploratórias e testes de funções. Os notebooks podem ser utilizados através do comando:

$ kedro jupyter lab

Esse comando cria um jupyter e devolve um link para acessá-lo através de um browser. O Kedro possui comandos próprios para interação com os dados e funções, e pode carregar datasets e modelos com apenas uma linha de código. Todo objeto definido em um catalog (podendo ser ele desde um modelo treinado até um pandas DataFrame) pode ser importado. O comando para a importação é:

catalog.load("nome_do_arquivo_no_catalog")

O Jupyter Notebook é altamente recomendado para todos os testes de conceito antes de serem implementados, bem como a realização de EDA dos dados. Mais comandos para o jupyter notebook no contexto do Kedro podem ser encontrados na sua documentação oficial.

O arquivo requirements

O Kedro cria um arquivo com os requisitos do projeto, ou seja: quais os módulos utilizados, quais as versões etc. Previne-se assim que os módulos sejam atualizados e as funções parem de funcionar. Preenche-se o arquivo requirements.txt (localizado na pasta /src/) e roda-se o seguinte comando para atualizar as dependências do Kedro:

kedro build-reqs

Depois, para instalar todas as dependências de maneira correta, o comando é:

$ kedro install
Visualização de pipelines

O Kedro também disponibiliza uma ferramenta de visualização dos pipelines chamada Kedro-Viz. Ela conecta automaticamente os nós e proporciona uma visualização interessante tanto para profissionais técnicos quanto para apresentações a audiências não técnicas. Para instalar a extensão, utilize:

$ pip install kedro-viz

A visualização é gerada a partir do comando (sim, só isso):

kedro viz
The Kedro-Viz pipeline for the Pokémon project
5) Rodando seu projeto

Para executar o seu projeto Kedro, rode apenas seguinte o comando:

$ kedro run

Também é possível rodar pipelines ou nós específicos, rodando:

$ kedro run --pipeline=data_engineering
$ kedro run --node=clean_data

Como apenas um comando é capaz de executar diversas tarefas, o Kedro consegue trabalhar muito bem em conjunto com APIs e outros frameworks de automação de execução de código.

Todos os outputs dos nodes serão salvos nas pastas especificadas nos arquivos de catalog.yml, e elas podem ser tanto locais quanto em nuvem.

6) Extra: boas práticas

Sim, o Kedro é ótimo para o gerenciamento de pipelines de ciência de dados. A estrutura padrão já é um forte incentivo para que o projeto se mantenha nos trilhos. Entretanto, há que se ter disciplina e cuidado ao escrever um pipeline de Kedro para aproveitar todas as vantagens desse framework.

  • Crie funções

Existe um mantra no desenvolvimento de software que diz: “não repita código”. Se você está repetindo operações em um arquivo, é porque provavelmente isso deveria transformar-se em uma função.

Mantenha suas funções com apenas um nível lógico, e deixe os níveis mais altos para serem feitos dentro de outras funções. Se essas funções necessitarem de mais níveis lógicos, chame funções dentro de suas funções. Assim, seu arquivo de nós será mais legível, mais modular e será mais fácil de manter ou alterar.

  • Utilize uma estrutura de pipelines padrão

O nome dos seus pipelines devem indicar de forma instintiva para o leitor qual é a função que ele exerce na estrutura do projeto. Nossa sugestão é utilizar os nomes padrão:

  • pre_processing: utilizado para a limpeza inicial dos dados.
  • data_engineering: utilizado para criação de features, separação de sets de treino e teste, separação X e y etc.
  • data_science: modelagem de ML.
  • metrics: node para avaliação dos resultados dos modelos (exploraremos mais sobre isso no próximo texto desta série.

  • Pense na modularidade

Sempre que escrever uma função, tente deixá-la o mais genérica possível. Imagine que seus dados podem mudar, como por exemplo o número de colunas, nomes das colunas etc. Escrever código que seja fácil de ser atualizado vai lhe poupar muito trabalho no futuro.

  • Documente os processos: outras pessoas vão trabalhar no mesmo projeto que você

Deixe comentários em todas as funções que criar. O que essa função faz, quais são os inputs e outputs essenciais para que as próximas pessoas a utilizar seu código sejam capazes de interpretar e realizar alterações que se fizerem necessárias.

  • Busque ajuda de um desenvolvedor caso sua experiência em programação seja limitada.

Se você, assim como eu em meu primeiro projeto em Kedro, não tem uma extensa experiência em programação, busque a ajuda de um desenvolvedor para revisar seu código e sugerir alterações.

  • Não tenha medo do debug, ele é seu amigo.

Aprenda a usar o debug do seu IDE, (o Kedro é facilmente debugável via VSCode, por exemplo) e faça uso extenso desse recurso. Sempre que os resultados forem diferentes do esperado, ou quando um erro inesperado acontecer, será essencial encontrar o problema rapidamente e resolvê-lo.

Próximos passos

O Kedro não é capaz de fazer o acompanhamento de métricas do projeto, nem de salvar as alterações feitas durante a duração dele. Por isso, outras ferramentas podem ser usadas como plugins para o Kedro, para a implementação de outras funcionalidades.

No próximo post, apresentaremos o plugin de MLFlow para Kedro, e como é possível acompanhar o desempenho dos modelos a cada nova iteração.

Até lá!