Formattazione dei dati per TensorFlow
La parte 1 di questa serie di blog ha dimostrato i vantaggi dell'utilizzo di un database relazionale per archiviare ed eseguire l'esplorazione dei dati di immagini utilizzando semplici istruzioni SQL. In questo tutorial, parte 2, si accederà ai dati utilizzati nella prima parte da un database MariaDB Server e convertiti nelle strutture dati necessarie a TensorFlow. I risultati dell'applicazione del modello per classificare nuove immagini verranno archiviati in una tabella relazionale per ulteriori analisi.
Questo è un breve tutorial di un programma TensorFlow con i dettagli descritti mentre procediamo. Se non hai familiarità con i concetti di base, un buon punto di partenza è questo tutorial di TensorFlow, "Classificazione di base:classifica le immagini di abbigliamento". Alcuni degli esempi e del codice nel tutorial vengono utilizzati qui.
Sono necessari pacchetti aggiuntivi
Sono necessari alcuni pacchetti aggiuntivi per creare e addestrare il modello di classificazione delle immagini:
- Sottaceto implementa protocolli binari per serializzare e deserializzare una struttura di oggetti Python.
- NumPy fornisce supporto per matrici e matrici multidimensionali di grandi dimensioni, insieme a funzioni matematiche di alto livello per operare su queste matrici.
- Flusso tensore è una libreria Python per il calcolo numerico veloce. È una libreria di base che può essere utilizzata per creare modelli di Deep Learning direttamente o utilizzando librerie wrapper che semplificano il processo basato su TensorFlow.
- Kera è una libreria di rete neurale open source scritta in Python.
import pickle import numpy as np import tensorflow as tf from tensorflow import keras print('Tensorflow version: ', tf.__version__) print('Numpy version: ', np.__version__) Tensorflow version: 2.0.0 Numpy version: 1.16.2
Recupera immagini
Una volta importati i pacchetti, il passaggio successivo consiste nel recuperare le immagini di addestramento dal database e dividere i dati in due numpy matrici. Innanzitutto, è necessario inizializzare gli array delle immagini di addestramento (train_images) e delle etichette di addestramento (train_labels). Poiché abbiamo già vettorizzato le immagini, possiamo utilizzare l'attributo img_vector per popolare l'array train_images con l'istruzione SQL di seguito.
# Initialize the numpy arrays train_images = np.empty((60000,28,28), dtype='uint8') train_labels = np.empty((60000), dtype='uint8') # Retrieve the training images from the database sql="SELECT img_label, img_vector, img_idx \ FROM tf_images INNER JOIN img_use ON img_use = use_id \ WHERE use_name = 'Training'" cur.execute(sql) result = cur.fetchall() # Populate the numpy arrays. row[2] contains the image index for row in result: nparray = pickle.loads(row[1]) train_images[row[2]] = nparray train_labels[row[2]] = row[0]
In modo simile, le immagini per il test possono essere recuperate dal database. Il insensibile gli array usati in questo caso sono test_images e test_labels. In questo caso, i dati del test sono 10.000 immagini con una risoluzione di 28×28 pixel.
# Initialize the numpy arrays test_images = np.empty((10000,28,28), dtype='uint8') test_labels = np.empty((10000), dtype='uint8') # Retrieve the testing images from the database sql="SELECT img_label, img_vector, img_idx \ FROM tf_images INNER JOIN img_use ON img_use = use_id \ WHERE use_name = 'Testing'" cur.execute(sql) result = cur.fetchall() # Populate the numpy arrays. row[2] contains the image index for row in result: nparray = pickle.loads(row[1]) test_images[row[2]] = nparray test_labels[row[2]] = row[0]
Infine, ogni immagine viene mappata su una singola etichetta. I nomi delle etichette vengono archiviati nella tabella delle categorie e caricati nell'array class_names:
sql="SELECT class_name FROM categories" cur.execute(sql) class_names = cur.fetchall()
Preelabora i dati
I dati devono essere preelaborati prima dell'addestramento della rete. Se esamini la prima immagine nel set di addestramento, vedrai che i valori dei pixel rientrano nell'intervallo da 0 a 255:
plt.figure() plt.imshow(train_images[0]) plt.colorbar() plt.grid(False) plt.show()
sopra:immagine dal set di dati fashion_mnist
Prima di inviare le immagini al modello di rete neurale, i valori devono essere ridimensionati in un intervallo da 0 a 1. A tale scopo, dividi i valori per 255. È importante che il set di addestramento e il set di test siano preelaborati allo stesso modo .
Puoi usare matplotlib per visualizzare le prime 25 immagini per verificare che i dati siano nel formato corretto e pronti per costruire e addestrare la rete:
train_images = train_images / 255.0 test_images = test_images / 255.0 plt.figure(figsize=(10,10)) for i in range(25): plt.subplot(5,5,i+1) plt.xticks([]) plt.yticks([]) plt.grid(False) plt.imshow(train_images[i], cmap=plt.cm.binary) plt.xlabel(class_names[train_labels[i]]) plt.show()
sopra:immagini dal set di dati fashion_mnist
Costruire il modello
Dopo che i dati sono stati preelaborati in due sottoinsiemi, è possibile procedere con un training del modello. Questo processo comporta "alimentare" l'algoritmo con i dati di addestramento. L'algoritmo elaborerà i dati e produrrà un modello in grado di trovare un valore target (attributo) in nuovi dati, ovvero classificare l'immagine presentata alla rete neurale.
La maggior parte delle reti neurali di deep learning sono prodotte concatenando insieme livelli semplici.
Il primo livello nella rete trasforma il formato dell'immagine da una matrice bidimensionale (di 28 x 28 pixel) a una matrice unidimensionale (di 28 * 28 =784 pixel). Questo livello non ha parametri da apprendere; riformatta solo i dati.
Dopo che i pixel sono stati appiattiti, la rete è composta da due livelli completamente collegati che devono essere attivati. In una rete neurale, la funzione di attivazione è responsabile della trasformazione dell'input ponderato sommato dal nodo nell'attivazione del nodo o dell'output per quell'input.
Il primo strato denso ha 128 nodi (o neuroni) e utilizza un metodo di attivazione dell'unità lineare rettificata (ReLU). La funzione di attivazione lineare rettificata è una funzione lineare a tratti che emetterà direttamente l'input se è positivo, altrimenti emetterà zero.
Il secondo (e ultimo) livello è un livello softmax a 10 nodi. Una funzione softmax genera un vettore che rappresenta le distribuzioni di probabilità di un elenco di potenziali risultati. Restituisce una matrice di 10 punteggi di probabilità che si sommano a 1. Ciascun nodo contiene un punteggio che indica la probabilità che l'immagine corrente appartenga a una delle 10 classi.
La maggior parte dei livelli, come tf.keras.layers.Dense, ha parametri che vengono appresi durante l'allenamento.
model = keras.Sequential([ keras.layers.Flatten(input_shape=(28, 28)), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(10, activation='softmax') ])
Compilazione del modello
Il passaggio di compilazione del modello viene utilizzato per aggiungere alcune altre impostazioni prima che sia pronto per l'addestramento. In questo caso, sono abilitate le seguenti impostazioni.
- Ottimizzatore:aggiorna il modello in base ai dati che vede e alla relativa funzione di perdita (vedi sotto).
- Funzione di perdita:misura la precisione del modello durante l'allenamento. Vuoi ridurre al minimo questa funzione per "orientare" il modello nella giusta direzione.
- Metriche:monitora le fasi di addestramento e test. L'esempio seguente utilizza l'accuratezza, la frazione delle immagini classificate correttamente.
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
Formazione del modello
L'addestramento del modello di rete neurale richiede i seguenti passaggi.
- Invia i dati di addestramento al modello.
- Il modello impara ad associare immagini ed etichette.
- Fai previsioni su un set di test.
- Verifica che le previsioni corrispondano alle etichette dell'array test_labels.
Per iniziare l'addestramento, chiama il metodo model.fit, così chiamato perché "adatta" il modello ai dati di addestramento:
model.fit(train_images, train_labels, epochs=10) Train on 60000 samples Epoch 1/10 60000/60000 [==============================] - 5s 83us/sample - loss: 0.4964 - accuracy: 0.8236 Epoch 2/10 60000/60000 [==============================] - 4s 65us/sample - loss: 0.3735 - accuracy: 0.8642 Epoch 3/10 60000/60000 [==============================] - 3s 55us/sample - loss: 0.3347 - accuracy: 0.8773 Epoch 4/10 60000/60000 [==============================] - 3s 56us/sample - loss: 0.3106 - accuracy: 0.8861 Epoch 5/10 60000/60000 [==============================] - 3s 58us/sample - loss: 0.2921 - accuracy: 0.8924s - loss: 0.2928 - accura - ETA: 0s - loss: 0.2925 - accuracy Epoch 6/10 60000/60000 [==============================] - 3s 57us/sample - loss: 0.2796 - accuracy: 0.8969s Epoch 7/10 60000/60000 [==============================] - 4s 70us/sample - loss: 0.2659 - accuracy: 0.9007 Epoch 8/10 60000/60000 [==============================] - 4s 61us/sample - loss: 0.2548 - accuracy: 0.9042 Epoch 9/10 60000/60000 [==============================] - 4s 61us/sample - loss: 0.2449 - accuracy: 0.9084 Epoch 10/10 60000/60000 [==============================] - 5s 76us/sample - loss: 0.2358 - accuracy: 0.9118
Alla fine di ogni epoca, la rete neurale viene valutata rispetto al set di convalida. Questo è ciò a cui si riferiscono la perdita e l'accuratezza.
Valutare l'accuratezza e prevedere
Per stimare l'accuratezza complessiva del modello, calcola la media di tutte e dieci le occorrenze del valore di accuratezza, in questo caso l'88%.
Quindi esegui model.evaluate sul set di test per ottenere l'accuratezza predittiva della rete neurale addestrata su dati non visti in precedenza.
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) 10000/1 - 0s - loss: 0.2766 - accuracy: 0.8740
Il set di dati di test è meno accurato del set di dati di addestramento. In questo caso, questo divario tra l'accuratezza dell'allenamento e l'accuratezza del test rappresenta un overfitting. Il contrario è inadeguato. Se vuoi saperne di più su questo argomento, ti consiglio Overfitting vs. Underfitting:A Conceptual Explanation di Will Koehrsen.
A questo punto, possiamo fare alcune previsioni sulle immagini nel nostro set di dati di allenamento.
predictions = model.predict(test_images) predictions[0] array([1.90860412e-08, 8.05085235e-11, 1.56402713e-08, 1.66699390e-10, 7.86950158e-11, 4.33062996e-06, 2.49049066e-08, 1.20656565e-02, 3.80084719e-09, 9.87929940e-01], dtype=float32)
L'output di model.predict è un array di 10 numeri con la probabilità di un'istanza appartenente a ciascuna classe. È una buona idea mantenere i risultati nel database MariaDB per ulteriori analisi e rapporti. Di seguito è riportato un esempio di come eseguire un'iterazione sull'array delle previsioni per creare una tupla e quindi inserirla in prediction_results tabella.
sql = "INSERT INTO prediction_results ( img_idx , img_use , T_shirt_Top , Trouser , Pullover , Dress , Coat , Sandal , Shirt , Sneaker , Bag , Ankle_boot , label) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" i = 0 for row in predictions: insert_tuple = (str(i), str(2) , str(row[0]), str(row[1]), str(row[2]), str(row[3]), str(row[4]) , str(row[5]), str(row[6]), str(row[7]), str(row[8]), str(row[9]) , str(test_labels[i])) cur.execute(sql, insert_tuple) conn.commit() i += 1
Ancora una volta, è possibile utilizzare una semplice istruzione SQL per verificare che i dati siano stati caricati.
sql = "SELECT T_shirt_Top , Trouser , Pullover , Dress , Coat , Sandal , Shirt , Sneaker , Bag , Ankle_boot , class_name as 'Test Label' FROM prediction_results JOIN categories ON label = class_idx WHERE img_idx = 1" display( pd.read_sql(sql,conn) )
T_shirt_Top | Pantaloni | Pullover | Vestito | Cappotto | Sandalo | Camicia | Scarpe da ginnastica | Borsa | Stivaletti_alla caviglia | Etichetta di prova |
0,00001 | 0.0 | 0,997912 | 0.0 | 0,001267 | 0.0 | 0,00081 | 0.0 | 0.0 | 0.0 | Pullover |
Previsioni di tracciamento
Di seguito sono definite un paio di funzioni di stampa per visualizzare le previsioni (Funzioni di rappresentazione grafica).
Recuperiamo una nuova immagine dal set di test e visualizziamo la classificazione della rete neurale in base alla probabilità di previsione.
sql = "SELECT img_idx, label FROM prediction_results WHERE img_idx = 1" cur.execute(sql) result = cur.fetchone() plt.figure(figsize=(6,3)) plt.subplot(1,2,1) plot_image(result[0], predictions[result[0]], test_labels, test_images) plt.subplot(1,2,2) plot_value_array(result[0], predictions[result[0]], test_labels) plt.show()
sopra:immagine dal set di dati fashion_mnist
In questo caso, il modello è stato in grado di classificare correttamente l'immagine con una precisione del 100%. Quindi eseguiamo una query per recuperare le prime 15 immagini dal set di test e classificarle.
sql = "SELECT img_idx, label FROM prediction_results LIMIT 15" num_rows = 5 num_cols = 3 plt.figure(figsize=(2*2*num_cols, 2*num_rows)) cur.execute(sql) result = cur.fetchall() for row in result: plt.subplot(num_rows, 2*num_cols, 2*row[0]+1) plot_image(row[0], predictions[row[0]], test_labels, test_images) plt.subplot(num_rows, 2*num_cols, 2*row[0]+2) plot_value_array(row[0], predictions[row[0]], test_labels) plt.tight_layout() plt.show()
sopra:immagini dal set di dati fashion_mnist
Come puoi vedere, ci saranno casi in cui il modello può essere sbagliato come mostrato nell'ultima riga, colonna di sinistra. In questo caso, una sneaker è stata classificata come un sandalo (in rosso).
In sintesi
Sebbene l'integrazione tra TensorFlow e MariaDB Server sia semplice, i vantaggi di questa integrazione sono sostanziali:
- L'uso di dati relazionali all'interno dell'apprendimento automatico può ridurre la complessità dell'implementazione. Sia i data scientist che i data engineer possono utilizzare un linguaggio comune per eseguire attività di esplorazione ed esplorazione dei dati.
- L'efficienza ottenuta durante l'accesso, l'aggiornamento, l'inserimento, la manipolazione e la modifica dei dati può accelerare il time-to-market.
- La possibilità di archiviare i risultati del modello nel database consente agli utenti finali e agli analisti di eseguire query e report utilizzando strumenti di reporting intuitivi come Tableau.
Licenza MIT
Il set di dati Fashion MNIST (fashion_mnist) sfruttato da questo blog è concesso in licenza con licenza MIT, Copyright © 2017 Zalando SE, https://tech.zalando.com
Il codice sorgente sfruttato da questo blog è adattato dal tutorial "Classificazione di base:classifica le immagini di abbigliamento" concesso in licenza con licenza MIT, Copyright (c) 2017 François Chollet.
Si concede il permesso, gratuitamente, a chiunque ottenga una copia di questo software e dei file di documentazione associati (il "Software"), di trattare il Software senza restrizioni, inclusi senza limitazione i diritti di utilizzare, copiare, modificare, unire , pubblicare, distribuire, concedere in sublicenza e/o vendere copie del Software e consentire alle persone a cui viene fornito il Software di farlo, alle seguenti condizioni:
L'avviso di copyright di cui sopra e questo avviso di autorizzazione devono essere inclusi in tutte le copie o parti sostanziali del Software.
IL SOFTWARE VIENE FORNITO "COSÌ COM'È", SENZA ALCUN TIPO DI GARANZIA, ESPRESSA O IMPLICITA, INCLUSE MA NON LIMITATE ALLE GARANZIE DI COMMERCIABILITÀ, IDONEITÀ PER UNO SCOPO PARTICOLARE E NON VIOLAZIONE. IN NESSUN CASO GLI AUTORI O I TITOLARI DEL COPYRIGHT SARANNO RESPONSABILI PER ALCUN RECLAMO, DANNO O ALTRA RESPONSABILITÀ, SIA IN UN'AZIONE CONTRATTUALE, ILLECITO O ALTRO, DERIVANTE DA, DERIVANTE DA O IN COLLEGAMENTO CON IL SOFTWARE O L'UTILIZZO O ALTRI CONTRATTI NEL SOFTWARE.
Riferimenti
Converti la propria immagine nell'immagine di MNIST
matplotlib:tutorial sull'immagine
5 modi in cui l'IA sta trasformando l'esperienza del cliente
La digitalizzazione sta reinventando il business
Cos'è la classificazione delle immagini?
Introduzione a Python Libreria di Deep Learning TensorFlow
Funzioni grafiche
def plot_image(i, predictions_array, true_label, img): predictions_array, true_label, img = predictions_array, true_label[i], img[i] plt.grid(False) plt.xticks([]) plt.yticks([]) plt.imshow(img, cmap=plt.cm.binary) predicted_label = np.argmax(predictions_array) if predicted_label == true_label: color = 'blue' else: color = 'red' plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label], 100*np.max(predictions_array), class_names[true_label]), color=color) def plot_value_array(i, predictions_array, true_label): predictions_array, true_label = predictions_array, true_label[i] plt.grid(False) plt.xticks(range(10)) plt.yticks([]) thisplot = plt.bar(range(10), predictions_array, color="#777777") plt.ylim([0, 1]) predicted_label = np.argmax(predictions_array) thisplot[predicted_label].set_color('red') thisplot[true_label].set_color('blue')