Machine Learning como uma Função Serverless no Google Cloud Platform

Serverless Machine Learning

João Paulo Martins
Data Hackers
10 min readMay 15, 2020

--

Photo by Kevin Ku on Unsplash

Introdução

Esse mês nos meus estudos de engenharia de machine learning tropecei em um tópico bem interessante: machine learning como funções serverless. Então, como se já não bastasse trabalhar umas 12 horas por dia (é sério), decidi construir uma pipeline BEM simples para o desenvolvimento de um modelo de regressão BEM básico e, em seguida, fazer o deploy deste modelo como uma função serveless na Google Cloud Platform. O resultado foi uma experiência bem interessante que me deu algum know how e um vislumbre de como poderia fazer o deploy de algo assim em produção com um sistema de maior escala. Talvez algum dia eu faça algo mais complexo envolvendo mais peças desse quebra cabeças.

Como sempre, espero que esse post possa dar uma luz para alguém fazendo algo parecido.

TL;DR: criei um modelo de machine learning e fiz o deploy como uma função serverless no GCP.

Objetivos do Post:

Suponhamos que você queira colocar seu apartamento para alugar, mas não sabe exatamente qual preço colocar no aluguel. Para isso você começa a procurar na internet por apartamentos mais ou menos igual ao seu na sua cidade e tenta tirar a média para gerar seu próprio valor de aluguel, cansativo, não?

Ia ser bem legal ter um modelo para tentar predizer o valor ideal para seu imóvel baseado em outros imóveis, né? Bem, é isso que vamos tentar fazer neste post.

  • Desenvolvimento de um modelo para predição de valor de aluguel baseado em características do apartamento;
  • Salvar o modelo treinado no Google Cloud Storage;
  • Deploy do modelo treinado no Google Cloud Functions;
  • Teste de funcionamento.

O que é uma Arquitetura Serverless?

Nos últimos anos, muito hype vem sendo criado em cima de arquiteturas serverless. Boa parte desse barulho é gerado por fornecedores de tais arquiteturas, onde principais são, obviamente: Google, Amazon e Microsoft, que investiram uma quantidade considerável de dinheiro nas suas plataformas serverless.

Ok, mas o que é uma arquitetura ou aplicação serverless? De acordo com o Martin Fowler, podemos dividir arquiteturas serverless em dois tipos: as BaaS (Backend as a Service) e as FaaS (Function as a Service). Em ambos os modelos, a parte de gerenciamento e arquitetura “server side” é toda tratada pelo provedor da plataforma, tirando essa responsabilidade do cliente. Arquiteturas serverless se beneficiam de uma redução de custo operacional, complexidade e necessidade de horas de engenharia. Para empresas com times reduzidos ou cientistas de dados ao estilo “faz tudo”, esse tipo de aplicação é de grande ajuda, já que boa parte do processo de deploy é abstraída pelo provedor do serviço.

Para este post, vamos focar em aplicações FaaS. Neste tipo de aplicação, simplesmente criaremos uma função principal (main method) e usaremos as máquinas do Google Cloud Platform para hospedá-la. Essa função pode ser escrita em diferentes linguagens, obviamente utilizei Python3. Uma vez que a função tenha sido criada, sua execução será feita mediante requisições externas, ou seja, on demand. A parte de escalabilidade e distribuição também fica por conta do google, o que é uma mão na roda e tanto.

Pipeline do Mini Projeto

Fluxograma da pipeline

Etapas para Desenvolvimento:

1 — EDA Básico com Pandas Profiling;

2 — Desenvolvimento e treinamento do modelo utilizando Scikit-Learn e Pandas;

3 — Upload do modelo salvo para um bucket no Google Cloud Storage;

4 — Desenvolvimento da API Flask para deploy no Google Cloud Function.

EDA Básico

Para criar nosso modelo de predição, vamos utilizar um dataset disponível no Kaggle com features de imóveis de algumas cidades brasileiras. Pelo o que pude perceber do dataset, o autor fez o scrapping das páginas do Quinto Andar para conseguir essas informações.

A primeira etapa de todo projeto de data science é fazer um EDA (Exploratory Data Analysis) do dataset com o qual se vai trabalhar. Muitas vezes esse tipo de análise é bem demorada, pois exige muita atenção. Por isso, hoje vamos utilizar uma ferramenta MUITO útil nessas análises iniciais o Pandas Profiling. Essa lib do Python gera um report bem detalhado sobre o dataset no qual é aplicada, ela nos ajuda a economizar bastante tempo.

A instalação da lib é bem simples em ambientes virtuais:

Leitura do dataset com pandas

O dataset conta com as seguintes features:

  • city: cidade em que o imóvel se encontra;
  • area: área total do imóvel (m2);
  • rooms: quantidade de quartos do imóvel;
  • bathroom: quantidade de banheiros;
  • parking spaces: vagas de estacionamento;
  • floor: andar do imóvel;
  • furniture: se o imóvel é mobilhado;
  • hoa (R$): valor do condomínio;
  • rent amount (R$): valor do alguel;
  • property tax (R$): IPTU;
  • fire insurance (R$): seguro contra incêndio;
  • total (R$): valor total do imóvel

A coluna total (R$) trata do somatário dos valores de condomínio, aluguel, IPTU e seguro contra incêndio. Como queremos predizer apenas o valor de aluguel (rent amount (R$)), então, a coluna de total irá enviesar a análise. Por isso vamos excluí-la.

Identificação de Anomalias

Vamos procurar alugueis muito mais caros que o normal, a regra será: Q3 + 3,5xIQR. Como Pandas Profiling nos acusou, nosso Q3 = 5000 e nosso IQR = 3750.

Outliers identificados

Bom, a maioria dos aluguéis absurdos estão em São Paulo (nenhuma novidade aí). Temos alguns valores que chegam a 45k/mês, porém, a área do imóvel é de 700 metros quadrados, 7 banheiros, 4 quartos e 8 vagas de estacionamento. Então, creio que esteja condizente. Como não temos informações relativas ao bairro do imóvel este tipo de análise fica um pouco complicada.

Porém, temos uma situação (id 2859) em que temos o aluguel e o valor de condomínio em 20k/mês, muito provavelmente é um erro. Vamos eliminar essa linha.

Dropando linha contra outlier

Tratamento de Missing Values

Na coluna de floor algumas linhas que não possuem valor foram tratadas como ‘-’, vamos substituir esses valores.

Substituindo valores

Separação de Dados

Separação entre dados de treino e teste

Construção do Modelo

Como vamos fazer o deploy do modelo como um único main method no Google Cloud Functions não é interessante para nós criarmos mais funções para tratamento de entradas do modelo. Para fazer esse pré processamento vamos utilizar algumas funções bem interessantes da biblioteca Scikit-Learn. A estratégia aqui é criar uma única pipeline que engloba tanto o modelo de regressão quanto as funções de pré processamento. Dessa forma podemos gerar tudo em um único arquivo .pkl, garantindo que toda a pipeline seja rodada da mesma forma, tanto para treinamento quanto para predição.

O nosso dataset é constituído tanto de dados numéricos quanto de dados categóricos, então, vamos construir duas pipelines diferentes e junta-las em uma única ao final. A primeira vai tratar os dados numéricos e a segunda os categóricos.

Para a pipeline numérica vamos apenas substituir os valores faltantes (nenhum até agora) pela mediana de todos os outros valores. Em seguida, vamos padronizar os inputs através do StandardScaler.

Já na pipeline categórica, vamos substituir os valores faltantes por uma string “missing_values” e em seguida vamos fazer o Hot Enconding das variáveis.

Para criar uma única função de pré processamento, vamos juntar as duas pipelines utilizando a função ColumnTransformer do Sklearn. Ela é útil para ser utlizada em datasets heterogêneos, ou seja, com dados categóricos e numéricos. Com essa função podemos agregar diferentes tipos de pipelines de pré processamento.

Por fim, criaremos a pipeline final com as funções de pré processamento e com o regressor.

Pipeline para pré processamento e treinamento do mdoelo
Modelo treinado
Cálculo de erro

Conseguimos um RMSE um pouco alto, mas como nosso foco não é a otimização do modelo em si, vamos deixar assim mesmo. Com ele pronto já podemos fazer os testes com o Google Cloud Functions.

Persistindo o Modelo

Antes de enviar o modelo para o Google Cloud Storage, devemos salvar o modelo localmente. Para isso vamos utilizar uma lib chamada joblib.

Persistindo o modelo

Configurações para Uso do Google Services

Para iniciar esta etapa, a primeira coisa a ser feita é criar um projeto no Google Cloud Platform. O Google oferece 300 dólares gratuitos para quem estiver começando a utilizar seus serviços, é uma boa ajuda para quem gosta de fazer PoCs com novas tecnologias.

Em seguida, devemos instalar o Google Cloud command line tools e depois setar nossas credenciais para conexão com as aplicações necessárias. A instalação do command lines tools pode ser feita assim (em máquinas linux, se você usa windows só posso lamentar):

Download do Google Cloud Comand Line Tools

Suas credenciais devem ser ajustadas assim:

Ajuste de credenciais

Para enviarmos o modelo para o GCS devemos instalar a lib do google cloud para python, isso pode ser feito assim:

Ajuste de credenciais

Após as configurações, o primeiro passo a ser tomado é criar um bucket no GCS para armazenar nosso modelo, isso é feito da seguinte maneira:

Criação dos buckets no GCS

Agora vamos salvar o nosso modelo no bucket que acabamos de criar.

Upload do modelo para GCS

Para confirmar que o modelo foi salvo corretamente no bucket, vamos fazer um teste localmente.

Download e teste do modelo

Ok, tudo funcionando normalmente.

  • Configuramos o Google Cloud command line;
  • Ajustamos nossas credenciais;
  • Criamos o bucket no GCS;
  • Enviamos o modelo;

Agora, só nos resta fazer o deploy final para o Google Cloud Functions.

Criando as Funções no Google Cloud Functions

Como falei anteriormente, para fazermos o deploy do nosso modelo utilizando FaaS, nós precisamos apenas ajustar uma função (literalmente).

Criando a função

Para a criação de uma função Cloud Function no Google, siga os seguinte passos:

  1. Procure por “Cloud Function” na barra lateral;
  2. Clique em “Criar Função”;
  3. Adicione o nome que desejar para a função;
  4. Para teste, clique em “Permitir invocações não autenticadas”;
  5. Selecione Python 3.7 como Ambiente de execução.

A nossa função no GCF funciona basicamente como um aplicativo Flask. Ela vai receber um request, processar e gerar um resultado. Bom, nosso request será um json contendo as infomações do imóvel que queremos prever o aluguel e o nosso resultado será o valor predito do aluguel.

Quando a função for criada, você perceberá dois arquivos editáveis na plataforma. No MAIN.PY nós iremos criar nossa função para predição e no REQUIREMENTS.TXT iremos colocar as libs a serem instaladas.

Função main.py

O código da nossa função main.py é o seguinte:

Função main.py

Com o Google Cloud Funtions não podemos criar pastar e salvar arquivos normalmente, mas podemos salvar arquivos na pasta /tmp. Por essa razão salvamos nosso modelo nela após pegarmos do bucket.

Também usamos uma variável global no nosso modelo para não termos a necessidade de leitura de arquivo do HD a cada requisição da API, isso agiliza muito o processo de inferência.

Nosso requirements.txt ficará das seguinte forma:

requirements.txt

Pronto, tudo configurado. Só nos resta testar. O GCF nos fornece uma área de testes da função.

Vamos criar um JSON de exemplo e ver se nosso modelo nos retorna algo. O JSON para teste pode ser o seguinte:

Exemplo de JSON

Isso nos gera o seguinte resultado:

Teste de função no GCF

Também podemos fazer o teste enviando uma requisição diretamente para a URI gerado pela função:

Teste de função utilizando URI

Conclusões

Apesar dessa PoC ter sido bem pequena e simples, consegui simular uma pipeline de um modelo do treinamento ao deploy em um ambiente serverless. A parte mais interessante sem dúvida foi aprender coisas novas sobre as ferramentas do Google Cloud Platform.

As principais conclusões que tirei desse mini projeto foram:

  • A facilidade de trabalho no ambiente Cloud da Google é espantosa. A curva de aprendizado é muito boa;
  • As integrações entre serviços são bem fáceis também;
  • O deploy de um modelo como FaaS foi bem simples, mas como foi um modelo básico e tudo integrado em uma única pipeline acho que essa opinião pode estar um pouco enviesada;
  • Apesar de toda essa facilidade, me pergunto se, com o dólar a quase 6 reais, essas pipelines são viáveis para empresas de médio e pequeno porte. Já que você é cobrado por requisição;
  • Não pude testar a questão da escalabilidade do modelo, como eu disse, o dólar ta em quase 6 reais.

TODOs:

  • Utilizar modelos de Tensorflow ou Pytorch para testar com modelos mais complexos;
  • Utilizar múltiplas funções;
  • Criar pipelines mais complexas para teste.

Para mais tutoriais como esse acesse meu blog: https://jpvmm.github.io/

--

--

João Paulo Martins
Data Hackers

Cientista de Dados que recebe pra ser Cientista de Dados