16 KiB
Costruire un'App Web per Consigliare una Cucina
In questa lezione si creerà un modello di classificazione utilizzando alcune delle tecniche apprese nelle lezioni precedenti e con il delizioso insieme di dati sulla cucina utilizzato in questa serie. Inoltre, si creerà una piccola app web per utilizzare un modello salvato, sfruttando il runtime web di Onnx.
Uno degli usi pratici più utili dell'apprendimento automatico è la creazione di sistemi di raccomandazione e oggi si può fare il primo passo in quella direzione!
🎥 Fare clic sull'immagine sopra per un video
Quiz pre-lezione
In questa lezione, si imparerà:
- Come costruire un modello e salvarlo come modello Onnx
- Come usare Netron per ispezionare il modello
- Come utilizzare il modello in un'app web per l'inferenza
Costruire il modello
La creazione di sistemi ML applicati è una parte importante dell'utilizzo di queste tecnologie per i sistemi aziendali. Si possono utilizzare i modelli all'interno delle proprie applicazioni web (e quindi utilizzarli in un contesto offline se necessario) utilizzando Onnx.
In una lezione precedente si è costruito un modello di regressione sugli avvistamenti di UFO, è stato serializzato e lo si è utilizzato in un'app Flask. Sebbene questa architettura sia molto utile da conoscere, è un'app Python completa e i requisiti potrebbero includere l'uso di un'applicazione JavaScript.
In questa lezione si può creare un sistema di inferenza di base utilizzando JavaScript. Prima, tuttavia, è necessario addestrare un modello e convertirlo per l'utilizzo con Onnx.
Esercizio - modello di classificazione di addestramento
Innanzitutto, addestrare un modello di classificazione utilizzando l'insieme di dati pulito delle cucine precedentemente usato.
-
Iniziare importando librerie utili:
!pip install skl2onnx import pandas as pd
Serve 'skl2onnx' per poter convertire il modello di Scikit-learn in formato Onnx.
-
Quindi si lavora con i dati nello stesso modo delle lezioni precedenti, leggendo un file CSV usando
read_csv()
:data = pd.read_csv('../data/cleaned_cuisine.csv') data.head()
-
Rimuovere le prime due colonne non necessarie e salvare i dati rimanenti come "X":
X = data.iloc[:,2:] X.head()
-
Salvare le etichette come "y":
y = data[['cuisine']] y.head()
Iniziare la routine di addestramento
Verrà usata la libreria 'SVC' che ha una buona precisione.
-
Importare le librerie appropriate da Scikit-learn:
from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.model_selection import cross_val_score from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report
-
Separare gli insiemi di allenamento e test:
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3)
-
Costruire un modello di classificazione SVC come fatto nella lezione precedente:
model = SVC(kernel='linear', C=10, probability=True,random_state=0) model.fit(X_train,y_train.values.ravel())
-
Ora provare il modello, chiamando
predict()
:y_pred = model.predict(X_test)
-
Stampare un rapporto di classificazione per verificare la qualità del modello:
print(classification_report(y_test,y_pred))
Come visto prima, la precisione è buona:
precision recall f1-score support chinese 0.72 0.69 0.70 257 indian 0.91 0.87 0.89 243 japanese 0.79 0.77 0.78 239 korean 0.83 0.79 0.81 236 thai 0.72 0.84 0.78 224 accuracy 0.79 1199 macro avg 0.79 0.79 0.79 1199 weighted avg 0.79 0.79 0.79 1199
Convertire il modello in Onnx
Assicurarsi di eseguire la conversione con il numero tensore corretto. Questo insieme di dati ha 380 ingredienti elencati, quindi è necessario annotare quel numero in FloatTensorType
:
-
Convertire usando un numero tensore di 380.
from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType initial_type = [('float_input', FloatTensorType([None, 380]))] options = {id(model): {'nocl': True, 'zipmap': False}}
-
Creare l'onx e salvarlo come file model.onnx:
onx = convert_sklearn(model, initial_types=initial_type, options=options) with open("./model.onnx", "wb") as f: f.write(onx.SerializeToString())
Nota, si possono passare leopzioni nello script di conversione. In questo caso, si è passato 'nocl' come True e 'zipmap' come False. Poiché questo è un modello di classificazione, si ha la possibilità di rimuovere ZipMap che produce un elenco di dizionari (non necessario).
nocl
si riferisce alle informazioni sulla classe incluse nel modello. Ridurre le dimensioni del modello impostandonocl
su 'True'.
L'esecuzione dell'intero notebook ora creerà un modello Onnx e lo salverà in questa cartella.
Visualizzare il modello
I modelli Onnx non sono molto visualizzabili in Visual Studio code, ma c'è un ottimo software gratuito che molti ricercatori usano per visualizzare il modello per assicurarsi che sia costruito correttamente. Scaricare Netron e aprire il file model.onnx. Si può vedere il modello semplice visualizzato, con i suoi 380 input e classificatore elencati:
Netron è uno strumento utile per visualizzare i modelli.
Ora si è pronti per utilizzare questo modello accurato in un'app web. Si costruisce un'app che tornerà utile quando si guarda nel frigorifero e si prova a capire quale combinazione di ingredienti avanzati si può usare per cucinare una determinata tipologia di cucina, come determinato dal modello.
Creare un'applicazione web di raccomandazione
Si può utilizzare il modello direttamente in un'app web. Questa architettura consente anche di eseguirlo localmente e anche offline se necessario. Iniziare creando un file index.html
nella stessa cartella in cui si è salvato il file model.onnx
.
-
In questo file index.html, aggiungere il seguente codice markup:
<!DOCTYPE html> <html> <header> <title>Cuisine Matcher</title> </header> <body> ... </body> </html>
-
Ora, lavorando all'interno del tag
body
, aggiungere un piccolo markup per mostrare un elenco di caselle di controllo che riflettono alcuni ingredienti:<h1>Check your refrigerator. What can you create?</h1> <div id="wrapper"> <div class="boxCont"> <input type="checkbox" value="4" class="checkbox"> <label>apple</label> </div> <div class="boxCont"> <input type="checkbox" value="247" class="checkbox"> <label>pear</label> </div> <div class="boxCont"> <input type="checkbox" value="77" class="checkbox"> <label>cherry</label> </div> <div class="boxCont"> <input type="checkbox" value="126" class="checkbox"> <label>fenugreek</label> </div> <div class="boxCont"> <input type="checkbox" value="302" class="checkbox"> <label>sake</label> </div> <div class="boxCont"> <input type="checkbox" value="327" class="checkbox"> <label>soy sauce</label> </div> <div class="boxCont"> <input type="checkbox" value="112" class="checkbox"> <label>cumin</label> </div> </div> <div style="padding-top:10px"> <button onClick="startInference()">What kind of cuisine can you make?</button> </div>
Notare che a ogni casella di controllo viene assegnato un valore. Questo riflette l'indice in cui si trova l'ingrediente in base all'insieme di dati. Apple, ad esempio, in questo elenco alfabetico, occupa la quinta colonna, quindi il suo valore è "4" poiché si inizia a contare da 0. Si può consultare il foglio di calcolo degli ingredienti per scoprire l'indice di un determinato ingrediente.
Continuando il lavoro nel file index.html, aggiungere un blocco di script in cui viene chiamato il modello dopo la chiusura del tag
</div>
finale. -
Innanzitutto, importare il runtime Onnx:
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.8.0-dev.20210608.0/dist/ort.min.js"></script>
Onnx Runtime viene utilizzato per consentire l'esecuzione dei modelli Onnx su un'ampia gamma di piattaforme hardware, comprese le ottimizzazioni e un'API da utilizzare.
-
Una volta che il Runtime è a posto, lo si può chiamare:
<script> const ingredients = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] const checks = [].slice.call(document.querySelectorAll('.checkbox')); // use an async context to call onnxruntime functions. function init() { checks.forEach(function (checkbox, index) { checkbox.onchange = function () { if (this.checked) { var index = checkbox.value; if (index !== -1) { ingredients[index] = 1; } console.log(ingredients) } else { var index = checkbox.value; if (index !== -1) { ingredients[index] = 0; } console.log(ingredients) } } }) } function testCheckboxes() { for (var i = 0; i < checks.length; i++) if (checks[i].type == "checkbox") if (checks[i].checked) return true; return false; } async function startInference() { let checked = testCheckboxes() if (checked) { try { // create a new session and load the model. const session = await ort.InferenceSession.create('./model.onnx'); const input = new ort.Tensor(new Float32Array(ingredients), [1, 380]); const feeds = { float_input: input }; // feed inputs and run const results = await session.run(feeds); // read from results alert('You can enjoy ' + results.label.data[0] + ' cuisine today!') } catch (e) { console.log(`failed to inference ONNX model: ${e}.`); } } else alert("Please check an ingredient") } init(); </script>
In questo codice, accadono diverse cose:
- Si è creato un array di 380 possibili valori (1 o 0) da impostare e inviare al modello per l'inferenza, a seconda che una casella di controllo dell'ingrediente sia selezionata.
- Si è creata una serie di caselle di controllo e un modo per determinare se sono state selezionate in una funzione
init
chiamata all'avvio dell'applicazione. Quando una casella di controllo è selezionata, l 'arrayingredients
viene modificato per riflettere l'ingrediente scelto. - Si è creata una funzione
testCheckboxes
che controlla se una casella di controllo è stata selezionata. - Si utilizza quella funzione quando si preme il pulsante e, se una casella di controllo è selezionata, si avvia l'inferenza.
- La routine di inferenza include:
- Impostazione di un caricamento asincrono del modello
- Creazione di una struttura tensoriale da inviare al modello
- Creazione di "feed" che riflettano l'input
float_input
creato durante l'addestramento del modello (si può usare Netron per verificare quel nome) - Invio di questi "feed" al modello e attesa di una risposta
Verificare l'applicazione
Aprire una sessione terminale in Visual Studio Code nella cartella in cui risiede il file index.html. Assicurarsi di avere http-server installato globalmente e digitare http-server
al prompt. Dovrebbe aprirsi nel browser un localhost e si può visualizzare l'app web. Controllare quale cucina è consigliata in base ai vari ingredienti:
Congratulazioni, si è creato un'app web di "raccomandazione" con pochi campi. Si prenda del tempo per costruire questo sistema!
🚀 Sfida
L'app web è molto minimale, quindi continuare a costruirla usando gli ingredienti e i loro indici dai dati ingredient_indexes . Quali combinazioni di sapori funzionano per creare un determinato piatto nazionale?
Quiz post-lezione
Revisione e Auto Apprendimento
Sebbene questa lezione abbia appena toccato l'utilità di creare un sistema di raccomandazione per gli ingredienti alimentari, quest'area delle applicazioni ML è molto ricca di esempi. Leggere di più su come sono costruiti questi sistemi:
- https://www.sciencedirect.com/topics/computer-science/recommendation-engine
- https://www.technologyreview.com/2014/08/25/171547/the-ultimate-challenge-for-recommendation-engines/
- https://www.technologyreview.com/2015/03/23/168831/everything-is-a-recommendation/