O blog da AWS

Dimensionamento de aplicativos de reconhecimento de imagem com o Amazon Rekognition

Por Gabriel Paredes, Arquiteto de Soluções da Amazon Web Services para o Setor Público

 

Diante das medidas de controle do COVID-19 emitidas por vários governos em todo o mundo, a oportunidade de implementar aplicativos alavancados pela Inteligência Artificial e pelo Reconhecimento de Imagem aumentou os casos de uso de suporte, como Proctoring Virtual (Educação), Contagem de Pessoas, Processo Autenticação não presencial com reconhecimento facial, digitalização de documentos (RG, carteira de motorista), entre outros.

A AWS oferece o conjunto mais amplo e detalhado de serviços de Machine Learning e infraestrutura em nuvem, colocando-os nas mãos de desenvolvedores, cientistas de dados e profissionais especializados. Nomeada líder em serviços de nuvem de Inteligência Artificial para desenvolvedores de acordo com o Gartner. Dentro desse conjunto de serviços estão os serviços de Machine Learning, Frameworks for Deep Learning e Serviços de Inteligência Artificial. Com serviços de Inteligência Artificial pré-treinados, é possível adicionar facilmente inteligência a aplicativos e fluxos de trabalho sem a necessidade de experiência prévia com Machine Learning.

O Amazon Rekognition, como parte dos serviços de Inteligência Artificial da AWS, facilita a inclusão de análise de imagem e vídeo em seus aplicativos, utilizando tecnologia comprovada, escalável e de aprendizagem profunda (Deep Learning), que não requer experiência prévia com Machine Learning para utilizá-la. Com o Amazon Rekognition, podemos identificar objetos, pessoas, texto, cenas e atividades em imagens e vídeos, e detectar qualquer conteúdo inapropriado. O Amazon Rekognition também permite análise facial de alta precisão e recursos de pesquisa que você pode usar para detectar, analisar e comparar rostos.

Uma das bases do pilar de Confiabilidade do nosso Well Architected Framework é planejar e gerenciar Cotas de Serviço ou Limites de Serviço. Elas existem com o objetivo de impedir que mais recursos além do necessário sejam provisionados, controlar o número de solicitações à uma API específica e proteger os serviços contra abuso ou uso indevido. No caso do Amazon Rekognition, as cotas de serviço são focadas principalmente no número de transações por segundo (TPS) que podem ser solicitadas de diferentes APIs, como CompareFaces, DetectFaces, DetectLabels, entre outras. Também é importante observar que esta atribuição é feita por Região e por Conta, e os valores podem variar dependendo da região que você deseja usar (https://docs.aws.amazon.com/general/latest/gr/rekognition_region.html).

O objetivo deste artigo é realizar uma revisão detalhada de estratégias em uma solução para incorporar o uso uso da API do Amazon Rekognition (especificamente DetectFaces) em aplicativos de alta demanda, que exigem cota de serviço temporária para evitar erros do lado do aplicativo.

 

Solução planejada

Figura 1: Processando arquitetura intensiva com o Amazon Rekognition

 

A Figura 1 ilustra uma arquitetura que permitirá dimensionar chamadas para a API do Amazon Rekognition. Em uma primeira instância, o aplicativo pode carregar a imagem em um bucket do Amazon S3 para o qual a análise é necessária, aplicando o recurso DetectLabels (identifica entidades reais, como flores, carrinhos, árvores, festas, entre outros.) ou DetectFaces (identifica atributos de até 100 faces dentro de uma imagem). Para cada imagem enviada para o bucket, um evento de notificação S3 será gerado e direcionado para uma fila do AWS SQS (chamaremos essa fila Process_Queue), que corresponde à descrição do evento PutItem com as informações necessárias, para que em seguida se processe a imagem.

Depois disso, para cada nova mensagem que entra no Process_Queue (SQS), um evento do AWS Lambda será disparado com as informações contidas na mensagem original do evento Image Load Bucket. Esta função Lambda contém o código necessário para lidar com as requisições do endpoint do Amazon Rekognition, bem como o tratamento de erros e tentativas de reprocessamento (retry). Isso será detalhado na seção Usando novas tentativas com retrocesso exponencial + Jitter. Nesse ponto, há duas variáveis que permitem regular o número de chamadas da API do Amazon Rekognition sem exceder a cota de serviço atribuída. A primeira, usando a propriedade BatchSize que indica quantas mensagens na fila podem ser enviadas em um único evento do AWS Lambda (esse valor está em uma escala de 1 a 10). A segunda, é por meio de simultaneidade reservada, com a qual você controla o número máximo de chamadas simultâneas de uma função lambda. Com o produto dessas duas variáveis você pode ajustar a quantidade de TPS que será chamada para a API do Amazon Rekognition. Para simplificar a solução, consideramos usar um BatchSize de 1 e aproximamos a quantidade de TPS com a quantidade de simultaneidade reservada.

 

{ "FaceDetails": [ { "BoundingBox": { "Width": 0.20062141120433807, "Height": 
0.40441733598709106, "Left": 0.15825751423835754, "Top": 0.1316724270582199 }, 
"AgeRange": { "Low": 21, "High": 33 }, "Smile": { "Value": true, "Confidence": 
92.25345611572266 }, "Eyeglasses": { "Value": true, "Confidence": 
99.9189682006836 }, "Sunglasses": { "Value": true, "Confidence":
99.63880157470703 }, "Gender": { "Value": "Female", "Confidence":
99.3447036743164 }, "Beard": { "Value": false, "Confidence": 99.50582122802734
}, "Mustache": { "Value": false, "Confidence": 99.86498260498047 }, "EyesOpen": 
{ "Value": true, "Confidence": 99.99996948242188 }, "MouthOpen": { "Value": 
true, "Confidence": 99.09195709228516 }, "Emotions": [ { "Type": "HAPPY", 
"Confidence": 97.60749053955078 }, { "Type": "SURPRISED", "Confidence": 
0.7658454179763794 }, { "Type": "CONFUSED", "Confidence": 0.5557805895805359 }, 
{ "Type": "ANGRY", "Confidence": 0.3515093922615051 }, { "Type": "DISGUSTED", 
"Confidence": 0.34102049469947815 }, { "Type": "CALM", "Confidence": 
0.19356855750083923 }, { "Type": "FEAR", "Confidence": 0.13799777626991272 },
{ "Type": "SAD", "Confidence": 0.046782251447439194 } ],…

Exemplo 1: Extração de resposta da API do Amazon Rekognition DetectFaces

 

O exemplo 1 corresponde à resposta de uma requisição bem-sucedida da API do Amazon Rekognition DetectFaces, com a propriedade de DetectLabels= “ALL”. Este está em formato JSON e tem vários campos que permitem identificar atributos dos rostos presentes na imagem, como emoções, posição ocular, boca, nariz, gênero, acessórios, entre outros. Todos eles podem ser usados por consumidores para análise avançada. Neste link você encontrará uma lista de todas as tags que podem ser reconhecidas com esta chamada de API. Essa resposta é enviada pela função lambda como uma mensagem para uma segunda fila SQS chamada Response_Queue, que visa manter a mensagem temporariamente até que ela seja consumida por algum processo.

Para a finalidade da solução proposta, o próximo passo é gerar um evento de invocação do AWS Lambda para cada mensagem recebida no Response_Queue e, em seguida, guardar os resultados em uma tabela do Amazon DynamoDB, utilizando uma operação PutItem (isso será pelo aplicativo que carregou a imagem no bucket do S3). Esta parte final da arquitetura proposta pode variar de acordo com o caso de uso ou o sistema downstream que você deseja integrar para executar a análise da resposta Rekognition. Fazer essa alteração envolve apenas alterar o consumidor da fila Response_Queue para o processo ou aplicativo necessário, sem afetar nenhum dos componentes acima.

 

Usando Repetições com Recuo Exponencial + Jitter

Quando um aplicativo consome qualquer tipo de serviço por meio de chamadas de API, é muito importante implementar estratégias de manipulação de erros e tentativas de reprocessamento. Primeiro, usando novas tentativas, você pode lidar com situações de tempo limite (timeout) ou erros transitórios na API que você está utilizando. Desta forma, em caso de erro, o código reenvia a solicitação novamente até um número máximo de vezes. No entanto, essa técnica é um pouco “egoísta” da perspectiva do servidor, já que o código simplesmente usará mais recursos do servidor para obter uma maior chance de sucesso. Isso não apresenta um problema para falhas transitórias, no entanto, quando falha no lado do servidor é devido a uma sobrecarga de solicitação, a carga simplesmente estará aumentando, potencializando o problema.

Do some sync/async operation.

retries = 0

WHILE (retry AND (retries < MAX_RETRIES))

    wait for (100 * 2^retries) milliseconds + random(0, 1000) milliseconds

    status = Get the result of the asynchronous operation.

    IF status = SUCCESS
        retry = false
    ELSE IF status = NOT_READY
        retry = true
    ELSE IF status = THROTTLED
        retry = true
    ELSE
        Some other error occurred, so stop calling the API.
        retry = false
    END IF

    retries = retries + 1

Exemplo 2: Pseudocódigo de uma implementação de novas tentativas com recuo exponencial + Jitter

 

É por isso que é aconselhável incluir, além das novas tentativas, um algoritmo de retrocesso exponencial. Ao invés de tentar novamente assim que o erro for detectado, um curto período de espera é adicionado no código do aplicativo que levará uma progressão exponencial para um tempo máximo, ou condição de repetição máxima. Isso garante que tentativas sucessivas sejam feitas no espaçamento de tempo, onde quanto maior o número de tentativas, mais tempo você terá que esperar para fazer uma solicitação. Parcialmente corrigido o problema, as condições de sobrecarga devem agora ser levadas em consideração, uma vez que um grupo de solicitações que falharam em um T1 será executado novamente em um T1 + 1. Isso inclui a terceira técnica de Jitter, que consiste em adicionar um valor aleatório ao tempo limite calculado, minimizando o número de colisões em novas tentativas.

Para o Amazon Rekognition, a documentação indica os tipos de erros que podem ser encontrados e como lidar com eles. ThrottlingException e ProvisionedThrough Through CeedException são dois candidatos a aplicar as técnicas descritas nesta seção, à medida que os limites das Cotas de Serviço atribuídos são atingidos. Um exemplo dessa implementação está disponível neste link.

Nos links a seguir, você encontrará dois artigos com uma explicação mais detalhada desses tópicos:

 

Implantação

Essa solução foi criada usando o AWS Cloud Development Kit (AWS CDK), para ser implantado em uma conta da AWS. Você pode usá-lo baixando o código neste repositório. Posteriormente, siga estas etapas:

Pré-requisitos

Para implantar essa solução, você precisa ter os seguintes pré-requisitos:

Configurando seu projeto com o AWS CDK

1. Clonar o código deste repositório — https://github.com/aws-samples/amazon-rekognition-large-scale-processing

2. Executar os seguintes comandos no terminal

$ npm install -g aws-cdk
$ cd amazon-rekognition-large-scale-processing
$ python3 -m venv .env
$ source .env/bin/activate
$ pip install -r requirements.txt
$ cdk deploy

3. Validación del despliegue: como resultado del paso anterior se observará en consola el nombre del bucket de Amazon S3 donde se pueden empezar a cargar las imágenes, los resultados serán registrados en la tabla de AWS DynamoDB detect_faces_results

Pruebas de carga

Para probar la escalabilidad, confiabilidad y estabilidad de la solución, se tomo un subconjunto de 30.000 imágenes del Flickr-Faces-HQ Dataset (FFHQ). Este contiene 70.000 imágenes de rostros humanos de alta calidad y resolución y es comúnmente utilizado para realizar benchmarks de generative adversarial networks (GAN). Se hicieron tres pruebas así: carga paralela de una aplicación a 25 imágenes/segundo, 50 imágenes/segundo y 100 imágenes/segundo. A continuación, veremos el comportamiento para cada uno de los escenarios y cual es el comportamiento de cada capa de la arquitectura bajo las siguientes premisas:

  • Service Quota de Amazon Rekognition de 50TPS para el API de DetectFaces
  • AWS Lambda con un Reserved Concurrency de 50 invocaciones

Simulación 1: @ 25TPS

 

Imagem 1: CloudWatch: S3/sqs/lambda @ 25TPS

 

Imagem 2: CloudWatch: Rekognition @ 25TPS

 

As 30.000 imagens foram processadas em 20 minutos. Conforme detalhado nas imagens 1 e 2, para cada evento PutObject no bucket de imagem S3, uma mensagem é gerada para o Process_Queue, pois a API é consumida em uma velocidade menor que a Cota de Serviço e Reservada Simultância das funções do Lambda. Cada mensagem que entra na fila é processada imediatamente, não aumentando o número de mensagens visíveis no Process_Queue. Além disso, há uma aproximação grande na quantidade de imagens recebidas e processadas pelo Amazon Rekognition.

Simulação 2: @ 50TPS

Imagem 3: CloudWatch: S3/sqs/Lambda @ 50TPS

 

Imagem 4: CloudWatch: Rekognition @ 50TPS

 

Desta vez, a mesma quantidade de imagens foi processada em 10 minutos, fazendo uso total da capacidade de cota do Amazon Rekognition Service. 90% das mensagens são processadas imediatamente na fila e apenas algumas mensagens são visíveis na fila de processamento. Nesta ocasião, eles começam a aumentar o valor dos ThrottleCounts e, em alguns casos, dos ServerErrorCount (Figura 4). O código da função lambda que envia as requisições para a API tem os mecanismos para lidar com esse tipo de evento usando Repetir, Recuo Exponencial + Jitter, para que todas as imagens sejam processadas com sucesso.

Simulação 3: @ 100TPS

 

Imagem 5: CloudWatch: S3/sqs/Lambda @ 100TPS

 

Imagem 6: CloudWatch: Rekognition @ 100TPS

 

Para finalizar, um teste foi realizado dobrando a capacidade alocada. Neste caso (Imagem 5), o carregamento da imagem termina em 5 minutos (Linha Violeta) e o processamento da imagem em 10 minutos (Linha Azul e Verde). Ainda na imagem 5, é possível ver  que as mensagens visíveis na fila aumentaram consideravelmente (Linha Verde), atingindo um limite de 15,6k mensagens. Entretanto, todas as solicitações são eventualmente processadas e evacuadas da fila a uma taxa estável e Consistente de 50TPS pelo Amazon Rekognition.

Limpeza

Para remover a solução implantada:

1. Execute os seguintes comandos no terminal

$cd amazon-rekognition-lgrande escala-processamento
$cdk destruir

2. Exclua a tabela do AWS DynamoDB:

2.1. Navegue no Console da AWS para o serviço do DynamoDB

2.2. Selecione a opção Tabelas, selecione a tabela detect_faces_results e exclua esta tabela.

3. Remover o bucket do Amazon S3:

3.1. Navegue no console da AWS até o serviço S3

3.2. Localize o bucket que foi criado durante a implantação da solução, e exclua este bucket.

 

Conclusão

Essa solução aproveita os recursos do Amazon Rekogniton para processamento de imagens na escala de dezenas de milhares de eventos, incorporando serviços como Amazon SQS e AWS Lambda com recursos BatchSize e de simultaneidade reservada, gerenciando assim o fluxo de requisições para a API DetectFaces. Além disso, graças à implementação de Retry e Exponential Backoff + Jitter, é possível controlar os momentos de congestionamento e erros que podem ocorrer no uso da API.

 

Este artigo foi traduzido do Blog da AWS em Espanhol.

 


Sobre el autor

Gabriel Paredes é arquiteto de soluções da Amazon Web Services para o setor público. Gabriel ajuda várias instituições educacionais na América Latina a adotar tecnologia e melhorar seus serviços estudantis.

 

 

 

 

Revisores técnicos

Cristian David Romero é arquiteto de soluções da Amazon Web Services para o setor público. Cristian ajuda várias instituições do setor público e privado a adotar a tecnologia de nuvem na América Latina.

 

 

 

 

Jhon Guzmán é arquiteto de soluções da Amazon Web Services para o setor público. A Jhon ajuda vários parceiros a adotar tecnologia e soluções de nuvem para seus clientes na América Latina.