Análise de Séries Temporais: Modelo VAR-Como-Um-Serviço Usando Flask e MinIO

VAR-As-A-Service é uma abordagem MLOps para a unificação e reutilização de modelos estatísticos e de aprendizagem de máquina em pipelines de implantação. Este é o segundo de uma série de artigos construídos sobre esse projeto, representando experimentos com vários modelos estatísticos e de aprendizagem de máquina, pipelines de dados implementados usando ferramentas DAG existentes e serviços de armazenamento, tanto baseados em nuvem quanto soluções on-premises alternativas. Este artigo se concentra na armazenagem de arquivos de modelo usando uma abordagem também aplicável e utilizada para modelos de aprendizagem de máquina. O armazenamento implementado é baseado em MinIO como um serviço de armazenamento de objetos compatível com o AWS S3. Além disso, o artigo fornece uma visão geral de soluções de armazenamento alternativas e destaca os benefícios do armazenamento baseado em objetos.

O primeiro artigo da série (Análise de Séries Temporais: VARMAX-As-A-Service) compara modelos estatísticos e de aprendizagem de máquina como modelos matemáticos e fornece uma implementação completa de um modelo estatístico baseado em VARMAX para previsão macroeconômica usando uma biblioteca Python chamada statsmodels. O modelo é implantado como um serviço REST usando Flask e servidor web Apache, embalado em um contêiner Docker. A arquitetura de alto nível do aplicativo é representada na imagem a seguir:

O modelo é serializado como um arquivo pickle e implantado no servidor web como parte do pacote de serviço REST. No entanto, em projetos reais, os modelos são versionados, acompanhados de informações de metadados, e protegidos, e os experimentos de treinamento precisam ser registrados e mantidos reproduzíveis. Além disso, do ponto de vista arquitetural, armazenar o modelo no sistema de arquivos ao lado do aplicativo contradiz o princípio da responsabilidade única. Um bom exemplo é a arquitetura baseada em microsserviços. Dimensionar o serviço de modelo horizontalmente significa que cada instância de microsserviço terá sua própria versão do arquivo pickle físico replicado em todas as instâncias de serviço. Isso também significa que o suporte a múltiplas versões dos modelos exigirá um novo lançamento e reimplementação do serviço REST e de sua infraestrutura. O objetivo deste artigo é desacoplar os modelos da infraestrutura do serviço web e permitir a reutilização da lógica do serviço web com diferentes versões de modelos.

Antes de mergulhar na implementação, vamos falar um pouco sobre modelos estatísticos e o modelo VAR utilizado nesse projeto. Modelos estatísticos são modelos matemáticos, assim como modelos de aprendizado de máquina. Mais sobre a diferença entre os dois pode ser encontrada no primeiro artigo da série. Um modelo estatístico geralmente é especificado como uma relação matemática entre uma ou mais variáveis aleatórias e outras variáveis não aleatórias. Autoregressão Vetorial (VAR) é um modelo estatístico usado para capturar a relação entre múltiplas quantidades à medida que elas mudam ao longo do tempo. Os modelos VAR generalizam o modelo autoregressivo de variável única (AR) permitindo séries temporais multivariadas. No projeto apresentado, o modelo é treinado para fazer previsões para duas variáveis. Os modelos VAR são frequentemente utilizados em economia e ciências naturais. Em geral, o modelo é representado por um sistema de equações, que no projeto estão escondidas atrás da biblioteca Python statsmodels.

A arquitetura do aplicativo de serviço do modelo VAR é retratada na imagem a seguir:

O componente de tempo de execução VAR representa a execução real do modelo com base nos parâmetros enviados pelo usuário. Ele se conecta a um serviço MinIO via interface REST, carrega o modelo e executa a predição. Comparado à solução no primeiro artigo, onde o modelo VARMAX é carregado e desserializado no início do aplicativo, o modelo VAR é lido do servidor MinIO cada vez que uma predição é acionada. Isso tem o custo de tempo adicional de carregamento e desserialização, mas também traz o benefício de ter a versão mais recente do modelo implantado em cada execução. Além disso, isso permite a versão dinâmica de modelos, tornando-os automaticamente acessíveis a sistemas externos e usuários finais, como será mostrado mais adiante no artigo. Observe que devido a esse overhead de carregamento, o desempenho do serviço de armazenamento selecionado é de grande importância.

Mas por que MinIO e armazenamento baseado em objetos em geral?

O MinIO é uma solução de armazenamento de objetos de alta performance com suporte nativo para implantações em Kubernetes, que oferece uma API compatível com o Amazon Web Services S3 e suporta todos os recursos principais do S3. No projeto apresentado, o MinIO está em Modo Standalone, composto por um único servidor MinIO e um único disco ou volume de armazenamento no Linux usando Docker Compose. Para ambientes de desenvolvimento ou produção estendidos, há a opção de modo distribuído descrita no artigo Implantar MinIO em Modo Distribuído.

Vamos dar uma olhada rápida em algumas alternativas de armazenamento, enquanto uma descrição abrangente pode ser encontrada aqui e aqui:

  • Armazenamento de arquivos local/distribuído: O armazenamento de arquivos local é a solução implementada no primeiro artigo, pois é a opção mais simples. Computação e armazenamento estão no mesmo sistema. É aceitável durante a fase de PoC ou para modelos muito simples que suportam uma única versão do modelo. Os sistemas de arquivos locais têm capacidade de armazenamento limitada e não são adequados para conjuntos de dados maiores, caso queiramos armazenar metadados adicionais, como o conjunto de dados de treinamento utilizado. Como não há replicação ou autoscaling, um sistema de arquivos local não pode operar de forma disponível, confiável e escalável. Cada serviço implantado para escalonamento horizontal é implantado com sua própria cópia do modelo. Além disso, o armazenamento local é tão seguro quanto o sistema hospedeiro. Alternativas ao armazenamento de arquivos local são NAS (Network-attached storage), SAN (Storage-area network), sistemas de arquivos distribuídos (Hadoop Distributed File System (HDFS), Google File System (GFS), Amazon Elastic File System (EFS) e Azure Files). Em comparação com o sistema de arquivos local, essas soluções são caracterizadas por disponibilidade, escalabilidade e resiliência, mas vêm com o custo de maior complexidade.
  • Bancos de dados relacionais: Devido à serialização binária de modelos, bancos de dados relacionais oferecem a opção de armazenamento blob ou binário de modelos em colunas de tabelas. Desenvolvedores de software e muitos cientistas de dados estão familiarizados com bancos de dados relacionais, o que torna essa solução direta. Versões de modelos podem ser armazenadas como linhas de tabela separadas com metadados adicionais, que também são fáceis de ler do banco de dados. Uma desvantagem é que o banco de dados exigirá mais espaço de armazenamento, o que afetará os backups. Ter grandes quantidades de dados binários em um banco de dados também pode afetar o desempenho. Além disso, bancos de dados relacionais impõem algumas restrições às estruturas de dados, o que pode complicar o armazenamento de dados heterogêneos como arquivos CSV, imagens e arquivos JSON como metadados do modelo.
  • Armazenamento de objetos: O armazenamento de objetos existe há algum tempo, mas foi revolucionado quando a Amazon o transformou no primeiro serviço da AWS em 2006 com o Simple Storage Service (S3). O armazenamento de objetos moderno é nativo da nuvem, e outras nuvens logo ofereceram seus próprios produtos no mercado. A Microsoft oferece o Azure Blob Storage, e o Google tem o serviço Google Cloud Storage. A API do S3 é o padrão de facto para os desenvolvedores interagirem com o armazenamento na nuvem, e há várias empresas que oferecem armazenamento compatível com o S3 para a nuvem pública, nuvem privada e soluções on-premises privadas. Independentemente de onde um repositório de objetos está localizado, ele é acessado por meio de uma interface RESTful. Embora o armazenamento de objetos elimine a necessidade de diretórios, pastas e outras organizações hierárquicas complexas, não é uma boa solução para dados dinâmicos que estão constantemente mudando, pois será necessário reescrever todo o objeto para modificá-lo, mas é uma boa opção para armazenar modelos serializados e os metadados do modelo.

A summary of the main benefits of object storage are:

  • Escalabilidade massiva: O tamanho do armazenamento de objetos é essencialmente ilimitado, então os dados podem escalar para exabytes simplesmente adicionando novos dispositivos. As soluções de armazenamento de objetos também executam melhor quando operam como um cluster distribuído.

  • Redução da complexidade: Os dados são armazenados em uma estrutura plana. A falta de árvores ou partições complexas (sem pastas ou diretórios) reduz a complexidade de recuperar arquivos, pois não é necessário saber a localização exata.
  • Busca: O metadado faz parte dos objetos, facilitando a busca e navegação sem a necessidade de um aplicativo separado. Pode-se etiquetar objetos com atributos e informações, como consumo, custo e políticas de exclusão automática, retenção e classificação. Devido ao espaço de endereçamento plano do armazenamento subjacente (cada objeto em apenas um bucket e nenhum bucket dentro de outro bucket), os repositórios de objetos podem encontrar um objeto entre bilhões de objetos rapidamente. 
  • Resiliência: O armazenamento de objetos pode replicar automaticamente os dados e armazená-los em vários dispositivos e localizações geográficas. Isso pode ajudar a proteger contra interrupções, garantir contra perda de dados e ajudar a apoiar estratégias de recuperação de desastres. 
  • Simplicidade: O uso de uma API REST para armazenar e recuperar modelos implica quase nenhuma curva de aprendizado e torna a integração em arquiteturas baseadas em microsserviços uma escolha natural. 

É hora de analisar a implementação do modelo VAR como um serviço e a integração com o MinIO. O部署 da solução apresentada é simplificado usando Docker e Docker Compose. A organização de todo o projeto é a seguinte:

Assim como no primeiro artigo, a preparação do modelo envolve alguns passos que estão escritos em um script Python chamado var_model.py , localizado em um repositório dedicado GitHub :

  • Carregar dados
  • Dividir dados em conjunto de treinamento e teste 
  • Preparar variáveis endógenas
  • Encontrar parâmetro de modelo ótimo p (primeiros p lags de cada variável usados como preditores de regressão) 
  • Instanciar o modelo com os parâmetros ótimos identificados
  • Serializar o modelo instanciado em um arquivo pickle
  • Armazenar o arquivo pickle como um objeto versionado em um bucket MinIO

Esses passos também podem ser implementados como tarefas em um mecanismo de fluxo de trabalho (por exemplo, Apache Airflow), acionado pela necessidade de treinar uma nova versão do modelo com dados mais recentes. DAGs e suas aplicações em MLOps serão o foco de outro artigo.

O último passo implementado em var_model.py é armazenar o modelo serializado como um arquivo pickle em um bucket no S3. Devido à estrutura plana do armazenamento de objetos, o formato selecionado é: 

<nome do bucket>/<nome do arquivo>

No entanto, para nomes de arquivos, é permitido usar uma barra para simular uma estrutura hierárquica, mantendo a vantagem de uma pesquisa linear rápida. A convenção para armazenar modelos VAR é a seguinte:

models/var/0_0_1/model.pkl

Onde o nome do bucket é models, e o nome do arquivo é var/0_0_1/model.pkl e no MinIO UI, é assim:

Esta é uma maneira muito conveniente de estruturar vários tipos de modelos e versões de modelos, mantendo ainda o desempenho e a simplicidade do armazenamento de arquivos planos. 

Note que a versão do modelo é implementada como parte do nome do modelo. MinIO também fornece a versão de arquivos, mas a abordagem selecionada aqui tem algumas vantagens:

  • Suporte de versões de instantâneo e substituição
  • Uso de versionamento semântico (pontos substituídos por ‘_’ devido a restrições)
  • Maior controle da estratégia de versionamento
  • Desacoplamento do mecanismo de armazenamento subjacente em termos de recursos específicos de versionamento

Uma vez que o modelo é implantado, é hora de expô-lo como um serviço REST usando Flask e implantá-lo usando docker-compose executando MinIO e um servidor Web Apache. A imagem Docker, bem como o código do modelo, podem ser encontrados em um repositório dedicado GitHub.

E finalmente, os passos necessários para executar o aplicativo são:

  1. Implantar aplicativo: docker-compose up -d
  2. Execute o algoritmo de preparação do modelo:  python var_model.py (requer um serviço MinIO em execução)
  3. Verifique se o modelo foi implantado: http://127.0.0.1:9101/browser
  4. Teste o modelo: http://127.0.0.1:80/apidocs

Após implantar o projeto, o Swagger API está acessível via <host>:<port>/apidocs (por exemplo, 127.0.0.1:80/apidocs). Há um ponto de extremidade para o modelo VAR ilustrado ao lado dos outros dois expondo um modelo VARMAX:

Internamente, o serviço utiliza o arquivo pickle do modelo deserializado carregado a partir de um serviço MinIO:

As requisições são enviadas ao modelo inicializado da seguinte forma:

O projeto apresentado é um fluxo de trabalho de modelo VAR simplificado que pode ser estendido passo a passo com funcionalidades adicionais como:

  • Explore formatos de serialização padrão e substitua o pickle por uma solução alternativa
  • Integre ferramentas de visualização de séries temporais como Kibana ou Apache Superset
  • Armazene dados de séries temporais em um banco de dados de séries temporais como Prometheus, TimescaleDB, InfluxDB, ou em um armazenamento de objetos como S3
  • Amplie o pipeline com etapas de carregamento e pré-processamento de dados
  • Incorpore relatórios de métricas como parte dos pipelines
  • Implemente pipelines usando ferramentas específicas como Apache Airflow ou AWS Step Functions ou ferramentas mais padrão como Gitlab ou GitHub
  • Comparar o desempenho e a precisão de modelos estatísticos com modelos de aprendizado de máquina
  • Implementar soluções integradas em nuvem end-to-end, incluindo Infraestrutura como Código
  • Expor outros modelos estatísticos e de ML como serviços
  • Implementar uma API de Armazenamento de Modelos que abstrai o mecanismo de armazenamento real e a versão do modelo, armazena metadados do modelo e dados de treinamento

Essas melhorias futuras serão o foco de artigos e projetos futuros. O objetivo deste artigo é integrar uma API de armazenamento compatível com S3 e permitir o armazenamento de modelos versionados. Essa funcionalidade será extraída em uma biblioteca separada em breve. A solução de infraestrutura end-to-end apresentada pode ser implantada em produção e melhorada como parte de um processo de CI/CD ao longo do tempo, também usando as opções de implantação distribuída do MinIO ou substituindo-o pelo AWS S3.

Source:
https://dzone.com/articles/time-series-analysis-var-model-as-a-service