Flüssige neuronale Netzwerke mit komplizierten Bildern verwenden

1. Hinweis

In diesem Codelab nutzen Sie Faltungen, um Bilder von Pferden und Menschen zu klassifizieren. Sie werden in diesem Lab mithilfe von TensorFlow eine CNN erstellen, die darauf geschult ist, Bilder von Pferden und Menschen zu erkennen und zu klassifizieren.

Voraussetzungen

Wenn Sie noch keine Faltungen mit TensorFlow erstellt haben, empfiehlt es sich, das Codelab zu Erstellung von Faltungen und Pooling durchzuführen, in dem wir Faltungen und Pooling einführen, sowie Convolutional Neural Networks (CNNs) zur Verbesserung der Bilderkennung zu verwenden. Dort werden wir besprechen, wie Sie Computer effizienter bei der Erkennung von Bildern einsetzen können.

Lerninhalte

  • Computer trainieren, um Merkmale in einem Bild zu erkennen, auf dem das Motiv nicht klar zu erkennen ist

Inhalte, die Sie erstellen werden

  • Ein flüchtiges neuronales Netzwerk, das zwischen Bildern von Pferden und Bildern von Menschen unterscheiden kann

Voraussetzungen

Sie finden den Code für den Rest des Codelabs, das in Colab ausgeführt wird.

Außerdem müssen TensorFlow und die Bibliotheken installiert sein, die Sie im vorherigen Codelab installiert haben.

2. Erste Schritte: Daten erfassen

Dazu erstellen Sie einen Klassifikator für Pferde oder Menschen, der Ihnen zeigt, ob ein bestimmtes Bild ein Pferd oder einen Menschen enthält. Das Netzwerk wird darin trainiert, Funktionen zu erkennen, die bestimmen, welches. Sie müssen die Daten erst verarbeiten, bevor Sie mit dem Training beginnen können.

Laden Sie zuerst die Daten herunter:

!wget --no-check-certificate https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip  -O /tmp/horse-or-human.zip

Der folgende Python-Code verwendet die Betriebssystembibliothek, um Betriebssystembibliotheken zu verwenden. So erhalten Sie Zugriff auf das Dateisystem und die ZIP-Dateibibliothek, sodass Sie die Daten entpacken können.

import os
import zipfile
 
local_zip = '/tmp/horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/horse-or-human')
zip_ref.close()

Der Inhalt der ZIP-Datei wird in das Basisverzeichnis /tmp/horse-or-human extrahiert, das Pferde und Unterverzeichnisse enthält.

Kurz gesagt, sind die Trainingsdaten die Daten, die verwendet werden, um dem neuronalen Netzwerkmodell zu vermitteln, dass ein Pferd so aussehen soll.

3. Mit dem ImageGenerator die Daten mit Labels versehen und vorbereiten

Sie markieren die Bilder nicht explizit als Pferde oder Menschen.

Später wird das Gerät ImageDataGenerator verwendet, das verwendet wird. Es liest Bilder aus Unterverzeichnissen und kennzeichnet sie automatisch mit dem Namen dieses Unterverzeichniss. Sie haben beispielsweise ein Trainingsverzeichnis mit einem Pferdeverzeichnis und einem Verzeichnis für Menschen. ImageDataGenerator kennzeichnet die Bilder entsprechend für Sie, wodurch ein Codierungsschritt erforderlich ist.

Definieren Sie jedes dieser Verzeichnisse.

# Directory with our training horse pictures
train_horse_dir = os.path.join('/tmp/horse-or-human/horses')
 
# Directory with our training human pictures
train_human_dir = os.path.join('/tmp/horse-or-human/humans')

Sehen wir uns nun an, wie die Dateinamen in den Trainingsverzeichnissen für Pferde und Menschen aussehen:

train_horse_names = os.listdir(train_horse_dir)
print(train_horse_names[:10])
train_human_names = os.listdir(train_human_dir)
print(train_human_names[:10])

Suchen Sie in den Verzeichnissen nach der Gesamtzahl der Bilder von Pferden und Menschen:

print('total training horse images:', len(os.listdir(train_horse_dir)))
print('total training human images:', len(os.listdir(train_human_dir)))

4. Daten ansehen

Sehen Sie sich einige Bilder an, um einen Eindruck davon zu erhalten, wie die Fotos aussehen.

Konfiguriere zuerst die matplot-Parameter:

%matplotlib inline
 
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
 
# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4
 
# Index for iterating over images
pic_index = 0

Zeigen Sie jetzt eine Reihe von acht Pferdebildern und acht menschlichen Bildern an. Sie können die Zelle noch einmal ausführen, um jedes Mal einen neuen Batch aufzurufen.

# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)
 
pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname) 
                for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname) 
                for fname in train_human_names[pic_index-8:pic_index]]
 
for i, img_path in enumerate(next_horse_pix+next_human_pix):
  # Set up subplot; subplot indices start at 1
  sp = plt.subplot(nrows, ncols, i + 1)
  sp.axis('Off') # Don't show axes (or gridlines)
 
  img = mpimg.imread(img_path)
  plt.imshow(img)
 
plt.show()
 

Hier sind einige Beispielbilder, auf denen Pferde und Menschen in verschiedenen Posen und Ausrichtungen dargestellt sind:

6b6ebbc6e694ccd2.png

5. Modell definieren

Definieren Sie das Modell.

Importieren Sie zuerst TensorFlow:

import tensorflow as tf

Fügen Sie anschließend Faltungsschichten hinzu und glätten Sie das Endergebnis in die dicht verbundenen Ebenen. Fügen Sie schließlich die eng verbundenen Ebenen hinzu.

Aufgrund eines Problems mit der zweiklassigen Klassifizierung (binäre Klassifizierung) wird Ihr Netzwerk mit einer Sigmoid-Aktivierung beendet. Dadurch wird die Ausgabe Ihres Netzwerks ein einziger Skala zwischen 0 und 1 sein, der die Wahrscheinlichkeit codiert, dass das aktuelle Bild Klasse 1 ist (nicht Klasse 0).

model = tf.keras.models.Sequential([
    # Note the input shape is the desired size of the image 300x300 with 3 bytes color
    # This is the first convolution
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    # The second convolution
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The third convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fourth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # The fifth convolution
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
    tf.keras.layers.Dense(1, activation='sigmoid')
])

Der Aufruf der Methode model.summary() gibt eine Zusammenfassung des Netzwerks aus.

model.summary()

Ergebnisse:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 298, 298, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 149, 149, 16)      0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 147, 147, 32)      4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 73, 73, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 71, 71, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 35, 35, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 33, 33, 64)        36928     
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 16, 16, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 14, 14, 64)        36928     
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
flatten (Flatten)            (None, 3136)              0         
_________________________________________________________________
dense (Dense)                (None, 512)               1606144   
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 513       
=================================================================
Total params: 1,704,097
Trainable params: 1,704,097
Non-trainable params: 0

In der Spalte „Ausgabeform“ sehen Sie, wie sich die Größe der Featurezuordnung in den einzelnen Ebenen ändert. Die Faltungsschichten reduzieren die Größe der Merkmalskarten aufgrund eines Abstands um etwas mehr und jede Poolschicht halbiert die Dimensionen.

6. Modell kompilieren

Konfigurieren Sie als Nächstes die Spezifikationen für das Modelltraining. Trainieren Sie Ihr Modell mit dem Verlust von binary_crossentropy, weil es ein binäres Klassifizierungsproblem ist und Ihre endgültige Aktivierung ein Sigmoid ist. Hier erfahren Sie mehr über die Messwerte zu Verlusten. Verwenden Sie den Optimierungstool rmsprop zur Lernrate 0,001. Beobachten Sie die Klassifizierungsgenauigkeit während des Trainings.

from tensorflow.keras.optimizers import RMSprop
 
model.compile(loss='binary_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics=['acc'])

7. Modell von Generatoren trainieren

Richte Datengeneratoren ein, die Bilder in deinen Quellordnern lesen, in Gleitkommazahlen über Tensoren umwandeln und mit ihrem Label in dein Netzwerk übertragen.

Sie haben einen Generator für die Trainings- und einen Validierungsimage. Die Generatoren liefern Gruppen von Bildern im Format 300 x 300 und deren Labels (binär).

Wie Sie vielleicht wissen, sollten Daten, die an neuronale Netzwerke gesendet werden, in der Regel normalisiert werden, um die Verarbeitung durch das Netzwerk besser zu ermöglichen. Es ist üblich, Rohpixel in einer CNN einzufügen. In Ihrem Fall führen Sie eine Vorverarbeitung Ihrer Bilder durch, indem Sie die Pixelwerte normalisieren. Sie müssen im Bereich [0, 1] liegen. Ursprünglich liegen alle Werte im Bereich [0, 255].

In Keras erfolgt dies über die Klasse keras.preprocessing.image.ImageDataGenerator mit dem Parameter „rescale“. Mit dieser ImageDataGenerator-Klasse können Sie Generatoren von Augmented-Image-Batches (und deren Labels) über .flow(data, labels) oder .flow_from_directory(directory) instanziieren. Diese Generatoren können dann mit den Keras-Modellmethoden verwendet werden, die Datengeneratoren als Eingaben akzeptieren: fit_generator, evaluate_generator und predict_generator.

from tensorflow.keras.preprocessing.image import ImageDataGenerator
 
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1./255)
 
# Flow training images in batches of 128 using train_datagen generator
train_generator = train_datagen.flow_from_directory(
        '/tmp/horse-or-human/',  # This is the source directory for training images
        target_size=(300, 300),  # All images will be resized to 150x150
        batch_size=128,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode='binary')

8. Training absolvieren

Ein Training für 15 Epochen. Dies kann einige Minuten dauern.

history = model.fit(
      train_generator,
      steps_per_epoch=8,  
      epochs=15,
      verbose=1)

Notieren Sie sich die Werte pro Epoche.

Die Verluste und die Genauigkeit sind ein guter Hinweis auf den Fortschritt des Trainings. Sie erraten die Klassifizierung der Trainingsdaten, messen sie dann mit dem bekannten Label und berechnen das Ergebnis. Die Genauigkeit ist der Teil der richtigen Vermutungen.

Epoch 1/15
9/9 [==============================] - 9s 1s/step - loss: 0.8662 - acc: 0.5151
Epoch 2/15
9/9 [==============================] - 8s 927ms/step - loss: 0.7212 - acc: 0.5969
Epoch 3/15
9/9 [==============================] - 8s 921ms/step - loss: 0.6612 - acc: 0.6592
Epoch 4/15
9/9 [==============================] - 8s 925ms/step - loss: 0.3135 - acc: 0.8481
Epoch 5/15
9/9 [==============================] - 8s 919ms/step - loss: 0.4640 - acc: 0.8530
Epoch 6/15
9/9 [==============================] - 8s 896ms/step - loss: 0.2306 - acc: 0.9231
Epoch 7/15
9/9 [==============================] - 8s 915ms/step - loss: 0.1464 - acc: 0.9396
Epoch 8/15
9/9 [==============================] - 8s 935ms/step - loss: 0.2663 - acc: 0.8919
Epoch 9/15
9/9 [==============================] - 8s 883ms/step - loss: 0.0772 - acc: 0.9698
Epoch 10/15
9/9 [==============================] - 9s 951ms/step - loss: 0.0403 - acc: 0.9805
Epoch 11/15
9/9 [==============================] - 8s 891ms/step - loss: 0.2618 - acc: 0.9075
Epoch 12/15
9/9 [==============================] - 8s 902ms/step - loss: 0.0434 - acc: 0.9873
Epoch 13/15
9/9 [==============================] - 8s 904ms/step - loss: 0.0187 - acc: 0.9932
Epoch 14/15
9/9 [==============================] - 9s 951ms/step - loss: 0.0974 - acc: 0.9649
Epoch 15/15
9/9 [==============================] - 8s 877ms/step - loss: 0.2859 - acc: 0.9338

9. Modell testen

Führen Sie nun mit dem Modell eine Vorhersage aus. Mit dem Code können Sie eine oder mehrere Dateien aus Ihrem Dateisystem auswählen. Anschließend werden sie hochgeladen und durch das Modell geleitet. So sehen Sie, ob es sich bei dem Objekt um ein Pferd oder einen Menschen handelt.

Sie können Bilder aus dem Internet in Ihr Dateisystem herunterladen, um sie auszuprobieren. Beachten Sie, dass das Netzwerk zwar viele Fehler aufweist, obwohl die Trainingsgenauigkeit über 99 % liegt.

Das liegt an einer Überanpassung, was bedeutet, dass das neuronale Netzwerk mit sehr begrenzten Daten trainiert wird (es gibt nur etwa 500 Bilder jeder Klasse). Es kann also sehr gut erkannt werden, wenn es Bilder sind, die denen im Trainings-Set ähneln, aber bei Bildern, die nicht im Trainings-Set enthalten sind, schlägt das oft fehl.

Das ist ein Datenpunkt, der beweist, dass je mehr Daten du trainierst, desto besser wird dein endgültiges Netzwerk!

Es gibt viele Techniken, die verwendet werden können, um das Training trotz eingeschränkter Daten zu verbessern. Dazu zählt auch die sogenannte Bilderweiterung. Das ist aber nicht das Codelab.

import numpy as np
from google.colab import files
from keras.preprocessing import image
 
uploaded = files.upload()
 
for fn in uploaded.keys():
 
  # predicting images
  path = '/content/' + fn
  img = image.load_img(path, target_size=(300, 300))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)
 
  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  print(classes[0])
  if classes[0]>0.5:
    print(fn + " is a human")
  else:
    print(fn + " is a horse")

Beispiel: Sie möchten mit diesem Bild testen:

9e07a57ff3be7a82.jpeg

Das Codelab zeigt Folgendes:

77b678e70b00862a

Obwohl es eine Zeichentrickgrafik ist, wird sie dennoch richtig klassifiziert.

Auch die folgende Abbildung ist korrekt klassifiziert:

c9213173d9f3d83c.jpeg

f2844da737a1a2f2.png

Testen Sie einige Ihrer eigenen Bilder und entdecken Sie sie!

10. Zwischendarstellungen visualisieren

Damit ihr erkennt, welche Funktionen eure CNN gelernt hat, möchtet ihr visualisieren, wie eine Eingabe im CNN transformiert wird.

Wählen Sie ein zufälliges Bild aus dem Trainings-Dataset aus und generieren Sie dann eine Zahl. Dabei ist jede Zeile die Ausgabe einer Ebene und jedes Bild in der Zeile ein bestimmter Filter in dieser Ausgabefeature-Zuordnung. Führen Sie diese Zelle noch einmal aus, um Zwischendarstellungen für eine Vielzahl von Trainingsbildern zu erstellen.

import numpy as np
import random
from tensorflow.keras.preprocessing.image import img_to_array, load_img
 
# Let's define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model after
# the first.
successive_outputs = [layer.output for layer in model.layers[1:]]
#visualization_model = Model(img_input, successive_outputs)
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)
# Let's prepare a random input image from the training set.
horse_img_files = [os.path.join(train_horse_dir, f) for f in train_horse_names]
human_img_files = [os.path.join(train_human_dir, f) for f in train_human_names]
img_path = random.choice(horse_img_files + human_img_files)
 
img = load_img(img_path, target_size=(300, 300))  # this is a PIL image
x = img_to_array(img)  # Numpy array with shape (150, 150, 3)
x = x.reshape((1,) + x.shape)  # Numpy array with shape (1, 150, 150, 3)
 
# Rescale by 1/255
x /= 255
 
# Let's run our image through our network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)
 
# These are the names of the layers, so can have them as part of our plot
layer_names = [layer.name for layer in model.layers]
 
# Now let's display our representations
for layer_name, feature_map in zip(layer_names, successive_feature_maps):
  if len(feature_map.shape) == 4:
    # Just do this for the conv / maxpool layers, not the fully-connected layers
    n_features = feature_map.shape[-1]  # number of features in feature map
    # The feature map has shape (1, size, size, n_features)
    size = feature_map.shape[1]
    # We will tile our images in this matrix
    display_grid = np.zeros((size, size * n_features))
    for i in range(n_features):
      # Postprocess the feature to make it visually palatable
      x = feature_map[0, :, :, i]
      x -= x.mean()
      if x.std()>0:
        x /= x.std()
      x *= 64
      x += 128
      x = np.clip(x, 0, 255).astype('uint8')
      # We'll tile each filter into this big horizontal grid
      display_grid[:, i * size : (i + 1) * size] = x
    # Display the grid
    scale = 20. / n_features
    plt.figure(figsize=(scale * n_features, scale))
    plt.title(layer_name)
    plt.grid(False)
    plt.imshow(display_grid, aspect='auto', cmap='viridis')

Beispielergebnisse:

e078d1bc9662c93f

Wie Sie sehen, wechseln Sie von den Rohpixeln der Bilder zu zunehmend abstrakten und kompakten Darstellungen. In den nachgelagerten Darstellungen sehen Sie, worauf sich das Netzwerk konzentriert. Außerdem werden weniger und weniger Funktionen angezeigt, die aktiviert sind. Die meisten sind auf null gesetzt. Das wird als sparsity bezeichnet. Die Darstellung von Dichten ist ein wichtiger Bestandteil von Deep Learning.

Diese Repräsentationen enthalten immer weniger Informationen zu den ursprünglichen Pixeln des Bildes, jedoch zunehmend verfeinerte Informationen über die Klasse des Bildes. Sie können sich einen CNN (oder ein Deep Network) im Prinzip als eine Destillationspipeline vorstellen.

11. Glückwunsch

Du hast gelernt, wie du komplexe Bilder mithilfe von CNNs optimieren kannst. Wie Sie Ihre Modelle für maschinelles Sehen weiter verbessern können, erfahren Sie unter Convolutional Neural Networks (CNNs) mit großen Datasets verwenden, um eine Überanpassung zu vermeiden.