Spaces:
Sleeping
Sleeping
repo
Browse files- .gitignore +42 -0
- requirements.txt +12 -0
- src/app.py +50 -0
- src/csv_creation.py +36 -0
- src/img_processing.py +97 -0
- src/model_training.py +99 -0
- src/send_model.py +18 -0
.gitignore
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ignorar ambiente virtual
|
| 2 |
+
.venv/
|
| 3 |
+
venv/
|
| 4 |
+
env/
|
| 5 |
+
|
| 6 |
+
# Ignorar arquivos de cache do Python
|
| 7 |
+
__pycache__/
|
| 8 |
+
*.pyc
|
| 9 |
+
*.pyo
|
| 10 |
+
*.pyd
|
| 11 |
+
|
| 12 |
+
# Ignorar arquivos de configuração do VS Code
|
| 13 |
+
.vscode/
|
| 14 |
+
|
| 15 |
+
# Ignorar arquivos de ambiente
|
| 16 |
+
.env
|
| 17 |
+
.env.local
|
| 18 |
+
|
| 19 |
+
# Ignorar arquivos de dados temporários (opcional, dependendo do fluxo de trabalho)
|
| 20 |
+
*.csv
|
| 21 |
+
*.joblib
|
| 22 |
+
|
| 23 |
+
# Ignorar arquivos de log
|
| 24 |
+
*.log
|
| 25 |
+
|
| 26 |
+
# Ignorar diretórios de build e distribuição
|
| 27 |
+
build/
|
| 28 |
+
dist/
|
| 29 |
+
*.egg-info/
|
| 30 |
+
|
| 31 |
+
# Ignorar arquivos do sistema operacional
|
| 32 |
+
.DS_Store
|
| 33 |
+
Thumbs.db
|
| 34 |
+
|
| 35 |
+
# Ignorar arquivos específicos do Hugging Face (se houver)
|
| 36 |
+
*.huggingface/
|
| 37 |
+
*.hf_cache/
|
| 38 |
+
|
| 39 |
+
# Ignorar arquivos gerados pelo Streamlit (opcional)
|
| 40 |
+
.streamlit/
|
| 41 |
+
|
| 42 |
+
animals/
|
requirements.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.1.0
|
| 2 |
+
torchvision==0.16.0
|
| 3 |
+
pandas==2.1.1
|
| 4 |
+
numpy==1.26.0
|
| 5 |
+
opencv-python==4.8.1.78
|
| 6 |
+
scikit-learn==1.3.2
|
| 7 |
+
seaborn==0.12.2
|
| 8 |
+
matplotlib==3.7.2
|
| 9 |
+
streamlit==1.27.0
|
| 10 |
+
joblib==1.3.2
|
| 11 |
+
huggingface_hub==0.19.4
|
| 12 |
+
Pillow==10.0.0
|
src/app.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import joblib
|
| 3 |
+
from PIL import Image
|
| 4 |
+
import torchvision.transforms as transforms
|
| 5 |
+
from huggingface_hub import hf_hub_download
|
| 6 |
+
|
| 7 |
+
# Função para carregar o modelo e o LabelEncoder do Hugging Face
|
| 8 |
+
@st.cache_resource
|
| 9 |
+
def load_model():
|
| 10 |
+
# Baixar o modelo e o LabelEncoder do Hugging Face
|
| 11 |
+
model_path = hf_hub_download(repo_id="arturevs/90AnimalClassification", filename="mlp_classifier.joblib")
|
| 12 |
+
label_encoder_path = hf_hub_download(repo_id="arturevs/90AnimalClassification", filename="label_encoder.joblib")
|
| 13 |
+
|
| 14 |
+
# Carregar o modelo e o LabelEncoder
|
| 15 |
+
model = joblib.load(model_path)
|
| 16 |
+
label_encoder = joblib.load(label_encoder_path)
|
| 17 |
+
return model, label_encoder
|
| 18 |
+
|
| 19 |
+
# Função para pré-processar a imagem
|
| 20 |
+
def preprocess_image(image):
|
| 21 |
+
transform = transforms.Compose([
|
| 22 |
+
transforms.Resize((256, 256)),
|
| 23 |
+
transforms.ToTensor(),
|
| 24 |
+
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
|
| 25 |
+
])
|
| 26 |
+
image = transform(image).flatten().numpy().reshape(1, -1)
|
| 27 |
+
return image
|
| 28 |
+
|
| 29 |
+
# Interface da aplicação
|
| 30 |
+
st.title("Classificador de Animais")
|
| 31 |
+
st.write("Envie uma imagem de um animal (gato, cachorro ou pássaro) para classificação.")
|
| 32 |
+
|
| 33 |
+
# Carregar o modelo e o LabelEncoder
|
| 34 |
+
model, label_encoder = load_model()
|
| 35 |
+
|
| 36 |
+
# Upload da imagem
|
| 37 |
+
uploaded_file = st.file_uploader("Escolha uma imagem...", type=["jpg", "jpeg", "png"])
|
| 38 |
+
if uploaded_file is not None:
|
| 39 |
+
image = Image.open(uploaded_file)
|
| 40 |
+
st.image(image, caption="Imagem enviada", use_column_width=True)
|
| 41 |
+
|
| 42 |
+
# Pré-processar a imagem
|
| 43 |
+
image_processed = preprocess_image(image)
|
| 44 |
+
|
| 45 |
+
# Fazer a previsão
|
| 46 |
+
prediction = model.predict(image_processed)
|
| 47 |
+
predicted_class = label_encoder.inverse_transform(prediction)[0]
|
| 48 |
+
|
| 49 |
+
# Exibir o resultado
|
| 50 |
+
st.write(f"Classificação: **{predicted_class}**")
|
src/csv_creation.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import pandas as pd
|
| 3 |
+
|
| 4 |
+
# Caminho para a pasta csv_folder (usando caminho relativo)
|
| 5 |
+
CSV_FOLDER = "./csv_folder"
|
| 6 |
+
|
| 7 |
+
# Lista para armazenar todos os DataFrames
|
| 8 |
+
dataframes = []
|
| 9 |
+
|
| 10 |
+
# Percorrer todos os arquivos na pasta csv_folder
|
| 11 |
+
for csv_file in os.listdir(CSV_FOLDER):
|
| 12 |
+
if csv_file.endswith(".csv"): # Verificar se é um arquivo CSV
|
| 13 |
+
csv_path = os.path.join(CSV_FOLDER, csv_file)
|
| 14 |
+
|
| 15 |
+
try:
|
| 16 |
+
# Ler o CSV e adicionar à lista de DataFrames
|
| 17 |
+
df = pd.read_csv(csv_path)
|
| 18 |
+
dataframes.append(df)
|
| 19 |
+
print(f"Arquivo '{csv_file}' carregado com sucesso.")
|
| 20 |
+
except Exception as e:
|
| 21 |
+
print(f"Erro ao carregar o arquivo '{csv_file}': {e}")
|
| 22 |
+
|
| 23 |
+
# Verificar se há DataFrames para unificar
|
| 24 |
+
if not dataframes:
|
| 25 |
+
print("Nenhum arquivo CSV foi carregado. Verifique a pasta 'csv_folder'.")
|
| 26 |
+
else:
|
| 27 |
+
# Unificar todos os DataFrames em um único DataFrame
|
| 28 |
+
unified_df = pd.concat(dataframes, ignore_index=True)
|
| 29 |
+
|
| 30 |
+
# Salvar o DataFrame unificado em um novo arquivo CSV
|
| 31 |
+
output_csv_path = os.path.join("./", "unified_dataset.csv")
|
| 32 |
+
try:
|
| 33 |
+
unified_df.to_csv(output_csv_path, index=False)
|
| 34 |
+
print(f"Dataset unificado salvo como '{output_csv_path}'")
|
| 35 |
+
except Exception as e:
|
| 36 |
+
print(f"Erro ao salvar o dataset unificado: {e}")
|
src/img_processing.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import cv2
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
import torchvision.transforms as transforms
|
| 7 |
+
from torchvision.models import resnet18 # Usaremos uma CNN pré-treinada (ResNet18)
|
| 8 |
+
|
| 9 |
+
# Configurações
|
| 10 |
+
DATASET_PATH = "./animals/" # Pasta principal com as subpastas de animais
|
| 11 |
+
CSV_FOLDER = "./csv_folder" # Pasta para salvar os CSVs
|
| 12 |
+
IMAGE_SIZE = (224, 224) # Tamanho das imagens para a CNN
|
| 13 |
+
|
| 14 |
+
# Criar a pasta csv_folder se não existir
|
| 15 |
+
if not os.path.exists(CSV_FOLDER):
|
| 16 |
+
os.makedirs(CSV_FOLDER)
|
| 17 |
+
|
| 18 |
+
# Carregar uma CNN pré-treinada (ResNet18) e remover a camada final (fully connected)
|
| 19 |
+
cnn_model = resnet18(pretrained=True)
|
| 20 |
+
cnn_model = nn.Sequential(*list(cnn_model.children())[:-1]) # Remove a última camada
|
| 21 |
+
cnn_model.eval() # Colocar o modelo em modo de avaliação
|
| 22 |
+
|
| 23 |
+
# Transformações para a imagem
|
| 24 |
+
transform = transforms.Compose([
|
| 25 |
+
transforms.ToPILImage(),
|
| 26 |
+
transforms.Resize(IMAGE_SIZE),
|
| 27 |
+
transforms.ToTensor(),
|
| 28 |
+
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # Normalização para o modelo pré-treinado
|
| 29 |
+
])
|
| 30 |
+
|
| 31 |
+
# Função para extrair características de uma imagem usando a CNN
|
| 32 |
+
def extract_features(image):
|
| 33 |
+
with torch.no_grad(): # Desativar cálculo de gradientes
|
| 34 |
+
image_tensor = transform(image).unsqueeze(0) # Adicionar dimensão do batch
|
| 35 |
+
features = cnn_model(image_tensor) # Extrair características
|
| 36 |
+
return features.flatten().numpy() # Achatar e converter para numpy array
|
| 37 |
+
|
| 38 |
+
# Função para processar uma subpasta (espécie) e salvar em um DataFrame
|
| 39 |
+
def process_animal_folder(animal_class, class_path):
|
| 40 |
+
# Lista para armazenar os dados da subpasta
|
| 41 |
+
data = []
|
| 42 |
+
|
| 43 |
+
# Percorrer as imagens da subpasta
|
| 44 |
+
for image_name in os.listdir(class_path):
|
| 45 |
+
image_path = os.path.join(class_path, image_name)
|
| 46 |
+
|
| 47 |
+
try:
|
| 48 |
+
# Verificar se o arquivo é uma imagem válida
|
| 49 |
+
if not image_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
|
| 50 |
+
print(f"Ignorando arquivo não suportado: {image_path}")
|
| 51 |
+
continue
|
| 52 |
+
|
| 53 |
+
# Carregar a imagem
|
| 54 |
+
image = cv2.imread(image_path)
|
| 55 |
+
if image is None:
|
| 56 |
+
raise ValueError(f"Falha ao carregar a imagem: {image_path}")
|
| 57 |
+
|
| 58 |
+
# Extrair características usando a CNN
|
| 59 |
+
features = extract_features(image)
|
| 60 |
+
|
| 61 |
+
# Adicionar ao dataset com o label sendo o nome da subpasta
|
| 62 |
+
data.append([animal_class] + list(features))
|
| 63 |
+
except Exception as e:
|
| 64 |
+
print(f"Erro ao processar {image_path}: {e}")
|
| 65 |
+
|
| 66 |
+
# Verificar se há dados antes de criar o DataFrame
|
| 67 |
+
if not data:
|
| 68 |
+
print(f"Nenhuma imagem válida encontrada na pasta: {class_path}")
|
| 69 |
+
return None
|
| 70 |
+
|
| 71 |
+
# Criar DataFrame
|
| 72 |
+
columns = ["label"] + [f"feature_{i}" for i in range(len(data[0]) - 1)]
|
| 73 |
+
df = pd.DataFrame(data, columns=columns)
|
| 74 |
+
|
| 75 |
+
return df
|
| 76 |
+
|
| 77 |
+
# Percorrer as subpastas
|
| 78 |
+
for animal_class in os.listdir(DATASET_PATH):
|
| 79 |
+
class_path = os.path.join(DATASET_PATH, animal_class)
|
| 80 |
+
|
| 81 |
+
# Verificar se é uma pasta
|
| 82 |
+
if os.path.isdir(class_path):
|
| 83 |
+
print(f"Processando imagens da classe: {animal_class}")
|
| 84 |
+
|
| 85 |
+
# Processar a subpasta e obter o DataFrame
|
| 86 |
+
df = process_animal_folder(animal_class, class_path)
|
| 87 |
+
|
| 88 |
+
if df is not None:
|
| 89 |
+
# Salvar CSV com o nome do animal
|
| 90 |
+
csv_filename = os.path.join(CSV_FOLDER, f"{animal_class}_dataset.csv")
|
| 91 |
+
try:
|
| 92 |
+
df.to_csv(csv_filename, index=False)
|
| 93 |
+
print(f"Dataset salvo como '{csv_filename}'")
|
| 94 |
+
except Exception as e:
|
| 95 |
+
print(f"Erro ao salvar o dataset {csv_filename}: {e}")
|
| 96 |
+
|
| 97 |
+
print("Processamento concluído!")
|
src/model_training.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import numpy as np
|
| 3 |
+
from sklearn.model_selection import train_test_split
|
| 4 |
+
from sklearn.preprocessing import StandardScaler, LabelEncoder
|
| 5 |
+
from sklearn.neural_network import MLPClassifier
|
| 6 |
+
from sklearn.metrics import classification_report, accuracy_score, confusion_matrix
|
| 7 |
+
import seaborn as sns
|
| 8 |
+
import matplotlib.pyplot as plt
|
| 9 |
+
import joblib
|
| 10 |
+
|
| 11 |
+
# Carregar o dataset unificado
|
| 12 |
+
csv_path = "./unified_dataset.csv" # Caminho relativo a partir da pasta src
|
| 13 |
+
try:
|
| 14 |
+
df = pd.read_csv(csv_path)
|
| 15 |
+
print("Dataset carregado com sucesso!")
|
| 16 |
+
except Exception as e:
|
| 17 |
+
print(f"Erro ao carregar o dataset: {e}")
|
| 18 |
+
exit()
|
| 19 |
+
|
| 20 |
+
# Verificar o dataset
|
| 21 |
+
print(df.head())
|
| 22 |
+
print(f"Tamanho do dataset: {df.shape}")
|
| 23 |
+
|
| 24 |
+
# Separar features (X) e labels (y)
|
| 25 |
+
X = df.drop(columns=["label"]) # Todas as colunas exceto 'label'
|
| 26 |
+
y = df["label"] # Coluna 'label'
|
| 27 |
+
|
| 28 |
+
# Codificar as labels (transformar strings em números)
|
| 29 |
+
label_encoder = LabelEncoder()
|
| 30 |
+
y = label_encoder.fit_transform(y)
|
| 31 |
+
|
| 32 |
+
# Dividir o dataset em treino e teste
|
| 33 |
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
| 34 |
+
|
| 35 |
+
# Normalizar as features (importante para MLP)
|
| 36 |
+
scaler = StandardScaler()
|
| 37 |
+
X_train = scaler.fit_transform(X_train)
|
| 38 |
+
X_test = scaler.transform(X_test)
|
| 39 |
+
|
| 40 |
+
# Criar e treinar a MLP
|
| 41 |
+
mlp = MLPClassifier(
|
| 42 |
+
hidden_layer_sizes=(128, 64), # Duas camadas ocultas com 128 e 64 neurônios
|
| 43 |
+
activation="relu", # Função de ativação ReLU
|
| 44 |
+
solver="adam", # Otimizador Adam
|
| 45 |
+
max_iter=500, # Número máximo de iterações
|
| 46 |
+
random_state=42,
|
| 47 |
+
verbose=True # Mostrar progresso durante o treinamento
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
print("Treinando a MLP...")
|
| 51 |
+
mlp.fit(X_train, y_train)
|
| 52 |
+
|
| 53 |
+
# Fazer previsões no conjunto de teste
|
| 54 |
+
y_pred = mlp.predict(X_test)
|
| 55 |
+
|
| 56 |
+
# Avaliar o modelo
|
| 57 |
+
print("\nRelatório de classificação:")
|
| 58 |
+
print(classification_report(y_test, y_pred, target_names=label_encoder.classes_))
|
| 59 |
+
|
| 60 |
+
print(f"Acurácia: {accuracy_score(y_test, y_pred):.4f}")
|
| 61 |
+
|
| 62 |
+
# Gerar a matriz de confusão
|
| 63 |
+
conf_matrix = confusion_matrix(y_test, y_pred)
|
| 64 |
+
|
| 65 |
+
# Plotar a matriz de confusão
|
| 66 |
+
plt.figure(figsize=(10, 7))
|
| 67 |
+
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues",
|
| 68 |
+
xticklabels=label_encoder.classes_,
|
| 69 |
+
yticklabels=label_encoder.classes_)
|
| 70 |
+
plt.xlabel("Predito")
|
| 71 |
+
plt.ylabel("Verdadeiro")
|
| 72 |
+
plt.title("Matriz de Confusão")
|
| 73 |
+
plt.show()
|
| 74 |
+
|
| 75 |
+
# Extrair valores relevantes da matriz de confusão
|
| 76 |
+
print("\nValores relevantes da matriz de confusão:")
|
| 77 |
+
|
| 78 |
+
# Acurácia por classe
|
| 79 |
+
class_accuracy = conf_matrix.diagonal() / conf_matrix.sum(axis=1)
|
| 80 |
+
for i, accuracy in enumerate(class_accuracy):
|
| 81 |
+
print(f"Acurácia da classe {label_encoder.classes_[i]}: {accuracy:.4f}")
|
| 82 |
+
|
| 83 |
+
# Erros mais comuns (maiores valores fora da diagonal)
|
| 84 |
+
conf_matrix_df = pd.DataFrame(conf_matrix, index=label_encoder.classes_, columns=label_encoder.classes_)
|
| 85 |
+
conf_matrix_df.values[np.diag_indices_from(conf_matrix_df)] = 0 # Zerar a diagonal para focar nos erros
|
| 86 |
+
most_common_errors = conf_matrix_df.stack().sort_values(ascending=False).head(5)
|
| 87 |
+
|
| 88 |
+
print("\nErros mais comuns:")
|
| 89 |
+
print(most_common_errors)
|
| 90 |
+
|
| 91 |
+
# Salvar o modelo
|
| 92 |
+
model_filename = "mlp_classifier.joblib"
|
| 93 |
+
joblib.dump(mlp, model_filename)
|
| 94 |
+
print(f"Modelo salvo como {model_filename}")
|
| 95 |
+
|
| 96 |
+
# Salvar o LabelEncoder (para decodificar as previsões)
|
| 97 |
+
label_encoder_filename = "label_encoder.joblib"
|
| 98 |
+
joblib.dump(label_encoder, label_encoder_filename)
|
| 99 |
+
print(f"LabelEncoder salvo como {label_encoder_filename}")
|
src/send_model.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from huggingface_hub import HfApi
|
| 2 |
+
|
| 3 |
+
# Nome do repositório no Hugging Face
|
| 4 |
+
repo_id = "arturevs/90AnimalClassifier" # Substitua pelo seu usuário e nome do repositório
|
| 5 |
+
|
| 6 |
+
# Arquivos a serem enviados
|
| 7 |
+
files_to_upload = ["./mlp_classifier.joblib", "./label_encoder.joblib"]
|
| 8 |
+
|
| 9 |
+
# Enviar arquivos para o Hugging Face
|
| 10 |
+
api = HfApi()
|
| 11 |
+
for file in files_to_upload:
|
| 12 |
+
api.upload_file(
|
| 13 |
+
path_or_fileobj=file,
|
| 14 |
+
path_in_repo=file,
|
| 15 |
+
repo_id=repo_id,
|
| 16 |
+
repo_type="model"
|
| 17 |
+
)
|
| 18 |
+
print("Modelo enviado para o Hugging Face!")
|