De gegevens voor TensorFlow formatteren
Deel 1 van deze blogserie demonstreerde de voordelen van het gebruik van een relationele database voor het opslaan en uitvoeren van gegevensverkenning van afbeeldingen met behulp van eenvoudige SQL-instructies. In deze zelfstudie, deel 2, worden de gegevens die in deel één zijn gebruikt, benaderd vanuit een MariaDB Server-database en geconverteerd naar de gegevensstructuren die TensorFlow nodig heeft. De resultaten van het toepassen van het model om nieuwe afbeeldingen te classificeren, worden opgeslagen in een relationele tabel voor verdere analyse.
Dit is een korte zelfstudie van een TensorFlow-programma met de details die gaandeweg worden beschreven. Als u niet bekend bent met de basisconcepten, is deze TensorFlow-zelfstudie "Basisclassificatie:afbeeldingen van kleding classificeren" een goede plek om te beginnen. Enkele voorbeelden en code in de tutorial worden hier gebruikt.
Aanvullende pakketten nodig
Er zijn enkele aanvullende pakketten nodig voor het bouwen en trainen van het beeldclassificatiemodel:
- Augurk implementeert binaire protocollen voor het serialiseren en deserialiseren van een Python-objectstructuur.
- NumPy biedt ondersteuning voor grote, multidimensionale arrays en matrices, samen met wiskundige functies op hoog niveau om op deze arrays te werken.
- TensorFlow is een Python-bibliotheek voor snel numeriek computergebruik. Het is een basisbibliotheek die kan worden gebruikt om Deep Learning-modellen rechtstreeks te maken of door wrapperbibliotheken te gebruiken die het proces dat bovenop TensorFlow is gebouwd, vereenvoudigen.
- Keras is een open-source neurale netwerkbibliotheek geschreven 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
Afbeeldingen ophalen
Nadat de pakketten zijn geïmporteerd, is de volgende stap het ophalen van de trainingsafbeeldingen uit de database en het splitsen van de gegevens in twee numpy reeksen. Eerst moeten we de trainingsafbeeldingen (train_images) en trainingslabels (train_labels) arrays initialiseren. Omdat we de afbeeldingen al hebben gevectoriseerd, kunnen we het img_vector attribuut gebruiken om de train_images array te vullen met de onderstaande SQL-instructie.
# 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]
Op vergelijkbare wijze kunnen de te testen afbeeldingen uit de database worden gehaald. De numpy arrays die in dit geval worden gebruikt, zijn test_images en test_labels. In dit geval zijn de testgegevens 10.000 afbeeldingen met een resolutie van 28×28 pixels.
# 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]
Ten slotte wordt elke afbeelding toegewezen aan een enkel label. De labelnamen worden opgeslagen in de categorieëntabel en geladen in de class_names-array:
sql="SELECT class_name FROM categories" cur.execute(sql) class_names = cur.fetchall()
Bewerk de gegevens voor
De gegevens moeten worden voorbewerkt voordat het netwerk wordt getraind. Als je de eerste afbeelding in de trainingsset bekijkt, zul je zien dat de pixelwaarden in het bereik van 0 tot 255 liggen:
plt.figure() plt.imshow(train_images[0]) plt.colorbar() plt.grid(False) plt.show()
hierboven:afbeelding uit dataset fashion_mnist
Voordat de afbeeldingen naar het neurale netwerkmodel worden gestuurd, moeten de waarden worden geschaald naar een bereik van 0 tot 1. Om dit te doen, deelt u de waarden door 255. Het is belangrijk dat de trainingsset en de testset op dezelfde manier worden voorbewerkt .
U kunt matplotlib . gebruiken om de eerste 25 afbeeldingen weer te geven om te controleren of de gegevens in het juiste formaat zijn en klaar zijn voor het bouwen en trainen van het netwerk:
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()
hierboven:afbeeldingen uit dataset fashion_mnist
Het model bouwen
Nadat de gegevens zijn voorbewerkt tot twee subsets, kunt u doorgaan met een modeltraining. Dit proces houdt in dat het algoritme wordt 'voed' met trainingsgegevens. Het algoritme verwerkt de gegevens en voert een model uit dat in staat is om een doelwaarde (attribuut) in nieuwe gegevens te vinden - dat wil zeggen, het classificeren van het beeld dat aan het neurale netwerk wordt gepresenteerd.
De meeste deep learning neurale netwerken worden geproduceerd door eenvoudige lagen aan elkaar te koppelen.
De eerste laag in het netwerk transformeert het beeldformaat van een tweedimensionale array (van 28 bij 28 pixels) naar een eendimensionale array (van 28 * 28 =784 pixels). Deze laag heeft geen parameters om te leren; het formatteert alleen de gegevens.
Nadat de pixels zijn afgevlakt, bestaat het netwerk uit twee volledig verbonden lagen die moeten worden geactiveerd. In een neuraal netwerk is de activeringsfunctie verantwoordelijk voor het transformeren van de opgetelde gewogen invoer van het knooppunt in de activering van het knooppunt of de uitvoer voor die invoer.
De eerste dichte laag heeft 128 knooppunten (of neuronen) en maakt gebruik van een Rectified Linear Unit (ReLU) activeringsmethode. De gelijkgerichte lineaire activeringsfunctie is een stuksgewijs lineaire functie die de invoer direct zal uitvoeren als deze positief is, anders zal deze nul uitvoeren.
De tweede (en laatste) laag is een softmax-laag met 10 knooppunten. Een softmax-functie geeft een vector weer die de kansverdelingen van een lijst met mogelijke uitkomsten weergeeft. Het retourneert een array van 10 waarschijnlijkheidsscores die optellen tot 1. Elk knooppunt bevat een score die de waarschijnlijkheid aangeeft dat de huidige afbeelding tot een van de 10 klassen behoort.
De meeste lagen, zoals tf.keras.layers.Dense, hebben parameters die tijdens de training worden geleerd.
model = keras.Sequential([ keras.layers.Flatten(input_shape=(28, 28)), keras.layers.Dense(128, activation='relu'), keras.layers.Dense(10, activation='softmax') ])
Het model samenstellen
De modelcompilatiestap wordt gebruikt om nog een paar instellingen toe te voegen voordat het klaar is voor training. In dit geval zijn de volgende instellingen ingeschakeld.
- Optimizer:werkt het model bij op basis van de gegevens die het ziet en de verliesfunctie (zie hieronder).
- Verliesfunctie:meet hoe nauwkeurig het model is tijdens de training. U wilt deze functie minimaliseren om het model in de goede richting te "sturen".
- Metrieken:houd de trainings- en teststappen bij. Het volgende voorbeeld gebruikt nauwkeurigheid, de fractie van de afbeeldingen die correct zijn geclassificeerd.
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
Het model trainen
Het trainen van het neurale netwerkmodel vereist de volgende stappen.
- Voer de trainingsgegevens naar het model.
- Het model leert afbeeldingen en labels te associëren.
- Doe voorspellingen over een testset.
- Controleer of de voorspellingen overeenkomen met de labels uit de test_labels array.
Om de training te starten, roept u de model.fit-methode aan, zo genoemd omdat deze het model "past" bij de trainingsgegevens:
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
Aan het einde van elk tijdperk wordt het neurale netwerk geëvalueerd ten opzichte van de validatieset. Dit is waar verlies en nauwkeurigheid naar verwijzen.
Nauwkeurigheid evalueren en voorspellen
Om de algehele nauwkeurigheid van het model te schatten, berekent u het gemiddelde van alle tien keer dat de nauwkeurigheidswaarde voorkomt, in dit geval 88%.
Voer vervolgens model.evaluate . uit op de testset om de voorspellende nauwkeurigheid van het getrainde neurale netwerk te krijgen op voorheen ongeziene gegevens.
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) 10000/1 - 0s - loss: 0.2766 - accuracy: 0.8740
De testdataset is minder nauwkeurig dan de trainingsdataset. In dit geval vertegenwoordigt deze kloof tussen trainingsnauwkeurigheid en testnauwkeurigheid overfitting. Het tegenovergestelde is ondermaats. Als je meer wilt weten over dit onderwerp, raad ik Overfitting vs. Underfitting:A Conceptual Explanation door Will Koehrsen aan.
Op dit punt kunnen we enkele voorspellingen doen over de afbeeldingen in onze trainingsgegevensset.
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)
De uitvoer van model.predict is een array van 10 getallen met de kans dat een instantie tot elke klasse behoort. Het is een goed idee om de resultaten in de MariaDB-database te bewaren voor verdere analyse en rapportage. Hieronder ziet u een voorbeeld van hoe u de voorspellingsmatrix kunt herhalen om een tuple te bouwen en deze vervolgens in te voegen in de prediction_results tafel.
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
Nogmaals, een eenvoudige SQL-instructie kan worden gebruikt om te controleren of de gegevens zijn geladen.
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 | Broek | Trui | Jurk | Jas | Sandaal | Overhemd | Sneaker | Tas | Enkel_boot | Testlabel |
0.00001 | 0.0 | 0,997912 | 0.0 | 0,001267 | 0.0 | 0.00081 | 0.0 | 0.0 | 0.0 | Trui |
Voorspellingen plotten
Hieronder worden een aantal plotfuncties gedefinieerd om de voorspellingen weer te geven (Graphing-functies).
Laten we een nieuwe afbeelding uit de testset halen en de neurale netclassificatie weergeven op basis van de voorspellingskans.
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()
hierboven:afbeelding uit dataset fashion_mnist
In dit geval was het model in staat om de afbeelding correct te classificeren met 100% nauwkeurigheid. Laten we vervolgens een query uitvoeren om de eerste 15 afbeeldingen uit de testset op te halen en deze te classificeren.
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()
hierboven:afbeeldingen uit dataset fashion_mnist
Zoals u kunt zien, zullen er gevallen zijn waarin het model fout kan zijn, zoals weergegeven in de laatste rij, linkerkolom. In dit geval werd een sneaker geclassificeerd als een sandaal (in het rood).
Samenvattend
Hoewel integratie tussen TensorFlow en MariaDB Server eenvoudig is, zijn de voordelen van deze integratie aanzienlijk:
- Het gebruik van relationele gegevens binnen machine learning kan de complexiteit van de implementatie verminderen. Zowel datawetenschappers als data-engineers kunnen een gemeenschappelijke taal gebruiken om data-ruzie en verkenningstaken uit te voeren.
- Efficiëntie die wordt behaald bij het openen, bijwerken, invoegen, manipuleren en wijzigen van gegevens kan de time-to-market versnellen.
- De mogelijkheid om de resultaten van het model terug op te slaan in de database stelt eindgebruikers en analisten in staat om query's en rapporten uit te voeren met behulp van gebruiksvriendelijke rapportagetools zoals Tableau.
MIT-licentie
De dataset Fashion MNIST (fashion_mnist) die door deze blog wordt gebruikt, is gelicentieerd onder de MIT-licentie, Copyright © 2017 Zalando SE, https://tech.zalando.com
De broncode die door deze blog wordt gebruikt, is een bewerking van de tutorial "Basisclassificatie:classificeer afbeeldingen van kleding" die is gelicentieerd onder de MIT-licentie, Copyright (c) 2017 François Chollet.
Hierbij wordt kosteloos toestemming verleend aan elke persoon die een kopie van deze software en bijbehorende documentatiebestanden (de "Software") verkrijgt, om zonder beperking in de Software te handelen, inclusief maar niet beperkt tot de rechten om te gebruiken, kopiëren, wijzigen, samenvoegen , publiceren, distribueren, in sublicentie geven en/of verkopen van kopieën van de Software, en om personen aan wie de Software wordt geleverd toe te staan dit te doen, onder de volgende voorwaarden:
De bovenstaande copyrightkennisgeving en deze toestemmingskennisgeving zullen worden opgenomen in alle kopieën of substantiële delen van de software.
DE SOFTWARE WORDT GELEVERD "AS IS", ZONDER ENIGE GARANTIE, EXPLICIET OF IMPLICIET, INCLUSIEF MAAR NIET BEPERKT TOT DE GARANTIES VAN VERKOOPBAARHEID, GESCHIKTHEID VOOR EEN BEPAALD DOEL EN NIET-INBREUK. IN GEEN GEVAL ZULLEN DE AUTEURS OF HOUDERS VAN HET AUTEURSRECHT AANSPRAKELIJK ZIJN VOOR ENIGE CLAIM, SCHADE OF ANDERE AANSPRAKELIJKHEID, HETZIJ IN EEN OVEREENKOMST, ONRECHTMATIGE OF ANDERE, VOORTVLOEIENDE UIT, UIT OF IN VERBAND MET DE SOFTWARE OF HET GEBRUIK IN OF DE ANDERE HANDELINGEN SOFTWARE.
Referenties
Converteer eigen afbeelding naar de afbeelding van MNIST
matplotlib:zelfstudie afbeeldingen
5 manieren waarop AI de klantervaring transformeert
Digitalisering vindt het bedrijfsleven opnieuw uit
Wat is afbeeldingsclassificatie?
Inleiding tot de Python Deep Learning-bibliotheek TensorFlow
Grafische functies
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')