Creare una mini-AI autonoma
Obiettivo del modulo
Progettare, addestrare e deployare una micro-AI che svolge un compito ben definito (testo, immagini o decisioni),
con pipeline completa: input → decisione AI → output → validazione, interfaccia d’uso (CLI, API o web),
logging e salvataggio/ripristino dei pesi. Il percorso è hands-on e progressivo: si parte da un baseline semplice, poi si estende.
Scaletta passo-passo
🕐 Scoping e setup ambiente
Scegli il dominio:
- Testo: classificatore di notizie (politica/sport/tech).
- Immagini: generatore di descrizioni per immagini pre-caricate (feature estratte + template).
- Decisioni: AI che suggerisce azioni su una checklist (regole+modello).
- Definisci l’output: etichetta, punteggio, testo, raccomandazione con motivazione breve.
- Setup: Python 3.10+, virtualenv, pacchetti minimi:
pip install numpy pandas scikit-learn joblib fastapi uvicorn streamlit pydantic
Repo: struttura consigliata:
mini_ai/
├─ data/ # dataset grezzi e processati
├─ models/ # pesi, vectorizer, versioni
├─ src/
│ ├─ config.py
│ ├─ preprocess.py
│ ├─ model.py
│ ├─ train.py
│ ├─ eval.py
│ ├─ serve_api.py # FastAPI
│ └─ ui_streamlit.py # interfaccia web
└─ logs/
🕑 Dati e metrica di successo
- Raccolta: CSV con colonne minime (es.
text,label per il testo; image_path,caption per immagini).
- Split: train/val/test (70/15/15) con stratificazione per classi.
Metriche:
- Classificazione: accuracy, F1 macro (classi sbilanciate), matrice di confusione.
- Generazione (caption): BLEU/ROUGE (anche valutazione umana light: 1–5 coerenza).
- Decisioni su checklist: precision@k e tasso di adozione (quante azioni proposte accettate).
🕒 Baseline funzionante (semplice & robusto)
Obiettivo: avere una prima versione end-to-end che produce un output coerente, anche se non perfetto.
Testo (consigliato per iniziare):
CountVectorizer + Logistic Regression (veloce, solido, interpretabile).
# src/train.py (estratto – baseline testo)
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report
import joblib, os
df = pd.read_csv("data/news.csv") # colonne: text,label
train, test = train_test_split(df, test_size=0.2, stratify=df.label, random_state=42)
pipe = Pipeline([
("vec", CountVectorizer(max_features=30000, ngram_range=(1,2))),
("clf", LogisticRegression(max_iter=200, n_jobs=-1))
])
pipe.fit(train.text, train.label)
pred = pipe.predict(test.text)
print(classification_report(test.label, pred, digits=3))
os.makedirs("models", exist_ok=True)
joblib.dump(pipe, "models/news_baseline.joblib")
- Immagini (baseline didattico):
estrai feature con un backbone pre-addestrato (es. ResNet da torchvision), poi Nearest Neighbors per suggerire la caption dell’immagine più simile (semplice ma utile per il flusso end-to-end).
- Decisioni:
Rule-first + piccolo modello: regole deterministiche per i casi chiari; modello di classificazione binaria per consigliare “fai/non fare” dove le regole non bastano.
🕓 Validazione, error analysis, versioning
- Valida sullo split di test; salva classification_report in
logs/ con timestamp.
- Errori ricorrenti: estrai i falsi positivi/negativi, crea una “lista nera” di pattern e una todo di miglioramenti (es. pulizia testo, stopword dominio-specifiche).
Versiona modelli/dati:
# src/config.py
MODEL_VERSION = "v1.0.0"
ARTIFACT_DIR = f"models/{MODEL_VERSION}/"
Salva anche le feature (vectorizer) e la configurazione usata (seed, parametri, vocabolario).
🕔 Interfacce d’uso (CLI, API, Web)
CLI (per uso locale/automazione):
# src/model.py (inference)
import joblib
_pipe = joblib.load("models/news_baseline.joblib")
def predict_text(txt: str):
label = _pipe.predict([txt])[0]
prob = max(_pipe.predict_proba([txt])[0])
return {"label": label, "confidence": float(prob)}
# cli.py
import argparse
from src.model import predict_text
parser = argparse.ArgumentParser()
parser.add_argument("--text", required=True)
args = parser.parse_args()
print(predict_text(args.text))
API (per integrazioni):
# src/serve_api.py
from fastapi import FastAPI
from pydantic import BaseModel
from src.model import predict_text
app = FastAPI(title="Mini-AI API")
class Item(BaseModel):
text: str
@app.post("/predict")
def predict(item: Item):
return predict_text(item.text)
# Avvio: uvicorn src.serve_api:app --reload --port 8000
Web UI (demo rapida):
# src/ui_streamlit.py
import streamlit as st
from src.model import predict_text
st.title("🧠 Mini-AI Classificatore di Notizie")
txt = st.text_area("Inserisci il testo della notizia")
if st.button("Predici"):
out = predict_text(txt)
st.write(f"**Classe:** {out['label']} | **Confidenza:** {out['confidence']:.2f}")
Avvio: streamlit run src/ui_streamlit.py
🕕 Logging, debugging, salvataggio/riuso pesi
Logging strutturato (JSON line per facile analisi):
# src/logging_utils.py
import json, time, os
def log_event(event: dict, fname="logs/events.jsonl"):
os.makedirs("logs", exist_ok=True)
event["ts"] = time.time()
with open(fname, "a", encoding="utf-8") as f:
f.write(json.dumps(event, ensure_ascii=False) + "\n")
Usalo in API/UI:
# dentro /predict
res = predict_text(item.text)
log_event({"route": "predict", "input_len": len(item.text), "output": res})
return res
- Salvataggio & ripristino: già visto con
joblib; per reti neurali usa torch.save/model.save() (TF).
Aggiungi checksum o hash del file e della config per riproducibilità.
Debugging:
- stampa le top-n feature che “spingono” la predizione (es. coef_ di Logistic Regression) per audit.
- logga eccezioni con
exc_info=True, conserva input problematica in logs/bad_cases/.
🕖 Hardening & deploy
- Seed & determinismo: imposta random_state ovunque per esperimenti ripetibili.
- Config separata (
.yaml o .json) per parametri (feature, modello, soglie).
- Test: unit test su
preprocess e su un paio di casi attesi del modello.
Docker (opzionale):
# Dockerfile (minimal)
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "src.serve_api:app", "--host", "0.0.0.0", "--port", "8000"]
- Deploy: locale, VM, o PaaS (Railway/Render/Cloud Run). Esporre endpoint
/predict; proteggi con chiave API se pubblico.
🔬 Lab guidato: micro-AI end-to-end
- Importa dati (CSV) e fai lo split con stratificazione.
- Addestra baseline (testo: CountVectorizer+LR) e salva pesi.
- Valida su test e salva report e matrice di confusione (immagine/CSV).
- Servi il modello via API FastAPI e prova con
curl o Postman.
- Interfaccia Streamlit per demo; logga ogni richiesta.
- Itera: migliora preprocessing (stopword dominio-specifiche, n-grammi), confronta F1 e aggiorna versione (
v1.1.0).
🧭 Design dell’autonomia: validazione & fallback
Evenienza reale: la mini-AI deve “sapere dire non so”. Aggiungi un validatore e un fallback:
- Soglia di confidenza: se
confidence < 0.55 → restituisci “richiedi conferma” o inoltra a regola/operatore.
- Controlli di sicurezza: blocca input vuoti o troppo lunghi, rimuovi HTML/script.
- Audit: salva i low-confidence per active learning e migliorare il dataset in seguito.
📈 Miglioramenti successivi (opzionali)
- Text: TF-IDF, SVM, o DistilBERT (Hugging Face) con fine-tuning.
- Immagini: CLIP per embedding e nearest neighbor con caption semantiche.
- Decisioni: meta-policy: regole deterministiche + classificatore + spiegazioni (feature importanti) nel payload.
Commenti
Posta un commento