Deploy de um modelo de Análise de Sentimentos como uma REST API
Esse é o segundo de uma série de dois posts que irão mostrar como ajustar o BERT para realizar análise de sentimentos em portguês e colocar a solução em produção a partir da criação de uma API (FastAPI + Uvicorn + Docker).
O objetivo desse artigo é produtizar o modelo treinado como uma REST API e construir um sistema em que backend e frontend se comunicam em tempo real, gerando resultados como o mostrado a seguir:
Antes de entrar na construção da solução, é importante garantir o entendimento de alguns conceitos.
API e REST API
De forma simplificada, uma API (Application Programming Interface) é um conjunto de definições e protocolos para construir e integrar aplicações. Em uma analogia simples, pode-se dizer que uma API é um contrato entre um fornecedor e um consumidor de informações. A Figura 1 mostra um exemplo de comunicação envolvendo uma API.
APIs são mediadores entre sistemas e requisições podem ser feitas através de comandos como o CURL ou softwares como Postman e REST Client.
Uma das APIs mais famosas atualmente é a do Github, a seguir, um exemplo de request e response feitos via terminal.
Request:
curl https://api.github.com/users/hugozanini
Response:
Falando agora de REST. Essa é uma abreviação para Representational State Transfer (Transferência de Estado Representaconal)- trata-se de uma representação de dados em formatos que são convenientes para quem está solicitando (cliente). Algo que gera muita confusão, e que é importante destacar, é que o REST não é um protocolo, mas uma abordagem, ou estilo arquitetural, para escrever uma API.
Além do REST, é comum ouvir o conceito de RESTful API. Como o REST é um estilo arquitetural, o RESTful é a interpretação disso. Ou seja, se um servidor backend possui uma REST API e o cliente (aplicação web) faz uma requisição a essa API, então o cliente é RESTful.
Nesse tutorial, será construída uma REST API para retornar as inferências do modelo de Análise de Sentimentos construído no post anterior e uma aplicação web (cliente) para enviar as requisições (frases) definidas pelo usuário.
Construindo a aplicação
Tão importante quanto construir e treinar um modelo de Machine Learning, é colocá-lo em produção e disponibilizá-lo para os clientes. Atualmente, existem aplicações focadas exclusivamente em gerenciar todo o ciclo de vida de um modelo, como o MLflow. No entanto, essas soluções de “prateleira” ainda apresentam limitações e em muitas casos não conseguem llidar com um alto número de requisições e processamentos distribuidos.
Portanto, o que é mostrado na Figura 2, e que será construído aqui, é um projeto usando soluções open-source e focadas em escala. No lado do cliente, será desenvolvido um sistema web utilizando html e javascript e a estrutura de serving do modelo será baseada nas seguintes tecnologias.
- FastAPI: Framework para desenvolver REST APIs em python
- Uvicorn: Servidor que permite programação assíncrona em Python
- Pydantic: Biblioteca para análise e validação de dados
- Docker Compose: Ferramenta para rodar e sincronizar vários multiserviços
A seguir, serão detalhadas todas as etapas para a construção do projeto. Caso você queira ir direto para o repositório com os códigos, clique aqui.
Construindo a API
Todo o código da API será desenvolvido em python. A lista com as bibliotecas necessárias encotram-se no arquivo requirements.txt do repositório do projeto e podem ser instaladas a partir do seguinte comando:
pip install -r requirements.txt
Crie a seguinte estrutura para dar inicio ao projeto. Na pasta assets
, adicione o pesos treinados e salvos no artigo anterior.
O primeiro passo é a importação dos código que foram utilizados no tutorial anterior para o processo de inferência do modelo. Os trechos de código a seguir, devem estar presentes em model.py
e sentiment_classifier.py
respectivamente para facilitar a organização e modularização do processo de inferência.
A única novidade destes códigos e a etapa de carregamento das configurações do modelo a partir do arquivo config.json
. Ele contém as informações necessárias para a inicialização dos pesos treinados na etapa anterior e deve ser populado da seguinte maneira:
Feito isso, é necessário construir o script api.py
. Nele, estará toda a estrutura da API.
Como citado anteriormente, a utilização da FastAPI facilita muito o trabalho de desenvolvimento e criação das rotas de resposta às solicitações do cliente. A partir da utilização do Framework de Dependency Injection, é possível criar estruturas padronizadas e limpas.
Na linha 28 é definido o formato de resposta a solicitação de /predict
, ela segue o estrutura definida na classe SentimentResponse
e vai retornar sempre a probabilidade das predições, o sentimento com maior probabilidade e a confiança da resposta. Como o exemplo a seguir:
Na linha 29, a função predict
define que é necessário enviar uma string com a frase em que se deseja analisar o sentimento e que a predição será feita a partir do método predict
da classe Model
presente no script model.py
.
Para testar o código construído, é necessário criar um script bash em start_server
com os comandos necessários para baixar um modelo pré-treinado, caso o usuário não tenha colocado os seus pesos, e utilizar o uvicorn
para subir um servidor HTTP:
Ao executar o script, a seguinte tela deve ser exibida:
Ao enviar uma informação para o url em que a solução ficou disponível, provavelmente http://localhost:8000/, o seguinte formato de resposta é esperado:
Se tudo ocorreu bem, é hora de criar um contâiner linux para “empacotar” todos os códigos, dependencias e garantir que os comandos necessários para a execução da API serão executados corretamente. O arquivo Dockerfile
deve conter as seguintes informações:
Feito isso, é hora de iniciar a construção da aplicação web.
Pensando no lado do cliente
Agora que a API já está disponível e exposta em um url, é hora de trabalhar na construção da aplicação web (comumente chamada de cliente). A ideia é que seja algo simples e que o foco esteja em entender como solicitar e receber os dados em javascript.
Para isso, clone o branch web
do repositório do projeto a partir do seguinte comando:
git clone -b web
https://github.com/hugozanini/sentiment-analysis.git
A seguinte estrutura de projeto precisa estar disponível:
├─ sentiment-analysis-web
│ ├─ .dockerignore
│ ├─ Dockerfile
│ ├─ package-lock.json
│ ├─ package.json
│ ├─ public
│ │ ├─ assets
│ │ │ ├─ blank.png
│ │ │ ├─ negative.png
│ │ │ ├─ neutral.png
│ │ │ └─ positive.png
│ │ └─ index.html
│ └─ src
│ ├─ index.js
│ └─ style.scss
O arquivo index.html
é reponságithub do projeto.
ou novos exercícios através dovel pela construção de uma página web simples em que o usuário pode escrever uma frase para ser analisada. O componente tem o nome user_input
e a entrada será usada no código em javascript.
Ao abrir o arquivo em um navegador web, é esperada a saída mostrada na Figura 5.
As requisições na API serão feitas no arquivo index.js
, que possui a estrutura mostrada a seguir.
Todas as vezes que o usuário colocar uma frase no campo phrase
e clicar no botão submit
, a função process_input
(linha 24) será chamada e as funções update_plot
(linha 30) e update_image
(linha 24), serão responsáveis por atualizar as saídas para o usuário e produzir resultados como o a seguir:
Para finalizar esta etapa, basta construir um contâiner para rodar a aplicação. Os seguintes comandos devem estar dentro do arquivo Dockerfile
.
Subindo os microserviços
Ao criar dois contâiners diferentes, a ideia foi deixar as soluções o mais independentes possíveis e operando como microserviços. Agora, é necessário orquestrar os serviços para que eles se comuniquem e sejam executados da forma adequada.
Os Dockerfiles criados anteriormente vão ser utilizados para este trabalho e serão orquestrados a partir de uma ferramenta chamada Docker Compose. Ela permite configurar como cada aplicação será inicializada e subir toda a arquitetura de uma vez só.
Suba um nível na hierarquia de pastas do projeto e crie o arquivo docker-compose.yml
, como mostrado a seguir.
├─ sentiment-analysis-web
├─ sentiment-analysis-api
└─ docker-compose.yml
O script irá construir a infraestrutura necessária e realizará os links entre a API e o sistema web.
Suba os containers com o comando sudo docker-compose up
e as seguintes informações serão mostradas:
Se tudo ocorreu como o esperado, ao abrir http://localhost:8000/, a seguinte tela deve ser exibida:
Caso você tenha se interessado pelo assunto, sinta-se a vontade para contribuir com ajustes e melhorias atráves do github do projeto. Se ficou alguma dúvida, deixe aqui nos comentários ou me chame no Linkedin :)
Referências
[0] Vaswani, Ashish, et al. “Attention is all you need.” arXiv preprint arXiv:1706.03762 (2017).
[1] Devlin, Jacob, et al. “Bert: Pre-training of deep bidirectional transformers for language understanding.” arXiv preprint arXiv:1810.04805 (2018).
[2] Valkov, Venelin. “Bert for Sentiment Analysis using Pytorch, Transformers by Hugging Face and FASTAPI.” March 1, 2020.
[3] “FastAPI Documentation .” FASTAPI. Accessed November 1, 2021. https://fastapi.tiangolo.com/.