Tensorflow — Prevendo o preço de casas com base na sua área total
Olá, este post está dividido em duas partes:
Parte 1: Tensorflow — Uma porta de entrada para Machine Learning
Parte 2: Tensorflow — Prevendo o preço de casas com base na sua área total
Avançando nos estudos de Data science, aqui vou seguir me aventurando neste mundo desconhecido, o famigerado mundo de Machine Learning. Seguindo a mesma ideia de outros posts que já fiz aqui, este post será a segunda parte dos estudos de TensorFlow. No primeiro post foi falado o que é o TensorFlow, explicado alguns conceitos, como ele funciona e quais são seus principais benefícios. O objetivo deste post é mostrar o uso de TensorFlow do ponto de vista de um desenvolvedor de software.
Modelo de Regressão linear simples — introdução
Aviso: Durante estes estudos eu percebi a necessidade de conhecer ao menos o básico de estatísticas. Na verdade, já havia comentado sobre essa necessidade no post de Data science. Durante a elaboração deste post isso ficou ainda mais evidente.
O tutorial deste post utiliza equações de regressão linear para solucionar o problema levantado. Não pretendo entrar nos detalhes de cada formula , mas aqui nesta sessão vou deixar um breve resumo sobre o que é o modelo de Regressão linear simples.
Caso você queira pular essa sessão e voltar mais tarde. Fique a vontade para ir direto a sessão TensorFlow na prática.
Regressão linear é um modelo estatístico que examina o relacionamento linear entre duas(Regressão linear simples) ou mais(Regressão linear múltipla) variáveis — uma independente e outra dependente. O relacionamento linear basicamente diz que quando uma( ou mais) variáveis independentes aumentam( ou diminuem), as variáveis dependentes aumentam(ou diminuem) também:
Como é possível notar na Figura 1, um relacionamento linear pode ser positivo ou negativo. Isso é possível notar observando a direção que a linha é desenhada no gráfico.
A relação entre as duas variáveis, X e Y, é representada pela equação abaixo:
Y = mX + b
Analisando a equação temos as seguintes observações:
- Y é a variável dependente. A variável que estamos tentando prever ou estimar;
- X é a variável independente. A variável que estamos usando para dar as previsões;
- m é a inclinação da linha de regressão. Representa o efeito que X possui em Y. Em outras palavras, se X aumentar por 1 unidade, Y irá aumentar exatamente m unidades. (Ressalva: isso pode se aplicar apenas para os casos que soubermos que X e Y têm um relacionamento linear. Em quase todos os casos de Regressão linear, isso não será verdade)
- b é uma constante, é o ponto em que a linha intercepta o eixo Y. Se X é igual a 0(zero), Y será igual a b. (Ressalva: aqui é o mesmo caso da ressalva acima)
As observações descritas acima não necessariamente se aplicam na vida real — pois não teremos sempre uma relação exatamente linear entre os pontos X e Y.
Essas ressalvas nos levam a um modelo de Regressão Linear Simples(RLS). Este modelo é construído baseado em dados — o declive da linha(m) e o ponto em que intercepta o eixo Y (b) são derivados de dados. Além disso, o modelo RLS não faz necessário que o relacionamento entre X e Y seja exatamente linear.
Os modelos SLR também levam em consideração os possíveis erros que possam ter no dados( também conhecidos como resíduos). Para não estender muito o post, não irei entrar no detalhe sobre isso, mas os resíduos é basicamente a diferença entre o valor real e o valor estimado de Y. É importante notar que em uma Regressão linear, estamos tentando prever uma variável continua. E no modelo de regressão, estamos tentando minimizar os erros e achar a “linha mais próxima do ideal”.
O objetivo do modelo de Regressão linear simples é diminuir a distância dos pontos azuis da linha vermelha o mais perto de zero quanto possível. Isso é relacionado( ou equivalente) a minimizar o erro médio quadrático ou a soma residual dos quadrados. Mas estes detalhes estão certamente além do escopo deste post :-).
TensorFlow na prática
Agora que entendemos um pouco sobre o modelo de Regressão linear simples, vamos preparar nosso ambiente para utilizar o TensorFlow.
Instalando e preparando ambiente
O TensorFlow é multiplataforma, ou seja, ele funciona em diferentes sistemas operacionais e ambientes. Para executar este tutorial, eu utilizei o sistema operacional Ubuntu 18 e rodei tudo dentro de um virtual environment de Python. Caso este não seja o seu caso, siga as instruções daqui.
- Instale Python 3, pip e Virtualenv.
sudo apt-get install python3-pip python3-dev python-virtualenv
2. Crie e ative o Virtualenv.
virtualenv --system-site-packages -p python3 .env3
source .env3/bin/activate
3. Após ativado, instale as dependências no VirtualEnv.
pip install tensorflow
4. Rode o comando abaixo para verificar se foi instalado corretamente.
python -c "import tensorflow as tf; print(tf.__version__)"
A questão que queremos responder
Existe um ciclo no processo de Data Science, como é possível visualizar na figura abaixo:
Observação: Caso queira mais detalhes sobre cada uma destas etapas, eu falo mais sobre isso no post sobre Data Science.
Neste tutorial, será abordada cada uma das esferas do ciclo — exceto as esfera de “coleta de dados”(pois os dados serão gerados randomicamente) e esfera de “implantar o modelo”(pois pretendo deixar este assunto para outro post :-) ).
Começando pela primeira esfera, qual é a questão que queremos analisar?(dica, tem spoiler no título :-D). Para este tutorial, a questão( ou hipótese) que queremos analisar é:
Se existe uma relação entre o preço do imóvel e a sua área útil.
Utilizando Regressão linear simples e um algoritmo de otimização chamado Gradient Descent — já disponibilizado pela TensorFlow — iremos implementar um modelo que aprenderá a relação entre área útil e o valor do imóvel e preverá possíveis valores de acordo com a área útil passada.
Mão a obra
A partir daqui, por questão de didática, vamos analisar pedaços de códigos, etapa a etapa — caso queira acessar o código completo, acesse aqui.
Preparando os dados
O primeiro passo que precisamos fazer é gerar o volume de dados. Após isso, devemos preparar nossos dados, dividindo-os em duas partes: o conjunto para treinar o modelo e o conjunto para testar. Vamos analisar o trecho abaixo:
Neste trecho de código estamos gerando 160 imóveis, com valores de preços e áreas úteis randômicos. Destes 160 imóveis, 70% será utilizado para treinar o modelo e 30% para testar. Note que a normalização dos valores também faz parte deste processo de preparar os dados(efetuamos ela com o método normalize
). A normalização é uma prática utilizada em estatísticas para ajustar valores de diferentes escalas para que todos tenham o mesmo peso.
Neste tutorial utilizamos a biblioteca Numpy, uma biblioteca muito famosa nos algoritmos de computação científica. No trecho acima, ela é utilizada para trabalhar com arrays e operações randômicas. O exemplo abaixo gera uma lista de 160 valores randômicos no intervalo de 90 e 325:
np.random.randint(low=90, high=325, size=160)
Criando o modelo
Agora que preparamos nossos dados, vamos começar a desenvolver o modelo, é nesta parte que começará a aparecer os cálculos estatísticos. Abaixo vamos analisar o código fonte que esboça o inicio deste modelo:
Até o momento, ainda não tínhamos visto nenhum código realmente relacionado ao Tensorflow. Mas no trecho acima já é possível notar a aparição de algumas funções especificas deste framework, vamos entender o que cada uma delas faz.
Placeholder. O tf.placeholder()
(a tradução é “espaço reservado”) é simplesmente uma variável à qual os dados serão atribuídos num momento futuro. Ele nos permite a construção dos grafos — aqueles vistos no primeiro artigo — sem realmente precisar dos dados. Estamos, de fato, reservando um espaço que será utilizado posteriormente. No caso do nosso tutorial, os dados do placeholder serão provindos dos dados analisados( aqueles 160 imóveis que acabamos de gerar)
Variable. O tf.Variable()
é muito semelhante ao placeholder, ele também nos permite a construção dos grafos assim como também fará um processamento tardio( lazy computing). A principal diferença é que os dados da Variable estarão diretamente ligados ao aprendizado( algoritmos de Machine learning). Então, sempre que criamos modelos que precisam derivar os dados, estes dados serão armazenados em Variable. Que é exatamente o caso deste tutorial.
Após a declaração dos placeholders e variables, é declarado duas formulas, são elas:
Regressão linear simples. A formula já vista anteriormente aqui , ela será utilizada para prever o preço do imóvel. Abaixo é possível visualizar ela e comparar com a formula apresentada na sessão anterior:
tf_price_pred = tf_size_factor * tf_house_size + tf_price_offset
Y = m * X + b
Função de perda ou erro médio quadrático. Não entraremos no detalhes( pois daria um post só para isso), mas resumidamente falando é a função utilizada para otimizar e minimizar o erro do modelo — Machine learning :-). Abaixo podemos visualizar a formula da função:
tf_cost = tf.reduce_sum(pow(tf_price_pred - tf_price, 2)) / (2 * num_train_samples)
Observando esta formula, é possível notar mais uma função do TensorFlow. O tf.reduce_sum()
efetua o somatório de matrizes, ignorando o limite das dimensões. O exemplo abaixo deixa mais claro o que estou falando:
x = np.asarray([[1,2,1],[1,2,3]])
tf.reduce_sum(x) # 10
tf.reduce_sum(x, 0) # [2, 4, 4]
tf.reduce_sum(x, 1) # [4, 6]
O segundo parâmetro define qual é a dimensão que será calculada, para mais detalhes veja este link.
Aplicando o Machine Learning
Continuando na etapa de criar o modelo, vamos usar o algoritmo de otimização e executar iterações de aprendizado. O algoritmo abaixo demonstra isso:
No primeiro post que escrevi sobre Tensorflow, eu comentei que a principal razão de eu me interessar por essa ferramenta foi o palestrante ter apresentado como a “porta de entrada de Machine learning para os engenheiros de software”. É a partir de agora que isso começa a fazer sentido.
Machine Learning possui muitos algoritmos complexos, são algoritmos não usuais para a maioria dos engenheiros de software. E nisso que o TensorFlow ajuda, permitindo um certo nível de abstração — não sendo necessário entender os detalhes para desenvolver soluções Machine Learning. Abaixo é possível visualizar a chamada de um destes algoritmos :
optimizer = tf.train.GradientDescentOptimizer(0.1).minimize(tf_cost)
O 0.1
é a taxa de aprendizado(learning rate), é referente ao tamanho do passo que o algoritmo dará a cada adaptação do aprendizado, quanto menor for o valor mais preciso será o aprendizado e mais demorado será o processo.
Note que o optimizer
utiliza a formula de função de perda, a tf_cost
. A tf_cost
por sua vez, possui em sua formula duas Variables: tf_size_factor
e tf_price_offset
. Lembra que eu comentei que as Variables estão diretamente ligadas a algoritmos de aprendizado? Pois bem, a cada vez que é executado o optimizer
, o valor destas variáveis é reprocesso e ajustado, até chegar ao valor mais próximo de ótimo.
Session. Até agora, somente havíamos declarado formulas e variáveis e nenhum cálculo foi de fato processado. No Tensorflow, toda e qualquer computação é executada dentro de uma session
, além do mais, para começar a utilizar as Variables, é necessário inicializa-las utilizando tf.global_variables_initializer()
. Vamos analisar o que acontece na nossa session
:
num_training_iter = 80
for iteration in range(num_training_iter):
for (x, y) in zip(train_house_size_norm, train_price_norm):
sess.run(optimizer, feed_dict={tf_house_size: x, tf_price: y})
É possível notar que estamos fazendo 80 tentativas de treinamento / otimização do nosso modelo. A cada tentativa, estamos percorrendo uma lista contendo a combinação de áreas úteis normalizadas e preços normalizados. Para cada uma das combinações é executado o algorítimo de otimização(que por sua vez utiliza as formulas de regressão linear e função de perda). Note que o segundo parâmetro feed_dict
está passando os valores(a área útil e preço a serem processados) para os placeholders declarados anteriormente.
Ufa! Conseguimos! Acabamos de criar um modelo que aprendeu como prever o preço de imóveis baseado em uma área útil.
Agora vamos validar esse modelo?
Validando o modelo
Bom, agora precisamos validar o modelo — e como foi comentado no post de Data science — para isso precisamos utilizar o modelo e perceber se ele atende a necessidade e a informação retornada está de acordo com a realidade. Existem várias maneiras de testar o modelo:
- Podemos exportar o modelo para um arquivo e recuperar ele em outro script Python e executa-lo.
- Podemos exportar o modelo para um arquivo e executar ele via linha de comando(
saved_model_cli
). - Podemos implantar o modelo em um servidor para clients consumir o modelo.
As opções citadas acimas são utilizadas quando queremos implantar nosso modelo de modo que outras pessoas possam utilizar. Mas por questões de didática, praticidade e debug, iremos testar o nosso modelo simplesmente adicionando o trecho abaixo logo após o último print
:
No código acima estamos percorrendo os dados de teste(aqueles 30% que separamos no inicio) e rodando a formula de previsão de preço( tf_price_prediction
). Como os cálculos foram feito com base em dados normalizados — lembre que normalizamos os dados para treinamento do modelo — , precisamos normalizar os dados de teste também. O resultado do preço previsto será um valor normalizado, para visualizarmos melhor o resultado e compararmos, precisamos desnormalizar. Segue abaixo o output
do algoritmo (vou colocar somente os 5 primeiros resultados):
House size:243 Original price:301952.0 Price Prediction: 286238.553631259 Diff:-15713.446368740988House size: 306 Original price: 348662.0 Price Prediction: 349381.0713364025 Diff: 719.0713364024996House size: 277 Original price: 305392.0 Price Prediction: 320315.47017320164 Diff: 14923.47017320164House size: 213 Original price: 263535.0 Price Prediction: 256170.6841891221 Diff: -7364.315810877888House size: 130 Original price: 163067.0 Price Prediction: 172982.90762369934 Diff: 9915.907623699342
No output
é possível comparar a areal útil testada, o valor original, o valor que o nosso modelo previu e a diferença entre os dois. A primeira vista é possível perceber que tem uma grande diferença ( para mais e para menos) entre o valor previsto e o original.
Para intuito de aprendizado, o nosso modelo/tutorial está pronto. Mas na vida real, é a partir deste ponto que o ciclo do processo de Data science reiniciaria — ou voltaria uma ou mais etapas. Por exemplo, poderíamos descobrir que a massa de dados é pouca e criaríamos um modelo com mais imóveis, ou que precisamos de mais iterações ou que precisaríamos ajustar melhor a taxa de aprendizado (learning rate) ou até que este não é o modelo certo para resolver o nosso problema.
Conclusão
O intuito deste post era sair um pouco da teoria de Machine learning e entrar para prática. A elaboração deste tutorial foi feita conforme eu ia aprendendo sobre o assunto, a principal referência que utilizei foi este curso da Pluralsight. Também li muitas perguntas e respostas no Data science Stack Exchange, foi lá que peguei dicas sobre as formulas de cálculos estatísticos.
No curso da Pluralsight é mostrado o uso de outras bibliotecas, como por exemplo a matplotlib
, que permite criarmos gráficos para visualizar a evolução do aprendizado. Também é mostrado o uso do Tensorboard , o dashboard disponibilizado pelo próprio Tensorflow. Mas como este post já ficou muito extenso, eu resolvi deixar estes assuntos para um post futuro :-).
Caso queira ver a versão completa do código deste tutorial, é possível acessar aqui no meu github.
Se quiser trocar uma ideia ou entrar em contato comigo, pode me achar no Twitter(@e_ferreirasouza) ou Linkedin.
Grande abraço e até a próxima!