
Teilen Sie:
IOS-Entwickler, der sich für Data Science und maschinelles Lernen begeistert. Ich möchte, dass die Menschen verstehen, was maschinelles Lernen ist und wie wir es in unseren Applications nutzen können.
Aufbau eines Bildklassifikators in Tensorflow
Lesedauer: 9 Minuten
In diesem Beitrag werden Sie ein grundlegendes Bildklassifizierungsmodell für die Verarbeitung von Bildern erstellen, die von Mitgliedern einer Konversation in einer mit Nexmo In-App Messaging integrierten iOS-App gesendet werden. Nachdem ein Benutzer ein Bild hochgeladen hat, wird eine Bildunterschrift angezeigt, die das Bild beschreibt.
Wir werden Python verwenden, um unser Bildklassifizierungsmodell zu erstellen. Machen Sie sich keine Sorgen, wenn Sie noch nie mit Python gearbeitet haben oder keine Vorkenntnisse im Bereich maschinelles Lernen haben.
Was ist Bildklassifizierung?
Bei der Bildklassifizierung im Rahmen des maschinellen Lernens handelt es sich um ein Foto, bei dem das maschinelle Lernmodell in der Lage ist, zu erkennen, welches Motiv auf dem Foto zu sehen ist. Wenn Sie zum Beispiel ein Foto von einem Hund machen, kann das maschinelle Lernmodell sagen: "Das ist ein Hund".
Um ein maschinelles Lernmodell zu erstellen, benötigen wir zunächst Daten, um es zu trainieren.
Ein Modell für maschinelles Lernen benötigt Trainingsdaten, damit das Modell lernen kann. Zu Beginn müssen wir die Trainingsdaten auswählen. Für diesen Beitrag verwenden wir die CIFAIR-10 Datensatz.
Dieser Datensatz enthält Bilder in 10 Klassen, mit 6000 Bildern pro Klasse. Es handelt sich um einen gut genutzten Datensatz für maschinelles Lernen, der einen guten Start für unser Projekt darstellt. Da der Datensatz relativ klein ist, können wir das Modell schnell trainieren.
Dieses Notebook ausführen
Dieses Notizbuch wird gehostet auf Google Colab. Colaboratory ist eine kostenlose Jupyter-Notizbuchumgebung, die keine Einrichtung erfordert und vollständig in der Cloud läuft.
Beachten Sie, dass Sie ein Google-Konto benötigen, um das Notizbuch auszuführen.
Das Ausführen des Notizbuchs ist sehr einfach. In jeder Zelle, die Code enthält, befindet sich links neben der Zelle eine Schaltfläche zum Ausführen. Tippen Sie auf die Schaltfläche "Ausführen", um den Code auszuführen. Sie können auch den Tastaturbefehl Shift dann Enter.
Aufbau des Modells
Als Erstes müssen wir unsere Pakete importieren. Diese Pakete sind auf Google Colab vorinstalliert, sodass wir sie nicht installieren müssen.
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
import numpy as npBeachten Sie, dass wir Tensorflow und Keras als Frontend zu Tensorflow verwenden. Keras ist ein großartiges Framework, mit dem Sie Modelle einfacher erstellen können, ohne die ausführlichen Methoden in Tensorflow verwenden zu müssen.
Als nächstes werden wir den CIFAR-Datensatz laden. Mit Keras können wir den Datensatz ganz einfach herunterladen.
Wir teilen den Datensatz in 2 Gruppen auf, eine für das Training (x_train, y_train), die andere zum Testen (x_test, y_test).
Die Aufteilung des Datensatzes ermöglicht es dem Modell, aus dem Trainingssatz zu lernen. Wenn wir dann das Modell testen, wollen wir sehen, wie gut es mit Hilfe des Testsatzes gelernt hat. Daraus ergibt sich die Genauigkeit - wie gut das Modell abgeschnitten hat.
from keras.datasets import cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print('y_train shape', y_train.shape)
print(x_test.shape[0], 'test samples')
print('x_test shape', x_test.shape)
print(y_test.shape[0], 'test samples')Using TensorFlow backend.
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 75s 0us/step
x_train shape: (50000, 32, 32, 3)
50000 train samples
y_train shape (50000, 1)
10000 test samples
x_test shape (10000, 32, 32, 3)
10000 test samplesAls nächstes werden wir einige Konstanten deklarieren.
batch_sizeist die Anzahl der Stichproben, die über das Netz weitergegeben werden sollen.epochssind, wie oft wir auf dem gesamten Datensatz trainieren.class_namesist eine Liste aller möglichen Bezeichnungen im CIFAR-10-Datensatz.
batch_size = 32
epochs = 100
class_names = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"]Wir werden diese Konstanten später bei der Konvertierung unseres Modells in CoreML verwenden.
def plot_images(x, y, number_of_images=2):
fig, axes1 = plt.subplots(number_of_images,number_of_images,figsize=(10,10))
for j in range(number_of_images):
for k in range(number_of_images):
i = np.random.choice(range(len(x)))
title = class_names[y[i:i+1][0][0]]
axes1[j][k].title.set_text(title)
axes1[j][k].set_axis_off()
axes1[j][k].imshow(x[i:i+1][0])Schauen wir uns zunächst ein paar Bilder an. Wir haben eine Funktion, die 4 zufällige Bilder und die dazugehörige Beschriftung aufzeichnet.
plot_images(x_train, y_train)
Image recognition Tensorflow CoreML
Aufbau des Modells
Jetzt werden wir ein einfaches Modell einrichten. Wir erstellen ein tiefes neuronales Netzwerk mit Faltungen, Dropoutund Max-Pooling.
Am Ende werden wir das Netzwerk abflachen und die Relu, gefolgt von einem Softmax.
So erhalten wir einen Vektor (eine 1-dimensionale Matrix), der überwiegend mit 0 gefüllt ist.
Sie wird folgendermaßen aussehen.
[0,0,0,0,0,0,1,0,0,0]Dieser Vektor entspricht der gegebenen Bezeichnung aus dem Bild In diesem Beispiel wäre also der 1 an siebter Stelle ein Frosch sein, da 'Frosch' an siebter Stelle in der class_names Liste steht.
Die folgende Abbildung zeigt das gesamte Netz.
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(10, activation='softmax'))Das war's!
Training des Modells
Zunächst kompilieren wir das Modell, um seinen Verlust zu ermitteln. Der Verlust ist ein Maß dafür, wie gut das Modell bei den Tests abgeschnitten hat. Ein hoher Verlust bedeutet, dass das Modell schlecht abgeschnitten hat.
Hier verwenden Sie Adam Optimierereinen Algorithmus, der den beim maschinellen Lernen weit verbreiteten stochastischen Gradientenabstieg erweitert, um den Verlust zu berechnen.
Dann rufen wir .fit auf, der das Modell für 100 Epochen trainiert. Das bedeutet, dass der gesamte Trainingsdatensatz 100 Mal trainiert wird. batch_size von 32 ist die Anzahl der Proben, die durch das Netzwerk propagiert werden.
Wir sehen dann, wie gut es nach jeder Epoche mit model.evaluate. Es gibt uns eine Punktzahl für das Modell (höhere Numbers sind besser) und den Verlust (niedrigere Numbers sind besser).
Beachten Sie, dass dieser Vorgang mit Colab etwa 15 Minuten dauerte. Wenn Sie die Ergebnisse schneller sehen möchten, setzen Sie den epochs Parameter auf 1 oder 2. Die Genauigkeit ist dann allerdings nicht mehr so hoch.
# Compile the model
model.compile(loss='categorical_crossentropy',
optimizer=tf.keras.optimizers.Adam(lr=0.0001, decay=1e-6),
metrics=['accuracy'])
# Train the model
model.fit(x_train / 255.0, tf.keras.utils.to_categorical(y_train),
batch_size=batch_size,
shuffle=True,
epochs=epochs,
validation_data=(x_test / 255.0, tf.keras.utils.to_categorical(y_test))
)
# Evaluate the model
scores = model.evaluate(x_test / 255.0, tf.keras.utils.to_categorical(y_test))
print('Loss: %.3f' % scores[0])
print('Accuracy: %.3f' % scores[1])Train on 50000 samples, validate on 10000 samples
Epoch 1/100
#Omitted for readability
50000/50000 [==============================] - 30s 603us/step - loss: 0.1378 - acc: 0.9518 - val_loss: 0.7136 - val_acc: 0.8116
10000/10000 [==============================] - 2s 151us/step
Loss: 0.714
Accuracy: 0.812Unsere endgültige Genauigkeit lag bei 81 %, und unser Verlust betrug 0,7, was ziemlich gut ist.
Um es noch einmal zu wiederholen: Die Genauigkeit gibt an, wie gut das Modell jedes Bild klassifizieren konnte, während der Verlust angibt, wie schlecht die Vorhersagen des Modells waren.
Weitere Informationen finden Sie in dieser Definition von Verlust und Genauigkeit auf Google-Crashkurs für maschinelles Lernen.
Konvertierung des Modells in Core ML
Nachdem wir das Modell trainiert haben, können wir es speichern und dann in das Core ML-Format konvertieren.
Core ML wurde auf der WWDC 2018 vorgestellt und ermöglicht es iOS-Entwicklern, eine breite Palette von Machine-Learning-Modellen in eine iOS-App zu integrieren. Hier nutzen Sie diese Technologie mit Nexmo In-App Messaging, um Ihr eigenes Deep Learning für die Verarbeitung von Bildern zu ermöglichen.
Zunächst müssen wir das trainierte Modell speichern.
model.save('cifar-model.h5')Wir verwenden coremltools, das das Modell in ein Format konvertiert, das unsere Stitch-Anwendung verwenden kann.
Beachten Sie, dass das Core ML-Paket auf Colab nicht vorinstalliert ist, daher müssen wir es mit pip
Oben können Sie sehen, dass das Paket auf unserem Notebook installiert wurde.
Als Nächstes werden wir das gespeicherte Modell in Core ML konvertieren.
Da wir unser Modell mit Keras trainiert haben, ist es sehr einfach, es in Core ML zu konvertieren. Dies hängt jedoch davon ab, wie Sie Ihr Modell erstellt haben. Core ML-Tools haben andere Funktionen, die für andere Pakete für maschinelles Lernen verwendet werden können, einschließlich Tensorflow und Scikit Learn. Siehe das coremltools repo für weitere Informationen.
from keras.models import load_model
import coremltools
model = load_model('cifar-model.h5')
coreml_model = coremltools.converters.keras.convert(model,
input_names="image",
image_input_names="image",
image_scale=1/255.0,
class_labels=class_names)
coreml_model.save('CIFAR.mlmodel') 0 : conv2d_input, <keras.engine.topology.InputLayer object at 0x7fa7c829fac8>
1 : conv2d, <keras.layers.convolutional.Conv2D object at 0x7fa7c829f358>
2 : conv2d__activation__, <keras.layers.core.Activation object at 0x7fa7c75bf198>
3 : conv2d_1, <keras.layers.convolutional.Conv2D object at 0x7fa7c80e40b8>
4 : conv2d_1__activation__, <keras.layers.core.Activation object at 0x7fa7c75bf438>
5 : max_pooling2d, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c80e4550>
6 : conv2d_2, <keras.layers.convolutional.Conv2D object at 0x7fa7c77434a8>
7 : conv2d_2__activation__, <keras.layers.core.Activation object at 0x7fa7c73f9240>
8 : max_pooling2d_1, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c7743f28>
9 : conv2d_3, <keras.layers.convolutional.Conv2D object at 0x7fa7c87ad1d0>
10 : conv2d_3__activation__, <keras.layers.core.Activation object at 0x7fa7c7262dd8>
11 : max_pooling2d_2, <keras.layers.pooling.MaxPooling2D object at 0x7fa7c7743f60>
12 : flatten, <keras.layers.core.Flatten object at 0x7fa7c76fac50>
13 : dense, <keras.layers.core.Dense object at 0x7fa7c76b42b0>
14 : dense__activation__, <keras.layers.core.Activation object at 0x7fa7c71ff390>
15 : dense_1, <keras.layers.core.Dense object at 0x7fa7c7670358>
16 : dense_1__activation__, <keras.layers.core.Activation object at 0x7fa7c71ff898>Die obige Ausgabe zeigt alle Ebenen innerhalb des Modells. Diese stehen in direktem Zusammenhang damit, wie wir das Modell in dieser Zelle.
Schauen Sie sich die Parameter für die convert Funktion an. Hier setzen wir die Eingabe auf ein image sowohl für die input_names und image_input_names Parameter. Dadurch weiß das Core ML-Modell, welche Art von Eingabe es erwartet, nämlich ein Bild.
Dann skalieren wir die Bilder im Parameter image_scale Parameter auf eine Zahl zwischen 0 und 1.
Als nächstes setzen wir den class_labels Parameter auf class_names fest, den wir zuvor erstellt haben.
Wenn wir dieses Modell in Xcode verwenden, ist das Ergebnis ein Stringsein, das der vorhergesagten Bezeichnung des Bildes entspricht.
Nun können wir einen Blick auf das Core ML-Modell werfen.
print(coreml_model)input {
name: "image"
type {
imageType {
width: 32
height: 32
colorSpace: RGB
}
}
}
output {
name: "output1"
type {
dictionaryType {
stringKeyType {
}
}
}
}
output {
name: "classLabel"
type {
stringType {
}
}
}
predictedFeatureName: "classLabel"
predictedProbabilitiesName: "output1"Sie können sehen, dass unser input ein 32x32-Pixel-Bild ist, und unsere Ausgabe ist ein String, genannt classLabel
Als nächstes speichern wir das mlmodel lokal, indem wir ein Google Colab-Paket verwenden, um die Datei auf unseren Rechner herunterzuladen.
from google.colab import files
files.download('CIFAR.mlmodel') Einbindung des Modells in unsere Stitch-App
Sobald unser Modell gespeichert ist, können wir es in unsere App importieren. Ziehen Sie dazu einfach das soeben gespeicherte Modell in Xcode.
CIFAR xcode
Vergewissern Sie sich, dass das Modell im Ziel enthalten ist, indem Sie überprüfen, ob die Zielmitgliedschaft ausgewählt ist.
Als Nächstes werden wir den Code in unserer iOS-Anwendung schreiben, der dieses Modell verwenden wird.
In unserer Stitch-Demo-Anwendungkönnen Benutzer ein Foto in eine bestehende Konversation hochladen.
Nexmo's In-App Messaging ermöglicht es den Nutzern, als Mitglieder einer Konversation, nicht nur TextEvents sondern ImageEvents indem sie ein Foto in eine bestehende Konversation hochladen. Für dieses Beispiel werden wir versuchen, den Inhalt des Fotos, das ein Nutzer hochgeladen hat, vorherzusagen.
Sie integrieren die Funktionalität zur Beobachtung von ImageEvents für Core ML direkt in Ihren ViewController. Ein Beispiel, wie dies gemacht werden kann, finden Sie im dem Quellcode für dieses Beispiel.
In unserem ViewController werden wir das Modell instanziieren.
let model = CIFAR()Jetzt, innerhalb der cellForRowAtPath Methode prüfen wir, ob die event ist ein ImageEventist, und wenn ja, dann wird das Foto aus dem ImageEvent angezeigt. Dann nehmen wir das Bild, konvertieren es in ein PixelBuffermit einer Größe von 32x32 Pixeln und geben es dann in das Modell ein.
Der Grund, warum wir das Bild neu abtasten müssen, ist, dass das Modell auf Bildern mit 32x32 Pixeln trainiert wurde. Wenn wir also die Größe der Bilder nicht anpassen, kann das Modell keine Vorhersage machen (in Xcode wird ein Fehler angezeigt, der besagt, dass die Bildgröße falsch ist).
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let event = conversation?.events[indexPath.row]
switch event {
case is ImageEvent:
//get the image from the ImageEvent
let imageEvent = (event as! ImageEvent)
guard let imagePath = imageEvent.path(of: IPS.ImageType.thumbnail), let image = UIImage(contentsOfFile: imagePath) else {
break
}
cell.imageView?.image = image
//convert the image to a pixelBuffer
//using https://github.com/hollance/CoreMLHelpers.git
if let pixelBuffer = image.pixelBuffer(width: 32, height: 32) {
let input = CIFARInput(image: pixelBuffer)
//perform the prediction
if let output = try? model.prediction(input: input) {
cell.textLabel?.text = (imageEvent.from?.name)! + " uploaded a photo of a \(output.classLabel)"
}
else {
cell.textLabel?.text = (imageEvent.from?.name)! + " uploaded a photo"
}
}
break;
default:
cell.textLabel?.text = ""
}
return cell;
}Das Modell gibt dann eine classLabel. Dies ist der Name des Bildes, das das Modell vorhergesagt hat. Es könnte eine der folgenden Bezeichnungen sein: "Flugzeug", "Auto", "Vogel", "Katze", "Hirsch", "Hund", "Frosch", "Pferd", "Schiff" oder "LKW".
Schlussfolgerung
Anhand unserer Vorhersagen können wir feststellen, dass das Modell nur 10 Bezeichnungen erkennen kann. Das vollständige Notizbuch ist verfügbar auf GitHub.
Das ist gut für eine Demo, aber nicht für eine Produktionsanwendung. In einem späteren Beitrag werden wir uns mit der Erstellung eines Bilderkennungsmodells mit mehr Daten beschäftigen. Wir werden einen Blick auf die beliebte ImageNet-Datenbankdie 14.197.122 beschriftete Bilder enthält.
Es ist ein 150gb großer Download, also werden wir uns ansehen, wie man es herunterlädt, trainiert und in unsere Stitch-Demo-App integriert.