Apprendimento automatico per sviluppatori front-end con Tensorflow.js
Pubblicato: 2022-03-10L'apprendimento automatico spesso sembra appartenere al regno dei data scientist e degli sviluppatori Python. Tuttavia, negli ultimi due anni, sono stati creati framework open source per renderlo più accessibile in diversi linguaggi di programmazione, incluso JavaScript. In questo articolo, utilizzeremo Tensorflow.js per esplorare le diverse possibilità di utilizzo dell'apprendimento automatico nel browser attraverso alcuni progetti di esempio.
Che cos'è l'apprendimento automatico?
Prima di iniziare ad approfondire un po' di codice, parliamo brevemente di cos'è l'apprendimento automatico, nonché di alcuni concetti e terminologia di base.
Definizione
Una definizione comune è che è la capacità dei computer di apprendere dai dati senza essere programmati in modo esplicito.
Se lo confrontiamo con la programmazione tradizionale, significa che lasciamo che i computer identifichino schemi nei dati e generiamo previsioni senza che dobbiamo dirgli esattamente cosa cercare.
Prendiamo l'esempio del rilevamento delle frodi. Non ci sono criteri prestabiliti per sapere cosa rende una transazione fraudolenta o meno; le frodi possono essere eseguite in qualsiasi paese, con qualsiasi account, mirando a qualsiasi cliente, in qualsiasi momento e così via. Sarebbe praticamente impossibile tenere traccia di tutto questo manualmente.
Tuttavia, utilizzando i dati precedenti sulle spese fraudolente raccolti nel corso degli anni, possiamo addestrare un algoritmo di apprendimento automatico per comprendere i modelli in questi dati per generare un modello a cui può essere data qualsiasi nuova transazione e prevedere la probabilità che si tratti di una frode o meno, senza dicendogli esattamente cosa cercare.
Concetti principali
Per comprendere i seguenti esempi di codice, è necessario prima trattare alcuni termini comuni.
Modello
Quando si addestra un algoritmo di apprendimento automatico con un set di dati, il modello è l'output di questo processo di addestramento. È un po' come una funzione che prende nuovi dati come input e produce una previsione come output.
Etichette e caratteristiche
Le etichette e le funzionalità si riferiscono ai dati che fornisci a un algoritmo nel processo di addestramento.
Un'etichetta rappresenta il modo in cui classificheresti ogni voce nel tuo set di dati e come la etichetteresti. Ad esempio, se il nostro set di dati fosse un file CSV che descrive diversi animali, le nostre etichette potrebbero essere parole come "gatto", "cane" o "serpente" (a seconda di ciò che ciascun animale rappresenta).
Le caratteristiche d'altra parte, sono le caratteristiche di ogni voce nel tuo set di dati. Per i nostri animali, ad esempio, potrebbero essere cose come "baffi, miagolii", "giocosi, latrati", "rettile, rampante" e così via.
Utilizzando questo, un algoritmo di apprendimento automatico sarà in grado di trovare una correlazione tra le funzionalità e la loro etichetta che utilizzerà per le previsioni future.
Reti neurali
Le reti neurali sono un insieme di algoritmi di apprendimento automatico che cercano di imitare il modo in cui funziona il cervello utilizzando strati di neuroni artificiali.
Non abbiamo bisogno di approfondire il loro funzionamento in questo articolo, ma se vuoi saperne di più, ecco un video davvero buono:
Ora che abbiamo definito alcuni termini comunemente usati nell'apprendimento automatico, parliamo di cosa si può fare usando JavaScript e il framework Tensorflow.js.
Caratteristiche
Attualmente sono disponibili tre funzionalità:
- Utilizzando un modello pre-addestrato,
- Trasferisci l'apprendimento,
- Definizione, esecuzione e utilizzo del proprio modello.
Cominciamo con quello più semplice.
1. Utilizzo di un modello pre-addestrato
A seconda del problema che stai cercando di risolvere, potrebbe esserci un modello già addestrato con un set di dati specifico e per uno scopo specifico che puoi sfruttare e importare nel tuo codice.
Ad esempio, supponiamo che stiamo costruendo un sito Web per prevedere se un'immagine è l'immagine di un gatto. Un popolare modello di classificazione delle immagini si chiama MobileNet ed è disponibile come modello pre-addestrato con Tensorflow.js.
Il codice per questo sarebbe simile a questo:
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Cat detection</title> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]"> </script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]"> </script> </head> <body> <img alt="cat laying down" src="cat.jpeg"/> <script> const img = document.getElementById('image'); const predictImage = async () => { console.log("Model loading..."); const model = await mobilenet.load(); console.log("Model is loaded!") const predictions = await model.classify(img); console.log('Predictions: ', predictions); } predictImage(); </script> </body> </html>
Iniziamo importando Tensorflow.js e il modello MobileNet nell'intestazione del nostro HTML:
<script src="https://cdnjs.cloudflare.com/ajax/libs/tensorflow/1.0.1/tf.js"> </script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]"> </script>
Quindi, all'interno del corpo, abbiamo un elemento immagine che verrà utilizzato per le previsioni:
<img alt="cat laying down" src="cat.jpeg"/>
E infine, all'interno del tag script
, abbiamo il codice JavaScript che carica il modello MobileNet pre-addestrato e classifica l'immagine trovata nel tag image
. Restituisce una matrice di 3 previsioni ordinate in base al punteggio di probabilità (il primo elemento è la migliore previsione).
const predictImage = async () => { console.log("Model loading..."); const model = await mobilenet.load(); console.log("Model is loaded!") const predictions = await model.classify(img); console.log('Predictions: ', predictions); } predictImage();
E questo è tutto! Questo è il modo in cui puoi utilizzare un modello pre-addestrato nel browser con Tensorflow.js!
Nota : se vuoi dare un'occhiata a cos'altro può classificare il modello MobileNet, puoi trovare un elenco delle diverse classi disponibili su Github.
Una cosa importante da sapere è che il caricamento di un modello pre-addestrato nel browser può richiedere del tempo (a volte fino a 10 secondi), quindi probabilmente vorrai precaricare o adattare la tua interfaccia in modo che gli utenti non siano interessati.
Se preferisci utilizzare Tensorflow.js come modulo NPM, puoi farlo importando il modulo in questo modo:
import * as mobilenet from '@tensorflow-models/mobilenet';
Sentiti libero di giocare con questo esempio su CodeSandbox.
Ora che abbiamo visto come utilizzare un modello pre-addestrato, diamo un'occhiata alla seconda funzionalità disponibile: trasferire l'apprendimento.
2. Trasferisci l'apprendimento
Il trasferimento dell'apprendimento è la capacità di combinare un modello pre-addestrato con dati di addestramento personalizzati. Ciò significa che puoi sfruttare la funzionalità di un modello e aggiungere i tuoi campioni senza dover creare tutto da zero.
Ad esempio, un algoritmo è stato addestrato con migliaia di immagini per creare un modello di classificazione dell'immagine e, invece di crearne uno personalizzato, l'apprendimento del trasferimento consente di combinare nuovi campioni di immagini personalizzate con il modello pre-addestrato per creare un nuovo classificatore di immagini. Questa caratteristica rende davvero facile e veloce avere un classificatore più personalizzato.
Per fornire un esempio di come sarebbe nel codice, riproponiamo il nostro esempio precedente e lo modifichiamo in modo da poter classificare le nuove immagini.
Nota : il risultato finale è l'esperimento di seguito che puoi provare dal vivo qui.
Di seguito sono riportati alcuni esempi di codice della parte più importante di questa configurazione, ma se hai bisogno di dare un'occhiata all'intero codice, puoi trovarlo su questo CodeSandbox.
Dobbiamo ancora iniziare importando Tensorflow.js e MobileNet, ma questa volta dobbiamo anche aggiungere un classificatore KNN (k-nearest neighbor):
<!-- Load TensorFlow.js --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> <!-- Load MobileNet --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet"></script> <!-- Load KNN Classifier --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/knn-classifier"></script>
Il motivo per cui abbiamo bisogno di un classificatore è perché (invece di utilizzare solo il modulo MobileNet) stiamo aggiungendo campioni personalizzati mai visti prima, quindi il classificatore KNN ci consentirà di combinare tutto insieme ed eseguire previsioni sui dati combinati.
Quindi, possiamo sostituire l'immagine del gatto con un tag video
per utilizzare le immagini dal feed della fotocamera.
<video autoplay width="227" height="227"></video>
Infine, dovremo aggiungere alcuni pulsanti sulla pagina che utilizzeremo come etichette per registrare alcuni campioni di video e avviare le previsioni.
<section> <button class="button">Left</button> <button class="button">Right</button> <button class="test-predictions">Test</button> </section>
Ora, passiamo al file JavaScript da cui inizieremo impostando alcune variabili importanti:
// Number of classes to classify const NUM_CLASSES = 2; // Labels for our classes const classes = ["Left", "Right"]; // Webcam Image size. Must be 227. const IMAGE_SIZE = 227; // K value for KNN const TOPK = 10; const video = document.getElementById("webcam");
In questo esempio particolare, vogliamo essere in grado di classificare l'input della webcam tra la nostra testa inclinata a sinistra oa destra, quindi abbiamo bisogno di due classi etichettate left
e right
.
La dimensione dell'immagine impostata su 227 è la dimensione dell'elemento video in pixel. Sulla base degli esempi Tensorflow.js, questo valore deve essere impostato su 227 per corrispondere al formato dei dati con cui è stato addestrato il modello MobileNet. Per poter classificare i nostri nuovi dati, questi ultimi devono adattarsi allo stesso formato.
Se hai davvero bisogno che sia più grande, è possibile ma dovrai trasformare e ridimensionare i dati prima di inviarli al classificatore KNN.
Quindi, stiamo impostando il valore di K su 10. Il valore K nell'algoritmo KNN è importante perché rappresenta il numero di istanze che prendiamo in considerazione quando determiniamo la classe del nostro nuovo input.
In questo caso, il valore di 10 significa che, quando prevediamo l'etichetta per alcuni nuovi dati, esamineremo i 10 vicini più vicini dai dati di addestramento per determinare come classificare il nostro nuovo input.
Infine, stiamo ottenendo l'elemento video
. Per la logica, iniziamo caricando il modello e il classificatore:
async load() { const knn = knnClassifier.create(); const mobilenetModule = await mobilenet.load(); console.log("model loaded"); }
Quindi, accediamo al feed video:
navigator.mediaDevices .getUserMedia({ video: true, audio: false }) .then(stream => { video.srcObject = stream; video.width = IMAGE_SIZE; video.height = IMAGE_SIZE; });
Successivamente, impostiamo alcuni eventi dei pulsanti per registrare i nostri dati di esempio:
setupButtonEvents() { for (let i = 0; i < NUM_CLASSES; i++) { let button = document.getElementsByClassName("button")[i]; button.onmousedown = () => { this.training = i; this.recordSamples = true; }; button.onmouseup = () => (this.training = -1); } }
Scriviamo la nostra funzione che preleverà i campioni delle immagini della webcam, le riformatterà e le combinerà con il modulo MobileNet:
// Get image data from video element const image = tf.browser.fromPixels(video); let logits; // 'conv_preds' is the logits activation of MobileNet. const infer = () => this.mobilenetModule.infer(image, "conv_preds"); // Train class if one of the buttons is held down if (this.training != -1) { logits = infer(); // Add current image to classifier this.knn.addExample(logits, this.training); }
E infine, una volta raccolte alcune immagini della webcam, possiamo testare le nostre previsioni con il seguente codice:
logits = infer(); const res = await this.knn.predictClass(logits, TOPK); const prediction = classes[res.classIndex];
E infine, puoi smaltire i dati della webcam poiché non ne abbiamo più bisogno:
// Dispose image when done image.dispose(); if (logits != null) { logits.dispose(); }
Ancora una volta, se vuoi dare un'occhiata al codice completo, puoi trovarlo nel CodeSandbox menzionato in precedenza.
3. Addestrare un modello nel browser
L'ultima funzionalità consiste nel definire, addestrare ed eseguire un modello interamente nel browser. Per illustrare questo, costruiremo il classico esempio di riconoscimento delle iridi.
Per questo, creeremo una rete neurale in grado di classificare le iridi in tre categorie: Setosa, Virginica e Versicolor, sulla base di un set di dati open source.
Prima di iniziare, ecco un collegamento alla demo dal vivo ed ecco CodeSandbox se vuoi giocare con il codice completo.
Al centro di ogni progetto di machine learning c'è un set di dati. Uno dei primi passaggi che dobbiamo intraprendere è dividere questo set di dati in un set di addestramento e un set di test.
Il motivo è che useremo il nostro set di addestramento per addestrare il nostro algoritmo e il nostro set di test per verificare l'accuratezza delle nostre previsioni, per convalidare se il nostro modello è pronto per essere utilizzato o deve essere modificato.
Nota : per semplificare, ho già diviso il set di allenamento e il set di test in due file JSON che puoi trovare in CodeSanbox.
Il set di allenamento contiene 130 elementi e il set di test 14. Se dai un'occhiata all'aspetto di questi dati, vedrai qualcosa del genere:
{ "sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2, "species": "setosa" }
Ciò che possiamo vedere sono quattro diverse caratteristiche per la lunghezza e la larghezza del sepalo e del petalo, nonché un'etichetta per la specie.
Per poterlo utilizzare con Tensorflow.js, dobbiamo modellare questi dati in un formato che il framework capirà, in questo caso, per i dati di addestramento, sarà [130, 4]
per 130 campioni con quattro caratteristiche per iris.
import * as trainingSet from "training.json"; import * as testSet from "testing.json"; const trainingData = tf.tensor2d( trainingSet.map(item => [ item.sepal_length, item.sepal_width, item.petal_length, item.petal_width ]), [130, 4] ); const testData = tf.tensor2d( testSet.map(item => [ item.sepal_length, item.sepal_width, item.petal_length, item.petal_width ]), [14, 4] );
Successivamente, dobbiamo modellare anche i nostri dati di output:
const output = tf.tensor2d(trainingSet.map(item => [ item.species === 'setosa' ? 1 : 0, item.species === 'virginica' ? 1 : 0, item.species === 'versicolor' ? 1 : 0 ]), [130,3])
Quindi, una volta che i nostri dati sono pronti, possiamo passare alla creazione del modello:
const model = tf.sequential(); model.add(tf.layers.dense( { inputShape: 4, activation: 'sigmoid', units: 10 } )); model.add(tf.layers.dense( { inputShape: 10, units: 3, activation: 'softmax' } ));
Nell'esempio di codice sopra, iniziamo creando un'istanza di un modello sequenziale, aggiungendo un livello di input e output.
I parametri che puoi vedere utilizzati all'interno ( inputShape
, activation
e units
) non rientrano nell'ambito di questo post in quanto possono variare a seconda del modello che stai creando, del tipo di dati utilizzati e così via.
Una volta che il nostro modello è pronto, possiamo addestrarlo con i nostri dati:
async function train_data(){ for(let i=0;i<15;i++){ const res = await model.fit(trainingData, outputData,{epochs: 40}); } } async function main() { await train_data(); model.predict(testSet).print(); }
Se funziona bene, puoi iniziare a sostituire i dati di test con input utente personalizzati.
Una volta chiamata la nostra funzione principale, l'output della previsione apparirà come una di queste tre opzioni:
[1,0,0] // Setosa [0,1,0] // Virginica [0,0,1] // Versicolor
La previsione restituisce una matrice di tre numeri che rappresentano la probabilità dei dati appartenenti a una delle tre classi. Il numero più vicino a 1 è la previsione più alta.
Ad esempio, se l'output della classificazione è [0.0002, 0.9494, 0.0503]
, il secondo elemento dell'array è il più alto, quindi il modello prevedeva che il nuovo input sarebbe probabilmente un Virginica.
E questo è tutto per una semplice rete neurale in Tensorflow.js!
Abbiamo parlato solo di un piccolo set di dati di Irises ma se vuoi passare a set di dati più grandi o lavorare con le immagini, i passaggi saranno gli stessi:
- Raccolta dei dati;
- Divisione tra set di formazione e test;
- Riformattare i dati in modo che Tensorflow.js possa capirli;
- Scegli il tuo algoritmo;
- Adattamento dei dati;
- Prevedere.
Se vuoi salvare il modello creato per poterlo caricare in un'altra applicazione e prevedere nuovi dati, puoi farlo con la seguente riga:
await model.save('file:///path/to/my-model'); // in Node.js
Nota : per ulteriori opzioni su come salvare un modello, dai un'occhiata a questa risorsa.
Limiti
Questo è tutto! Abbiamo appena coperto le tre funzionalità principali attualmente disponibili utilizzando Tensorflow.js!
Prima di finire, penso che sia importante menzionare brevemente alcuni dei limiti dell'utilizzo dell'apprendimento automatico nel frontend.
1. Prestazioni
L'importazione di un modello pre-addestrato da un'origine esterna può avere un impatto sulle prestazioni dell'applicazione. Alcuni modelli di rilevamento degli oggetti, ad esempio, superano i 10 MB, il che rallenterà notevolmente il tuo sito web. Assicurati di pensare alla tua esperienza utente e ottimizza il caricamento delle tue risorse per migliorare le tue prestazioni percepite.
2. Qualità dei dati di input
Se crei un modello da zero, dovrai raccogliere i tuoi dati o trovare un set di dati open source.
Prima di eseguire qualsiasi tipo di elaborazione dei dati o provare diversi algoritmi, assicurati di controllare la qualità dei dati di input. Ad esempio, se stai cercando di costruire un modello di analisi del sentimento per riconoscere le emozioni in parti di testo, assicurati che i dati che stai utilizzando per addestrare il tuo modello siano accurati e diversificati. Se la qualità dei dati utilizzati è bassa, l'output della tua formazione sarà inutile.
3. Responsabilità
L'utilizzo di un modello pre-addestrato open source può essere molto veloce e semplice. Tuttavia, significa anche che non sempre sai come è stato generato, di cosa è fatto il set di dati o anche quale algoritmo è stato utilizzato. Alcuni modelli sono chiamati "scatole nere", il che significa che non sai davvero come hanno previsto un determinato output.
A seconda di ciò che stai cercando di costruire, questo può essere un problema. Ad esempio, se stai utilizzando un modello di apprendimento automatico per rilevare la probabilità che qualcuno abbia il cancro in base alle immagini di scansione, in caso di falso negativo (il modello prevedeva che una persona non avesse il cancro quando effettivamente lo aveva), lì potrebbe essere una vera responsabilità legale e dovresti essere in grado di spiegare perché il modello ha fatto una certa previsione.
Sommario
In conclusione, l'utilizzo di JavaScript e framework come Tensorflow.js è un ottimo modo per iniziare e saperne di più sull'apprendimento automatico. Anche se un'applicazione pronta per la produzione dovrebbe probabilmente essere costruita in un linguaggio come Python, JavaScript rende davvero accessibile agli sviluppatori la possibilità di giocare con le diverse funzionalità e ottenere una migliore comprensione dei concetti fondamentali prima di andare avanti e investire tempo nell'apprendimento di un altro linguaggio.
In questo tutorial, abbiamo coperto solo ciò che era possibile utilizzare Tensorflow.js, tuttavia, l'ecosistema di altre librerie e strumenti sta crescendo. Sono inoltre disponibili framework più specifici, che consentono di esplorare utilizzando l'apprendimento automatico con altri domini come la musica con Magenta.js o prevedere la navigazione dell'utente su un sito Web utilizzando guess.js!
Man mano che gli strumenti diventano più performanti, è probabile che le possibilità di creare applicazioni abilitate per l'apprendimento automatico in JavaScript diventino sempre più interessanti e ora è un buon momento per saperne di più, poiché la comunità si sta impegnando per renderlo accessibile.
Ulteriori risorse
Se sei interessato a saperne di più, ecco alcune risorse:
Altri framework e strumenti
- ml5.js
- ml.js
- brain.js
- Keras.js
- PoseNet
- Parco giochi Tensorflow
Esempi, modelli e set di dati
- Modelli Tensorflow.js
- Esempi di Tensorflow.js
- Set di dati
Ispirazione
- Macchina insegnabile
- Esperimenti di intelligenza artificiale
- AIJS.rocks
- Creabilità
Grazie per aver letto!