Deploy de um modelo de Análise de Sentimentos como uma REST API

Hugo Zanini
Data Hackers
Published in
7 min readNov 3, 2021

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:

Animação 1: Exemplo do modelo em produção

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.

Figura 1: Exemplo de comunicações 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.

Figura 2: Estrutura do projeto

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.

tree_api.sh

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.

model.py
sentiment_classifier.py

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:

config.json

Feito isso, é necessário construir o script api.py. Nele, estará toda a estrutura da API.

api.py

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:

response_example.json

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:

Figura 3: Execução do Dockerfile da API

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:

Figura 4: Exemplo de resposta da API

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:

Dockerfile

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 webhttps://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.

index.html

Ao abrir o arquivo em um navegador web, é esperada a saída mostrada na Figura 5.

Figura 5: Página da aplicação web

As requisições na API serão feitas no arquivo index.js, que possui a estrutura mostrada a seguir.

index.js

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:

Figura 6: Exemplo de predição usando a interface web

Para finalizar esta etapa, basta construir um contâiner para rodar a aplicação. Os seguintes comandos devem estar dentro do arquivo Dockerfile.

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.

docker-compose.yml

Suba os containers com o comando sudo docker-compose up e as seguintes informações serão mostradas:

Figura 7: Subindo a arquitetura via docker-compose

Se tudo ocorreu como o esperado, ao abrir http://localhost:8000/, a seguinte tela deve ser exibida:

Figura 7: Fim do tutorial

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/.

--

--

Hugo Zanini
Data Hackers

GDE in Machine Learning| Electrical Engineer | Technical Product Manager