Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Bildklassifizierung

Auf TensorFlow.org Führen Sie in Google Colab Quelltext anzeigen auf GitHub Herunterladen Notebook

Dieses Tutorial zeigt, wie Bilder von Blumen zu klassifizieren. Es erzeugt ein Bild Klassifikator ein mit keras.Sequential Modell und lädt Daten mit preprocessing.image_dataset_from_directory . Sie werden mit den folgenden Konzepten praktische Erfahrungen sammeln:

  • Effizientes einen Datensatz aus Disk geladen.
  • Identifizieren und Überanpassung Anwendung Techniken es zu mildern, einschließlich Daten Augmentation und Dropout.

Dieses Tutorial folgt eine Basismaschine Lern ​​Workflow:

  1. Untersuchen und verstehen, Daten
  2. Erstellen Sie eine Eingabe Pipeline
  3. Bauen Sie das Modell
  4. Train-the-Modell
  5. Testen Sie das Modell
  6. Verbessern Sie das Modell und wiederholen Sie den Vorgang
pip install -q tf-nightly

Import TensorFlow und andere Bibliotheken

 import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
 

Downloaden und erkunden den Datensatz

Dieses Tutorial verwendet einen Datensatz von über 3.700 Fotos von Blumen. Der Datensatz enthält 5 Unterverzeichnisse, eine pro Klasse:

 flower_photo/
  daisy/
  dandelion/
  roses/
  sunflowers/
  tulips/
 
 import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 4s 0us/step

Nach dem Download sollten Sie nun eine Kopie des Datensatzes zur Verfügung haben. Es gibt 3.670 Gesamt Bilder:

 image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
 
3670

Hier sind einige Rosen:

 roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))
 

png

 PIL.Image.open(str(roses[1]))
 

png

Und einige Tulpen:

 tulips = list(data_dir.glob('tulips/*'))
PIL.Image.open(str(tulips[0]))
 

png

 PIL.Image.open(str(tulips[1]))
 

png

Laden keras.preprocessing mit

Lassen Sie uns Last diese Bilder aus Platte , um das hilfreich mit image_dataset_from_directory Dienstprogramm. Dadurch werden Sie von einem Verzeichnis der Bilder auf der Festplatte zu einem nimmt tf.data.Dataset in nur ein paar Zeilen Code. Wenn Sie möchten, können Sie auch Ihre eigenen Datenlade Code von Grund auf durch den Besuch der Schreiblast Bilder - Tutorial.

Erstellen Sie einen Datensatz

Definieren Sie einige Parameter für den Lader:

 batch_size = 32
img_height = 180
img_width = 180
 

Es ist gute Praxis eine Validierung Split zu verwenden, wenn Ihr Modell zu entwickeln. Wir werden 80% der Bilder für die Ausbildung nutzen, und 20% für die Validierung.

 train_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
 
Found 3670 files belonging to 5 classes.
Using 2936 files for training.

 val_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
 
Found 3670 files belonging to 5 classes.
Using 734 files for validation.

Sie können die Klassennamen in dem finden class_names Attribut auf dieser Datensätze. Diese entsprechen den Verzeichnisnamen in alphabetischer Reihenfolge.

 class_names = train_ds.class_names
print(class_names)
 
['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']

Visualisieren Sie die Daten

Hier sind die ersten 9 Bilder aus dem Trainingsdatenmenge.

 import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")
 

png

Sie werden ein Modell mit diesen Datensatz trainieren , indem sie vorbei model.fit in einem Augenblick. Wenn Sie möchten, können Sie auch manuell Iterierte über den Datensatz und Reihen von Bildern abrufen:

 for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
 
(32, 180, 180, 3)
(32,)

Der image_batch ein Tensor der Form (32, 180, 180, 3) . Dies ist eine Charge von 32 Bildern von Form 180x180x3 (die letzte Dimension referes zu Farbkanälen RGB). Der label_batch ein Tensor der Form (32,) , werden diese entsprechenden Etiketten auf die 32 Bilder.

Sie können anrufen .numpy() auf dem image_batch und labels_batch Tensoren sie zu einem konvertieren numpy.ndarray .

Konfigurieren Sie den Datensatz für Leistung

Lassen Sie sich sicherstellen, dass gepufferte verwenden Prefetching, so dass wir Daten von der Festplatte, ohne nachgeben können I / O blockiert werden. Dies sind zwei wichtige Methoden, die Sie verwenden sollten, wenn Daten geladen werden.

Dataset.cache() hält die Bilder im Speicher , nachdem sie während der ersten Epoche aus der Festplatte geladen ist. Dadurch wird die Datenmenge nicht gewährleistet, zu einem Engpass werden, während Ihres Modell zu trainieren. Wenn Ihr Datenmenge zu groß, um in dem Speicher zu passen, können Sie auch diese Methode verwenden, um eine performante On-Disk-Cache zu erstellen.

Dataset.prefetch() überlappt Datenvorverarbeitung und Modellausführung während des Trainings.

Interessierte Leser können mehr über die beiden Methoden, als auch, wie auf Cache - Daten auf die Festplatte in der Lerndaten Performance Guide .

 AUTOTUNE = tf.data.experimental.AUTOTUNE

train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
 

Standardisieren der Daten

Die RGB - Kanal - Werte sind in dem [0, 255] Bereich. Das ist nicht ideal für ein neuronales Netz; im Allgemeinen sollten Sie versuchen, Ihre Eingabewerte klein zu machen. Hier werden wir Werte standardisieren in der sein [0, 1] durch eine Reskalierung Schicht verwendet wird .

 normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)
 

Es gibt zwei Möglichkeiten, um diese Schicht zu verwenden. Sie können es durch den Aufruf Karte auf den Datensatz anwenden:

 normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixels values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image)) 
 
0.0 1.0

Oder können Sie die Ebene in Ihrer Modelldefinition enthalten, die Bereitstellung vereinfachen kann. Wir werden hier den zweiten Ansatz.

Erstellen Sie das Modell

Das Modell besteht aus drei Blöcken mit einer Faltungs max Pool Schicht in jedem von ihnen. Es gibt eine vollständig verbunden Schicht mit 128 Einheiten auf ihn , die durch eine aktiviert wird relu Aktivierungsfunktion. Dieses Modell ist nicht für hohe Genauigkeit abgestimmt wurde, ist das Ziel dieses Tutorial einen einheitlichen Ansatz zu zeigen.

 num_classes = 5

model = Sequential([
  layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
 

Kompilieren Sie das Modell

Für dieses Tutorial, wählen Sie die optimizers.Adam Optimierer und losses.SparseCategoricalCrossentropy Verlustfunktion. Um Ansicht Probe- und Validierungsgenauigkeit für jede Trainings Epoche, übergeben Sie die metrics Argument.

 model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
 

Modellübersicht

Sehen Sie alle Ebenen des Netzwerks des Modells mit summary Methode:

 model.summary()
 
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
rescaling_1 (Rescaling)      (None, 180, 180, 3)       0         
_________________________________________________________________
conv2d (Conv2D)              (None, 180, 180, 16)      448       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 90, 90, 16)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 90, 90, 32)        4640      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
flatten (Flatten)            (None, 30976)             0         
_________________________________________________________________
dense (Dense)                (None, 128)               3965056   
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 645       
=================================================================
Total params: 3,989,285
Trainable params: 3,989,285
Non-trainable params: 0
_________________________________________________________________

Train-the-Modell

 epochs=10
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
 
Epoch 1/10
92/92 [==============================] - 4s 47ms/step - loss: 1.9328 - accuracy: 0.2896 - val_loss: 1.1022 - val_accuracy: 0.5245
Epoch 2/10
92/92 [==============================] - 1s 10ms/step - loss: 1.0441 - accuracy: 0.5761 - val_loss: 1.0057 - val_accuracy: 0.5913
Epoch 3/10
92/92 [==============================] - 1s 10ms/step - loss: 0.8640 - accuracy: 0.6763 - val_loss: 0.8951 - val_accuracy: 0.6499
Epoch 4/10
92/92 [==============================] - 1s 10ms/step - loss: 0.7106 - accuracy: 0.7472 - val_loss: 0.8992 - val_accuracy: 0.6621
Epoch 5/10
92/92 [==============================] - 1s 10ms/step - loss: 0.4817 - accuracy: 0.8285 - val_loss: 0.8997 - val_accuracy: 0.6662
Epoch 6/10
92/92 [==============================] - 1s 10ms/step - loss: 0.3131 - accuracy: 0.8903 - val_loss: 1.0014 - val_accuracy: 0.6567
Epoch 7/10
92/92 [==============================] - 1s 10ms/step - loss: 0.1782 - accuracy: 0.9436 - val_loss: 1.2140 - val_accuracy: 0.6431
Epoch 8/10
92/92 [==============================] - 1s 10ms/step - loss: 0.1024 - accuracy: 0.9703 - val_loss: 1.5144 - val_accuracy: 0.6240
Epoch 9/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0736 - accuracy: 0.9815 - val_loss: 1.7651 - val_accuracy: 0.5926
Epoch 10/10
92/92 [==============================] - 1s 10ms/step - loss: 0.0761 - accuracy: 0.9775 - val_loss: 2.0429 - val_accuracy: 0.5967

Visualize Trainingsergebnisse

Erstellen Sie Diagramme von Verlust und Genauigkeit auf die Ausbildung und Validierung setzt.

 acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss=history.history['loss']
val_loss=history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
 

png

Wie Sie aus den Plots sehen können, Training Genauigkeit und Validierung Genauigkeit von großem Spielraum und das Modell erreichte nur etwa 60% Genauigkeit auf dem Validierungssatz ab.

Schauen wir uns an, was schief gelaufen ist und versuchen, die Gesamtleistung des Modells zu erhöhen.

Überanpassung

In den Plots oben ist die Trainingsgenauigkeit linear über die Zeit zu erhöhen, während Validierungsgenauigkeit abgewürgt etwa 60% in dem Trainingsprozess. Auch der Unterschied in der Genauigkeit zwischen Ausbildung und Validierung Genauigkeit bemerkbar-ein Zeichen von Überanpassung .

Wenn es eine kleine Anzahl von Trainingsbeispielen, manchmal das Modell lernt von Geräuschen oder unerwünschten Details aus Trainingsbeispielen zu einem Ausmaß, dass sie die Leistung des Modells negativ Auswirkungen auf neue Beispielen. Dieses Phänomen ist bekannt als Überanpassung. Es bedeutet, dass das Modell eine schwierige Zeit verallgemeinernde auf einen neuen Datensatz hat.

Es gibt mehrere Möglichkeiten, in den Trainingsprozess zu bekämpfen Überanpassung. In diesem Tutorial werden Sie Daten Augmentation und fügen Dropout zu Ihrem Modell verwenden.

Daten Augmentation

Überanpassung erfolgt in der Regel, wenn es eine kleine Anzahl von Trainingsbeispielen ist. Datenvergrößerung führt den Ansatz der Generierung zusätzlicher Trainingsdaten aus den vorhandenen Beispielen durch Vermehrung dann zufällig Transformationen , die glaubwürdig aussehende Bilder ergeben. Dies hilft, um das Modell zu mehreren Aspekten der Daten aussetzen und besser verallgemeinern.

Wir werden Daten Augmentation mit experimentellen implementieren Keras Preprocessing Ebenen . Diese können in Ihrem Modell wie andere Schichten enthalten sein, und auf der GPU ausgeführt werden.

 data_augmentation = keras.Sequential(
  [
    layers.experimental.preprocessing.RandomFlip("horizontal", 
                                                 input_shape=(img_height, 
                                                              img_width,
                                                              3)),
    layers.experimental.preprocessing.RandomRotation(0.1),
    layers.experimental.preprocessing.RandomZoom(0.1),
  ]
)
 

Lassen Sie uns zu visualisieren, was ein paar Augmented Beispiele sehen aus wie von Datenvergrößerung auf das gleiche Bild mehrmals die Anwendung:

 plt.figure(figsize=(10, 10))
for images, _ in train_ds.take(1):
  for i in range(9):
    augmented_images = data_augmentation(images)
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(augmented_images[0].numpy().astype("uint8"))
    plt.axis("off")
 

png

Wir werden Daten Vergrößerung verwenden, um ein Modell in einem Moment zu trainieren.

Aussteigen

Eine weitere Technik zur Reduzierung Überanpassung ist die Einführung Dropout an das Netzwerk, eine Form der Regularisierung.

Wenn Sie Dropout auf eine Ebene anwenden fällt es zufällig aus (durch die Aktivierung auf Null) eine Anzahl von Ausgabeeinheiten aus der Schicht während des Trainingsprozesses. Dropout nimmt eine Bruchzahl als Eingangswert in der Form, wie beispielsweise 0,1, 0,2, 0,4, usw. Das bedeutet 10% Abbruch, 20% oder 40% der Ausgangseinheiten zufällig aus der aufgebrachten Schicht.

Lassen Sie uns ein neues neuronales Netzwerk erstellen layers.Dropout , dann trainieren sie vermehrt Bilder verwenden.

 model = Sequential([
  data_augmentation,
  layers.experimental.preprocessing.Rescaling(1./255),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Dropout(0.2),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
 

Kompilieren und trainieren das Modell

 model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
 
 model.summary()
 
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
sequential_1 (Sequential)    (None, 180, 180, 3)       0         
_________________________________________________________________
rescaling_2 (Rescaling)      (None, 180, 180, 3)       0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 180, 180, 16)      448       
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 90, 90, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 90, 90, 32)        4640      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 45, 45, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 45, 45, 64)        18496     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 22, 22, 64)        0         
_________________________________________________________________
dropout (Dropout)            (None, 22, 22, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 30976)             0         
_________________________________________________________________
dense_2 (Dense)              (None, 128)               3965056   
_________________________________________________________________
dense_3 (Dense)              (None, 5)                 645       
=================================================================
Total params: 3,989,285
Trainable params: 3,989,285
Non-trainable params: 0
_________________________________________________________________

 epochs = 15
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
 
Epoch 1/15
92/92 [==============================] - 2s 20ms/step - loss: 1.4842 - accuracy: 0.3279 - val_loss: 1.0863 - val_accuracy: 0.5640
Epoch 2/15
92/92 [==============================] - 1s 12ms/step - loss: 1.1215 - accuracy: 0.5284 - val_loss: 1.0374 - val_accuracy: 0.6022
Epoch 3/15
92/92 [==============================] - 1s 12ms/step - loss: 0.9680 - accuracy: 0.6117 - val_loss: 0.9200 - val_accuracy: 0.6485
Epoch 4/15
92/92 [==============================] - 1s 12ms/step - loss: 0.8538 - accuracy: 0.6753 - val_loss: 0.9206 - val_accuracy: 0.6417
Epoch 5/15
92/92 [==============================] - 1s 12ms/step - loss: 0.7744 - accuracy: 0.6977 - val_loss: 0.8169 - val_accuracy: 0.6839
Epoch 6/15
92/92 [==============================] - 1s 13ms/step - loss: 0.7758 - accuracy: 0.7093 - val_loss: 0.7743 - val_accuracy: 0.6880
Epoch 7/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6805 - accuracy: 0.7481 - val_loss: 0.8598 - val_accuracy: 0.6540
Epoch 8/15
92/92 [==============================] - 1s 13ms/step - loss: 0.7132 - accuracy: 0.7278 - val_loss: 0.7177 - val_accuracy: 0.7207
Epoch 9/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6634 - accuracy: 0.7580 - val_loss: 0.7152 - val_accuracy: 0.7166
Epoch 10/15
92/92 [==============================] - 1s 13ms/step - loss: 0.6562 - accuracy: 0.7538 - val_loss: 0.7251 - val_accuracy: 0.7248
Epoch 11/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5798 - accuracy: 0.7840 - val_loss: 0.7016 - val_accuracy: 0.7357
Epoch 12/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5635 - accuracy: 0.7913 - val_loss: 0.7755 - val_accuracy: 0.7248
Epoch 13/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5361 - accuracy: 0.7982 - val_loss: 0.7575 - val_accuracy: 0.7153
Epoch 14/15
92/92 [==============================] - 1s 13ms/step - loss: 0.5420 - accuracy: 0.8022 - val_loss: 0.7375 - val_accuracy: 0.7302
Epoch 15/15
92/92 [==============================] - 1s 12ms/step - loss: 0.5132 - accuracy: 0.8120 - val_loss: 0.7561 - val_accuracy: 0.7289

Visualize Trainingsergebnisse

Nach Anlegen von Daten Augmentation und Dropout, gibt es weniger Überanpassung als zuvor, und die Ausbildung und Validierungsgenauigkeit näher ausgerichtet ist.

 acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
 

png

Predict auf neue Daten

Schließlich wollen wir unser Modell verwenden, um ein Bild zu klassifizieren, die nicht in der Ausbildung oder Validierungssätze enthalten war.

 sunflower_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg"
sunflower_path = tf.keras.utils.get_file('Red_sunflower', origin=sunflower_url)

img = keras.preprocessing.image.load_img(
    sunflower_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch

predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])

print(
    "This image most likely belongs to {} with a {:.2f} percent confidence."
    .format(class_names[np.argmax(score)], 100 * np.max(score))
)
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/592px-Red_sunflower.jpg
122880/117948 [===============================] - 0s 0us/step
This image most likely belongs to sunflowers with a 89.39 percent confidence.