vinimoreira's picture
the biggest regression
40efad7 verified
raw
history blame
7.11 kB
import gradio as gr
import pandas as pd
import numpy as np
import torch
import joblib
import json
import os
import traceback
from transformers import AutoTokenizer, AutoModel
from torch import nn
# --- 1. DEFINIÇÃO DA ARQUITETURA DO MODELO ---
# Colocamos a classe aqui para que a aplicação seja autocontida.
class RegressionTransformer(nn.Module):
def __init__(self, model_name='neuralmind/bert-base-portuguese-cased'):
super(RegressionTransformer, self).__init__()
self.bert = AutoModel.from_pretrained(model_name)
self.regressor = nn.Sequential(
nn.Dropout(p=0.2),
nn.Linear(self.bert.config.hidden_size, 128),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(128, 1)
)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
pooled_output = outputs.pooler_output
return self.regressor(pooled_output)
# --- 2. CARREGAMENTO DOS ARTEFATOS GLOBAIS ---
# Esta seção é executada uma vez quando a aplicação inicia no Hugging Face Spaces.
print("Carregando artefatos do modelo...")
device = torch.device("cpu")
CACHE_DIR = "./huggingface_cache"
try:
# Carrega o tokenizador
TOKENIZER_NAME = 'neuralmind/bert-base-portuguese-cased'
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_NAME, cache_dir=CACHE_DIR)
print("Tokenizador carregado.")
# Carrega o modelo treinado
MODEL_PATH = './model/best_model_state.pth'
model = RegressionTransformer(model_name=TOKENIZER_NAME)
model.load_state_dict(torch.load(MODEL_PATH, map_location=device))
model.to(device)
model.eval()
print("Modelo carregado.")
# Carrega a lista de features que o modelo espera
FEATURES_PATH = './model/model_features.json'
with open(FEATURES_PATH, 'r') as f:
features_dict = json.load(f)
model_features = features_dict['numeric'] + features_dict['categorical']
print("Features do modelo carregadas.")
except Exception as e:
print("!!!!!! ERRO FATAL AO CARREGAR ARTEFATOS !!!!!!")
traceback.print_exc()
raise e
# --- 3. FUNÇÃO DE LÓGICA / PREVISÃO ---
# Esta função contém a "inteligência" do back-end.
def predict_price(make, model_name, year, odometer, trim, body, transmission, color, interior):
try:
print(f"Recebida nova predição: {make}, {model_name}, {year}, {odometer}km")
# Converte os inputs da interface em um DataFrame de uma linha
input_data_dict = {
'make': make, 'model': model_name, 'year': int(year), 'odometer': float(odometer),
'trim': trim, 'body': body, 'transmission': transmission,
'color': color, 'interior': interior
}
input_df = pd.DataFrame([input_data_dict])
# Aplica a mesma engenharia de features do treinamento
ano_referencia = 2024
input_df['age'] = ano_referencia - input_df['year']
input_df['sale_month'] = 0 # Placeholder
input_df['sale_dayofweek'] = 0 # Placeholder
input_df['sale_dayofyear'] = 0
input_df['make_popularity'] = 0
input_df['model_popularity'] = 0
input_df['km_per_year'] = 0
# Cria a "frase" textual
def criar_representacao_textual(row):
partes = [f"{coluna}[{str(row[coluna])}]" for coluna in model_features if coluna in row]
return " | ".join(partes)
text_input = input_df.apply(criar_representacao_textual, axis=1).iloc[0]
# Tokeniza e prepara os tensores
encoded_text = tokenizer.encode_plus(
text_input, max_length=128, return_tensors='pt',
padding='max_length', truncation=True
)
input_ids = encoded_text['input_ids'].to(device)
attention_mask = encoded_text['attention_mask'].to(device)
# Faz a inferência
with torch.no_grad():
prediction_log = model(input_ids, attention_mask)
# Pós-processa o resultado
predicted_price = np.expm1(prediction_log.cpu().numpy()[0][0])
# Formata a string de saída para o usuário
return f"R$ {predicted_price:,.2f}".replace(",", "X").replace(".", ",").replace("X", ".")
except Exception as e:
print("!!!!!! ERRO DURANTE A PREVISÃO !!!!!!")
traceback.print_exc()
return "Ocorreu um erro. Verifique os logs."
# --- 4. DEFINIÇÃO DA INTERFACE COM GRADIO ---
# Esta seção define a aparência do "front-end".
with gr.Blocks(theme=gr.themes.Soft(), css="footer {display: none !important}") as demo:
gr.Markdown("# 🚗 FipeFinder AI: Previsão de Preços de Carros Usados")
gr.Markdown("Preencha as características do veículo para receber uma estimativa de preço de mercado baseada em nosso modelo de IA. Este projeto demonstra um pipeline completo de Machine Learning, desde a análise de dados e treinamento de um modelo Transformer até o deploy de uma aplicação interativa.")
with gr.Row():
with gr.Column(scale=1):
make_input = gr.Dropdown(label="Marca", choices=["Ford", "Chevrolet", "Honda", "Toyota", "Nissan", "Hyundai", "Kia", "BMW", "Mercedes-Benz", "Volkswagen"])
model_input = gr.Textbox(label="Modelo", placeholder="Ex: Ka, Onix, Civic, Corolla...")
year_input = gr.Slider(label="Ano do Modelo", minimum=2000, maximum=2024, step=1, value=2015)
with gr.Column(scale=1):
odo_input = gr.Number(label="Quilometragem (km)", value=80000)
trim_input = gr.Textbox(label="Versão", placeholder="Ex: SE 1.0, LTZ, EXL...")
body_input = gr.Dropdown(label="Carroceria", choices=["Sedan", "SUV", "Hatchback", "Pickup", "Minivan", "Coupe", "Wagon"])
with gr.Column(scale=1):
trans_input = gr.Radio(label="Transmissão", choices=["automatic", "manual"], value="automatic")
color_input = gr.Textbox(label="Cor Externa", placeholder="Ex: preto, branco, prata...")
interior_input = gr.Textbox(label="Cor Interior", placeholder="Ex: preto, cinza, bege...")
predict_btn = gr.Button("Estimar Preço", variant="primary")
output_price = gr.Label(label="Preço Estimado")
predict_btn.click(
fn=predict_price,
inputs=[make_input, model_input, year_input, odo_input, trim_input, body_input, trans_input, color_input, interior_input],
outputs=output_price
)
gr.Examples(
examples=[
["Ford", "Focus", 2013, 75000.0, "SE 2.0", "Hatchback", "automatic", "prata", "preto"],
["Chevrolet", "Onix", 2018, 90000.0, "LT 1.0", "Hatchback", "manual", "branco", "cinza"],
["Toyota", "Corolla", 2020, 40000.0, "XEi", "Sedan", "automatic", "preto", "preto"],
],
inputs=[make_input, model_input, year_input, odo_input, trim_input, body_input, trans_input, color_input, interior_input]
)
# --- Lançamento da Interface ---
if __name__ == "__main__":
demo.launch()