WEB3DEV

Cover image for Crie um Classificador de Aprendizado de Máquina em Python e Implante-o com o AWS ECR, Lambda e API Gateway
Fatima Lima
Fatima Lima

Posted on

Crie um Classificador de Aprendizado de Máquina em Python e Implante-o com o AWS ECR, Lambda e API Gateway

Image description

Neste tutorial, você criará um aplicativo com as seguintes etapas:

  1. Criar e manter um classificador KNN com Python, NumPy e scikit-learn.
  2. Criar uma função de manipulador do Lambda do AWS que receba um rótulo e executar o modelo para retornar os 30 "vizinhos mais próximos"..
  3. Empacotar o manipulador lambda e o classificador armazenado como uma imagem do Docker.
  4. Criar um repositório no AWS Elastic Container Registry (ECR - registro de contêiner elástico do AWS) para manter a imagem.
  5. Implantar a imagem do ECR em uma função Lambda do AWS.
  6. Integrar o Lambda com uma API no Portal de API do AWS.
  7. Testar a API com o Postman e o CloudWatch do AWS.

Você criará uma nova conta do AWS como uma etapa de pré-requisito e nós faremos todas as configurações necessárias. Este aplicativo usa serviços do AWS nas categorias "Always Free" (Sempre gratuito) e "12 Months Free" (12 meses gratuitos). Portanto, certifique-se de remover todos os serviços obsoletos antes desse momento.

GitHub Reference Code

Pré-requisitos:

Estes comandos listados são para Linux (Ubuntu).

1.Python

mkdir pyai
cd pyai
Enter fullscreen mode Exit fullscreen mode

1.1 Configurar o Venv

O Venv é um módulo Python que permite a criação de ambientes isolados.

pip install virtualenv
Enter fullscreen mode Exit fullscreen mode

Crie um novo ambiente e dê a ele o nome do nosso projeto:

python3 -m venv pyai
Enter fullscreen mode Exit fullscreen mode

Ative o ambiente:

source ./pyai/bin/activate
Enter fullscreen mode Exit fullscreen mode

1.2 Classificador KNN

O classificador será treinado em um conjunto de dados de reconhecimento facial. Em última análise, ele irá expor um método que recebe o nome de uma celebridade como input e retorna uma lista de celebridades com rostos semelhantes de acordo com o aprendizado Nearest Neighbors (vizinhos próximos) e o conjunto de dados.

Isenção de responsabilidade: tento seguir as práticas recomendadas, mas não sou cientista de dados. O modelo Nearest Neighbors foi escolhido pela simplicidade e intuitividade, mas não é necessariamente um modelo ideal para a classificação de imagens.

1.2.0 Instale as dependências

pip install scikit-learn, Pillow
Enter fullscreen mode Exit fullscreen mode

1.2.1 Treinamento do módulo

Esse script será executado localmente para gerar os arquivos necessários para nosso aplicativo Dockerized.

touch train_model.py
Enter fullscreen mode Exit fullscreen mode

Adicione as seguintes importações:

from sklearn.datasets import fetch_lfw_people
from sklearn.neighbors import NearestNeighbors
import numpy as np
from joblib import dump
Enter fullscreen mode Exit fullscreen mode

Defina uma função que conterá o restante do código para esse arquivo:

def train_model():
 ...
Enter fullscreen mode Exit fullscreen mode

Obtenha o banco de dados codificado de características faciais:

face_data = fetch_lfw_people(min_faces_per_person=5)
Enter fullscreen mode Exit fullscreen mode

Separe o conjunto de características, os rótulos numéricos e os rótulos de texto:

X = face_data.data
labels = face_data.target # numeric labels corresponding to individuals
names = face_data.target_names # names corresponding to numeric labels
Enter fullscreen mode Exit fullscreen mode

O usuário fornece um nome de texto, que deve ser mapeado para um índice numérico para o modelo. O modelo emite índices numéricos que devem ser mapeados para nomes de texto para o usuário. Crie esses mapeamentos para uso posterior:

names_to_labels = {}
labels_to_names = {}

for index, names_idx in enumerate(labels):
 name = names[names_idx]
 if name in names_to_labels:
   names_to_labels[name].append(index)
 else:
   names_to_labels[name] = [index]

 labels_to_names[index] = names[labels[index]]
Enter fullscreen mode Exit fullscreen mode

Ajuste o modelo ao conjunto de características:

nn_model = NearestNeighbors(n_neighbors=15)
nn_model.fit(X, labels)
Enter fullscreen mode Exit fullscreen mode

Salve o modelo, a matriz de características e os objetos de mapeamento para uso posterior:

dump(nn_model, 'nn_model.joblib', compress=3)
np.save('feature_matrix.npy', X)
np.save('names_to_labels.npy', names_to_labels)
np.save('labels_to_names.npy', labels_to_names)

if __name__ == '__main__':
   train_model()
Enter fullscreen mode Exit fullscreen mode

1.2.2 Módulo de classificação

Esse é o módulo que o manipulador lambda chamará com o nome da entrada:

touch classifier.py
Enter fullscreen mode Exit fullscreen mode

Adicione as seguintes importações:

from joblib import load
import numpy as np
from collections import Counter
Enter fullscreen mode Exit fullscreen mode

Defina uma função que conterá o restante do código para esse arquivo:

def classify(input_name):
 ...
Enter fullscreen mode Exit fullscreen mode

Carregue os ativos que criamos ao executar o train_model.py localmente:

nn_model = load('nn_model.joblib')
X = np.load('feature_matrix.npy')
names_to_labels = np.load('names_to_labels.npy', allow_pickle=True).item()
labels_to_names = np.load('labels_to_names.npy', allow_pickle=True).item()

if input_name not in names_to_labels:
 print(f"{input_name} not found in dataset.")
 return []
Enter fullscreen mode Exit fullscreen mode

Obtenha as amostras da matriz de características correspondentes ao input_name:

name_record_indices = names_to_labels[input_name]
input_samples = X[name_record_indices]
Enter fullscreen mode Exit fullscreen mode

Obter os 15 vizinhos mais próximos para cada uma das amostras de entrada:

distances, indices = nn_model.kneighbors(input_samples, n_neighbors=15)
Enter fullscreen mode Exit fullscreen mode

Achate os resultados e crie tuplas de índice e distância:

index_distance_tuples = [(idx, dist) for dists, idxs in zip(distances, indices) for idx, dist in zip(idxs, dists)]
Enter fullscreen mode Exit fullscreen mode

Obtenha as 15 tuplas mais comuns:

counter = Counter(index_distance_tuples)
most_common_tuples = counter.most_common(15)
Enter fullscreen mode Exit fullscreen mode

Classifique as tuplas por distância e retorne os índices:

sorted_indices_by_distance = [idx for idx, _ in sorted(most_common_tuples, key=lambda x: x[1])]
Enter fullscreen mode Exit fullscreen mode

Obtenha os nomes correspondentes a esses índices::

nearest_neighbors_names = [labels_to_names[idx] for idx, _ in sorted_indices_by_distance]
Enter fullscreen mode Exit fullscreen mode

Retorna o array de nomes:

return nearest_neighbors_names

if __name__ == '__main__':
 classify('Angelina Jolie')
Enter fullscreen mode Exit fullscreen mode

Neste ponto, vale a pena executar o train_model.py e o classifier.py localmente com algumas declarações de impressão para verificar a saída.

1.3 Manipulador Lambda

Esta é a função que o Lambda do AWS invocará.

touch lambda_function.py
Enter fullscreen mode Exit fullscreen mode

Adicione o seguinte código:

import json
from classifier import classify

def lambda_handler(event, context):
   try:
       data = json.loads(event['body'])

       label = data['label'] if 'label' in data else ''

       results = classify(label)

       return json.dumps(results) if results else json.dumps([])
       except Exception as e:
       return str(e)
Enter fullscreen mode Exit fullscreen mode

Essa assinatura de função é definida pelo Lambda e deve ser respeitada.

Nossa API aceitará solicitações de POST com o rótulo incluído no corpo da solicitação.

Convertemos os resultados em uma string de caracteres JSON válida e a devolvemos ao Portal da API . O Portal de API é capaz de inferir o restante da estrutura de resposta com base em nosso tipo de retorno.

Informações Adicionais:

Handler format

2.Docker

Agora, empacotamos o aplicativo como uma imagem do Docker.

2.1 Crie um arquivo de requisitos usando o pip:

pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

2.2 Copie este Dockerfile na raiz do seu projeto:

FROM public.ecr.aws/lambda/python:3.11

COPY requirements.txt ${LAMBDA_TASK_ROOT}

COPY . ${LAMBDA_TASK_ROOT}

RUN pip install --no-cache-dir -r requirements.txt

CMD ["lambda_function.lambda_handler"]
Enter fullscreen mode Exit fullscreen mode

Usamos uma imagem ECR pública projetada especificamente para Python e configurada para Lambda.

Copiamos o arquivo de requisitos para o diretório raiz do Lambda no contêiner do Docker, assim como nossos outros arquivos.

Instalamos as dependências com base no arquivo requirements.txt no contêiner do Docker.

Por fim, definimos o comando padrão a ser executado quando o contêiner do Docker for executado.

2.3 Construa a imagem:

Nota: No Linux, talvez seja necessário, primeiro, adicionar seu usuário atual ao grupo do docker:

sudo usermod -aG docker ${USER}
Enter fullscreen mode Exit fullscreen mode

Informações adicionais: Gerencie o Docker como um usuário não raiz

Crie a imagem:

docker build -t pyai .
Enter fullscreen mode Exit fullscreen mode

2.4 Execute um contêiner a partir da imagem (apenas para teste):

docker run -p 9000:8080 pyai
Enter fullscreen mode Exit fullscreen mode

Informações adicionais:

Implante funções Lambda no Python com imagens de contêineres

3.Registro de Contêiner Elástico AWS (ECR)

O ECR manterá a imagem usada para nosso lambda.

3.1 Crie um Repositório ECR:

Navegue até o console do ECR AWS e clique em Create repository (Criar repositório).

Em Visibility settings (Configurações de visibilidade), mantenha a seleção Private (Privado).

Em Repository name entre com pyai.

Clique Create repository (Criar repositório).

Em sua lista de repositórios privados, você deverá ver pyai.

3.2 Envie a imagem local do Docker para o repositório ECR:

Selecione a caixa de seleção ao lado de pyai.

Clique em *View push commands *(visualizar comandos push).

Copie o comando em Retrieve an authentication token and authenticate your Docker client to your registry (Recupere um token de autenticação e autentique seu cliente Docker no seu registro). Cole-o em sua linha de comando e pressione Enter.

Copie o comando docker tag e execute-o.

Copie o comando docker push e execute-o.

Esse primeiro envio pode levar alguns minutos porque o Docker precisa enviar todas as camadas da imagem. Quando for concluído, você deverá ver o repositório pyai no console ECR.

4.Lambda AWS

Navegue até o console lambda AWS e clique em Create function (Criar função).

Selecione Container image (Imagem do contêiner).

Nome da função: pyai.

URI da imagem do contêiner: Clique em Browse images (imagens do navegador). Selecione o repositório: pyai. Em images, marque latest. Clique em Select image.

Observe, em Permissions: "Por padrão, o Lambda criará uma função de execução com permissões para carregar os registros no Amazon CloudWatch Logs. Você pode personalizar essa função padrão posteriormente ao adicionar gatilhos."

Expanda a função de execução padrão Change. Mantenha a seleção padrão Create a new role (Criar uma nova função) com permissões básicas do Lambda.

O LambdaECRImageRetrievalPolicy deve ser automaticamente criado para o repósitorio ECR pyai. Se não, siga essas instruções: Permissões ECR.

Na página da função pyai, clique em Configuration (Configuração) e depois em General configuration (Configuração geral).

Clique em Edit, e defina o Timeout para 30 seg. Em seguida, defina Memória para 1000 MB. Clique em S*ave*. Provavelmente, você só precisará de cerca de 400 MB de memória; sinta-se à vontade para reduzir a escala posteriormente com base nos registros do CloudWatch para o Lambda.

5.Portal API do AWS

Navegue até o console lambda do AWS e clique em Create API.

Em HTTP API, clique em Build.

Em Integrations, clique em Add integration e selecione Lambda e na função Lambda, clique em pyai function.

Nome da API: pyai.

Clique em Create.

Em Routes ele listará pyai e um link 'ANY'. Clique nele e, em seguida, em Route details (detalhes da rota), clique em Edit. Em vez de ANY, selecione POST. Clique em Save (Salvar).

Se você clicar em Integrations na barra lateral, deverá ver o Lambda AWS ao lado da nossa rota POST.

5.1 CORS

Clique em CORS e Configure.

Access-Control-Allow-Origin: entre http://localhost:3000.

Access-Control-Allow-Methods: selecione POST.

Access-Control-Allow-Headers: entre content-type.

Clique em Save.

5.2 CloudWatch do AWS

Em Monitor clique em Logging, selecione o estágio $default e clique em Select.

Clique em Edit, e alterne para Access logging.

Abra uma nova guia do navegador e navegue até a página do console CloudWatch do AWS.

Clique em Create log group.

Nome do grupo de registros: pyai.

Clique no grupo de registros recém-criado e, em seguida, copie seu ARN.

De volta ao console do Portal API, em Log destination, entre com o ARN.

Em Log format, clique em JSON.

Cole o seguinte JSON. Ele contém algumas das variáveis originais e algumas novas variáveis úteis relacionadas à integração:

{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength", "errorMessage": "$context.error.message", "integrationErrorMessage": "$context.integration.error", "integrationStatus": "$context.integration.integrationStatus" }
Enter fullscreen mode Exit fullscreen mode

Clique em Save.

Informações adicionais:

API Gateway & Lambda Integration

API Gateway & Lambda Request/Response Formats

6.Teste com Postman & CloudWatch

6.1 Postman

Do console do portal API do AWS, em Deploy, clique em Stages.

Em Stage details, copie o Invoke URL.

Execute o aplicativo Postman.

Para a nova solicitação, selecione POST.

No espaço URL digite Invoke URL.

No final do URL, adicione /pyai.

Abaixo do URL clique em Body.

Selecione raw.

Digite o seguinte:

{
  "label": "Angelina Jolie"
}
Enter fullscreen mode Exit fullscreen mode

Esse deve ser o nome de uma celebridade no banco de dados, ou o programa lançará uma exceção. Certifique-se de usar aspas duplas válidas.

Clique em Send.

Veja os nomes de celebridades retornados que nosso classificador simples acredita serem semelhantes à Angelina Jolie (seu nome deve ser o primeiro).

6.2 CloudWatch

Abra o console CloudWatch do AWS.

Clique em Log groups, depois pyai.

Em Log streams, veja os últimos eventos da API.

Verifique também o grupo de registros criado automaticamente para o Lambda em /aws/lambda/pyai. É aqui que você verá informações de depuração, como instruções de impressão do seu código Python.

Etapas da Reimplantação

Se você fizer alterações no aplicativo, siga estas etapas para reimplantar:

  1. Reconstrua a imagem do Docker localmente.
  2. Exclua a imagem antiga (não o repositório) do ECR do AWS para economizar espaço.
  3. Execute novamente os dois comandos push do ECR que usamos anteriormente.
  4. No console do Lambda AWS, em Image (Imagem), clique em Deploy new image (Implantar nova imagem) -> Browse Images (Procurar imagens) -> select the ECR repository (selecione o repositório ECR) -> marque a caixa com a tag de Imagem latest (Imagem mais recente) -> Save (Salvar).
  5. Limpe imagens e contêineres antigos do Docker usando o docker rmi e o docker prune.

Próximos Passos

Algumas direções possíveis para levar esse projeto adiante:

  • Adicione CI/CD com CodeBuild & CodePipeline do AWS.
  • Adicione seu próprio banco de dados com o RDS do AWS e conecte-se a ele a partir do aplicativo Python.
  • Crie um aplicativo de página única que interaja com a API.

Em linguagem simples

Obrigado por fazer parte de nossa comunidade! Antes de ir embora:

Esse artigo foi escrito por Mike Brinkman e traduzido por Fátima Lima. O original pode ser lido aqui.

Top comments (0)