TensorFlow-Tutorial. Teil 3: Datenmanagement

8 min read

TensorFlow-Tutorial. Teil 3

Es ist an der Zeit mit echten Daten zu arbeiten! Wir werden mit belgischen Verkehrszeichen arbeiten. Verkehr ist ein einfaches Thema, aber bevor wir mit der Programmierung beginnen, klären wir, welche Daten im Datensatz enthalten sind.

In diesem Artikel erhalten Sie alle Informationen, die Sie benötigen, um das Tutorial weiter zu studieren:

  • In Belgien ist der Text auf Verkehrszeichen in der Regel in Niederländisch und Französisch. Dies muss man wissen, aber für den Datensatz, mit dem Sie arbeiten werden, ist es nicht allzu wichtig!
  • In Belgien gibt es sechs Kategorien von Verkehrszeichen: Warnzeichen, Vorfahrtszeichen, Verbotszeichen, Gebotszeichen, Parkplatzschilder und Verkehrseinrichtungen.
  • Am 1. Januar 2017 wurden mehr als 30.000 Verkehrszeichen von den belgischen Straßen entfernt. Es waren Verbotszeichen, die die Höchstgeschwindigkeit der Fahrt begrenzten.
  • Die Entfernung von Zeichen steht im Zusammenhang mit einer langen Diskussion in Belgien (und in der gesamten Europäischen Union) über die übermäßige Anzahl von Verkehrszeichen.

Daten herunterladen

Wenn Sie nun mit den Besonderheiten des belgischen Verkehrs vertraut sind, müssen Sie den Datensatz herunterladen. Unter “BelgienTS for Classification (Cropped Images)” müssen Sie zwei Zip-Dateien mit den Namen “BelgiumTSC_Training” und “BelgiumTSC_Testing” herunterladen.

Ein Hinweis. Wenn Sie Dateien heruntergeladen haben oder dies nach dem Lesen des Tutorials tun, werfen Sie einen Blick auf die Struktur der Ordner, die Sie heruntergeladen haben! Sie werden sehen, dass die Test- und Lernordner 61 Unterordner enthalten, die den 61 Arten von Verkehrszeichen entsprechen, die Sie in diesem Tutorial zur Klassifizierung verwenden werden. Sie werden auch feststellen, dass die Dateien die Erweiterung.ppm oder Portable Pixmap Format haben. Sie haben Bilder von Verkehrszeichen heruntergeladen!

Beginnen wir mit dem Import von Daten in den Arbeitsbereich. Beginnen wir mit den Codezeilen, die unter der Benutzerfunktion load_data() angezeigt werden:

  • Installieren Sie zuerst ROOT_PATH. Dies ist der Pfad zu dem Dateiverzeichnis, das die Daten für das Training und Testen enthält.
  • Fügen Sie dann mit join() Pfade zu Ihrem ROOT_PATH hinzu. Speichern Sie diesen Pfad in train_data_directory und test_data_directory.
  • Sie werden sehen, dass Sie dann die Funktion load_data() aufrufen und train_data_directory an sie weitergeben können.
  • Jetzt wird load_data() Funktion selbst gestartet, indem alle Unterverzeichnisse, die sich im train_data_directory befinden, gesammelt werden.
  • Dann müssen Sie durch die Unterverzeichnisse gehen. Zuerst initialisieren Sie die beiden Listen, labels und images. Danach sammeln Sie die Unterverzeichnispfade und Bilddateinamen, die in diesen Unterverzeichnissen gespeichert sind. Anschließend können Sie mit dem Befehl append() Daten in zwei Listen sammeln.
def load_data(data_directory):

directories = [d for d in os.listdir(data_directory)

if os.path.isdir(os.path.join(data_directory, d))]

labels = []

images = [] for d in directories:

label_directory = os.path.join(data_directory, d)

file_names = [os.path.join(label_directory, f)

for f in os.listdir(label_directory)

if f.endswith(".ppm")]

for f in file_names:

images.append(skimage.data.imread(f))

labels.append(int(d))

return images, labels

ROOT_PATH = "/your/root/path"

train_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Training")

test_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Testing")

images, labels = load_data(train_data_directory)

Wir möchten Sie darauf hinweisen, dass sich die Daten für das Training und Testen im obigen Block in Ordnern mit den Namen “training” und “testing” befinden, die Unterverzeichnisse eines anderen “TrafficSigns”-Verzeichnisses sind. Auf dem Computer kann dies so aussehen: “/User /Name /Downloads /TrafficSigns” und dann zwei Unterordner namens “training” und “testing”.

Datenrecherche

Wenn die Daten hochgeladen sind, müssen Sie sie recherchieren! Zuerst können Sie eine Elementaranalyse mit Hilfe von ndim und size des Bildarrays durchführen:

Beachten Sie, dass images und labels Listen sind, deshalb müssen Sie möglicherweise np.array() verwenden, um die Variablen in ein Array im Arbeitsbereich zu konvertieren. Hier ist es für Sie schon erledigt!

# Output dimension 'images'
print(images.ndim)

# Output number of elements in 'images'
print(images.size)

# Output 1st value 'images'
images[0]

Achten Sie darauf, dass der von Ihnen ausgegebene Wert für images [0] tatsächlich ein Bild ist, das durch Arrays in einem Array dargestellt wird! Obwohl es unlogisch aussieht, gewöhnt man sich daran, wenn man mit Bildern in Machine- oder Deep Learning arbeitet.

Als Nächstes lassen Sie uns zu den Labels kommen, aber diesmal wird es keine Überraschungen geben:

# Output dimension 'labels'
print(labels.ndim)

# Output number of elemnts in 'labels'
print(labels.size)

# Output array length 'labels'
print(len(set(labels)))

Mit diesen Zahlen erhalten Sie eine Vorstellung davon, ob der Import richtig ist und wie groß Ihre Datenmenge ist. Im ersten Moment funktioniert alles so, wie Sie es erwartet haben, und Sie können sehen, dass die Größe des Arrays von Bedeutung ist, wenn Sie bedenken, dass Sie es mit Arrays innerhalb von Arrays zu tun haben.

Ein Hinweis: Versuchen Sie, die folgenden Attribute zu Ihren Arrays hinzuzufügen, um weitere Informationen über die Speicherzuweisung zu erhalten: Die Länge eines Array-Elements in Bytes und die Gesamtzahl der Bytes, die von Array-Elementen belegt werden: flags, itemsize und nbytes.

Sie können dann die Verteilung der Verkehrszeichen nach Typ untersuchen:

# Import module 'pyplot'
import matplotlib.pyplot as plt

# Build histogram with 64 points - values 'labels'
plt.hist(labels, 62)

# Output graph
plt.show()

Das ist großartig! Werfen wir einen Blick aufs Histogramm:

Die Tatsache, dass nicht alle Arten von Verkehrszeichen im Datensatz gleichermaßen dargestellt werden, ist klar. Dieses Problem wird Ihnen später begegnen, wenn Sie mit den Daten arbeiten, bevor Sie mit der Modellierung Ihres neuronalen Netzwerks beginnen. Die Anzahl der Typen 22, 32, 38 und 61 setzt sich auf den ersten Blick eindeutig gegen die anderen durch.

Datenvisualisierung

Sie haben bereits eine kleine Vorstellung von den Daten. Aber wenn es sich bei den Daten um Bilder handelt, müssen sie natürlich visualisiert werden.

Lassen Sie uns einige zufällige Zeichen betrachten:

  • Achten Sie zunächst darauf, dass Sie das pyplot-Modul des matplotlib-Pakets unter dem gemeinsamen Namen plt importieren.
  • Dann erstellen Sie eine Liste mit 4 Zufallszahlen. Sie werden verwendet, um Verkehrszeichen aus dem images-Array auszuwählen, das im letzten Abschnitt heruntergeladen wurde. Im folgenden Beispiel sind dies die Zahlen 300, 2.250, 3.650 und 4.000.
  • Danach erstellen Sie für jedes Element dieser Liste, von 0 bis 4, Diagramme ohne Achsen (damit sie den Fokus auf Bilder nicht stören). Diese Diagramme zeigen spezifische Bilder aus images-Array, die der i-Indexnummer entsprechen. Im ersten Schritt der Schleife erhalten Sie i = 300, im zweiten Schritt – 2.250 und so weiter. Zuletzt ist es notwendig, die Diagramme so anzuordnen, dass genügend Platz zwischen ihnen vorhanden ist.
  • Abschließend stellen Sie Ihre Diagramme mit der Funktion show() dar!

Code:

# Import module 'pyplot' 'matplotlib`

import matplotlib.pyplot as plt

# Input (random) numbers of images, which you want to output

traffic_signs = [300, 2250, 3650, 4000]

# Filling graphs with images

for i in range(len(traffic_signs)):
plt.subplot(1, 4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()

Wie Sie vermuten können, unterscheiden sich die Zeichen jedes der 62 Typen voneinander.

Doch was kann man noch sehen? Werfen wir einen Blick auf die folgenden Bilder:

Diese vier Bilder haben unterschiedliche Größen!

Selbstverständlich können Sie mit den Zahlen in der traffic_signs-Liste spielen und mehr darüber erfahren, aber trotzdem ist dies eine wichtige Nuance, auf die Sie achten müssen, wenn Sie mit den Daten arbeiten, die in das neuronale Netzwerk eingegeben werden müssen.

Lassen Sie uns die Hypothese verschiedener Größen bestätigen, indem wir die Auflösung der Bilder anzeigen, d.h. die Minimal- und Maximalwerte der einzelnen angezeigten Bilder.

Dieser Code ähnelt dem Code, der bei der Erstellung des Diagramms verwendet wurde, unterscheidet sich aber dadurch, dass nicht nur das Bild angezeigt wird, sondern auch seine Größe:

# Import 'matplotlib'

import matplotlib.pyplot as plt

# Input (random) numbers of images, which you want to output

traffic_signs = [300, 2250, 3650, 4000]

# Filling graphs with images and dimension output

for i in range(len(traffic_signs)):
plt.subplot(1, 4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()

print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape, images[traffic_signs[i]].min(), images[traffic_signs[i]].max()))

Achten Sie darauf, wie Sie die format()-Methode im Zeil  “shape” verwenden: {0}, min: {1}, max: um die Argumente {0}, {1} und {2} einzugeben.

Nachdem Sie nun die Bilder selbst gesehen haben, können Sie zu dem Histogramm zurückkehren. Sie können dies ganz einfach tun, indem Sie ein Bild von jeder Art von Zeichen anzeigen:

# Import module 'pyplot' 'matplotlib'

import matplotlib.pyplot as plt

# Types description

unique_labels = set(labels)

# Graph initialization

plt.figure(figsize=(15, 15))

# Counter description

i = 1

# For each type:

for label in unique_labels:

# Choosing 1st image of each type:

image = images[labels.index(label)]

# 64 graphs description

plt.subplot(8, 8, i)

# Turning off axis

plt.axis('off')

# Adding label to each graph

plt.title("Label {0} ({1})".format(label, labels.count(label)))

# Increase counter by 1

i += 1

# Output 1st image

plt.imshow(image)

# Output the whole graph

plt.show()

Achten Sie darauf, dass selbst wenn Sie 64 Diagramme definieren, nicht alle von ihnen Bilder haben werden (da es nur 62 Arten von Zeichen gibt!). Bitte beachten Sie auch hier, dass Sie keine Achsen ausgeben, um Ablenkungen zu vermeiden.

Wie das Histogramm zeigt, ist die Anzahl der Fotos von Zeichen mit den Typen 22, 32, 38 und 61 viel höher als bei den anderen. Dies kann man aus der obigen Tabelle sehen: Es gibt 375 Bilder mit der Marke 22, 316 Bilder mit der Marke 32, 285 Bilder mit der Marke 38 und schließlich 282 Bilder mit der Marke 61.

Eine der spannendsten Fragen, die man sich jetzt stellen kann, ist, ob es einen Zusammenhang zwischen all diesen Zeichen gibt – vielleicht sind es alle Zeichen?

Lassen Sie es uns näher betrachten: Sie können sehen, dass die Bezeichnungen 22 und 32 Verbotszeichen sind, aber die Bezeichnungen 38 und 61 Index- bzw. Prioritätszeichen. Das bedeutet, dass es keine direkte Verbindung zwischen den vier Zeichen gibt, mit der Ausnahme der Tatsache, dass die Hälfte der in Datensätzen am häufigsten vertretenen Zeichen verboten ist.

Extrahieren von Schildern

Nun, da Sie Ihre Daten sorgfältig studiert haben, müssen Sie die Ärmel hochkrempeln! Lassen Sie uns kurz feststellen, dass Sie keine Punkte vergessen haben:

  • Bilder haben unterschiedliche Größen;
  • Es gibt 62 Etiketten (denken Sie daran, dass die Nummerierung der Etiketten mit 0 beginnt und mit 61 endet);
  • Die Verteilung der Verkehrszeichentypen ist eher ungleichmäßig; es besteht kein Zusammenhang zwischen den Zeichen, die im Datensatz in großer Zahl vorhanden sind.

Nachdem Sie nun eine klare Vorstellung davon haben, was Sie beachten müssen, können Sie die Daten für die Eingabe in das neuronale Netzwerk oder in ein beliebiges Modell vorbereiten, an das Sie sie weitergeben möchten. Beginnen wir mit dem Extrahieren der Zeichen. Sie müssen die gleiche Größe der Bilder erstellen und sie in einen Schwarz-Weiß-Bereich umwandeln. Dann müssen Sie die Bilder in Graustufen umwandeln, da die Farbe für die Klassifizierung weniger wichtig ist. Bei der Zeichenerkennung spielt die Farbe jedoch eine wichtige Rolle! In diesen Fällen muss daher die Umstellung nicht durchgeführt werden!

Bildskalierung

Um die Bildgrößen gleich zu machen, können Sie die skimage-Funktion oder die Scikit-Image-Bibliothek verwenden, die einen Satz von Algorithmen für die Bildverarbeitung darstellt.
In dem zweiten Fall ist das Transform-Modul hilfreich, da es die Funktion resize() hat; es verwendet die Listeneinbindung wieder, um die Snapshot-Auflösung auf 28×28 Pixel zu erhöhen. Nochmals, Sie werden sehen, dass Sie tatsächlich eine Liste erstellen – für jedes Bild im image-Array führen Sie eine Konvertierungsoperation durch, die Sie aus der skimage Bibliothek ausleihen. Schließlich speichern Sie das Ergebnis in images28:

# Import module 'transform' from 'skimage'

import transform

# Scaling images in 'image'

array images28 = [transform.resize(image, (28, 28)) for image in images]

Sieht ganz einfach aus, nicht wahr?

Achten Sie darauf, dass die Bilder nun vierdimensional sind: Wenn Sie images28 in ein Array konvertieren und das Shape-Attribut binden, können Sie sehen, dass die Größe von images28 gleich ist (4575, 28, 28, 28, 28, 3). Die Bilder sind 784-dimensional (weil Ihre Bilder 28 x 28 Pixel groß sind).

Um das Ergebnis der Skalierung zu überprüfen, verwenden Sie den oben verwendeten Code erneut, um 4 Zufallsbilder mit der Variablen traffic_signs zu erstellen; denken Sie einfach daran, Bilder in images28 zu ändern.

Das Ergebnis:

Beachten Sie: Die Werte von min und max haben sich seit dem Verkleinern auch geändert; jetzt liegen sie alle im gleichen Bereich, was wirklich cool ist, da Sie keine Daten-Normalisierung mehr durchführen müssen!

Konvertierung in Graustufen

Die Farbe auf den Fotos ist bei der Klassifizierung weniger wichtig, deshalb werden Sie auch mit dem Problem der Bildkonvertierung in Graustufen konfrontiert.

Man kann auch selbst überprüfen, was mit den Endergebnissen des Modells passiert, wenn Sie diesen Schritt nicht abschließen.

Wie bei der Skalierung können Sie auch hier die Scikit-Image-Bibliothek verwenden; in diesem Fall benötigen Sie ein color-Modul mit der Funktion rgb2gray().

Es wird leicht sein!

Aber vergessen Sie nicht, die Variable images28 in ein Array zu konvertieren, denn die Funktion rgb2gray() nimmt Arrays als Argument.

# Import `rgb2gray` from `skimage.color`

from skimage.color import rgb2gray

# Conversion `images28` into array

images28 = np.array(images28)

# Conversion `images28` into grey tones

images28 = rgb2gray(images28)

Überprüfen Sie das Ergebnis Ihrer Graustufenkonvertierung, indem Sie einige der Bilder ausgeben; verwenden Sie dazu einen leicht modifizierten Code:

import matplotlib.pyplot as plt

traffic_signs = [300, 2250, 3650, 4000]

for i in range(len(traffic_signs)):

plt.subplot(1, 4, i+1)

plt.axis('off')

plt.imshow(images28[traffic_signs[i]], cmap="gray") plt.subplots_adjust(wspace=0.5)

# Output graph

plt.show()

Sie müssen eine Farbkarte oder cmap angeben und den Wert auf “grau” setzen, um Graustufenbilder anzuzeigen. Die Ursache dafür ist, dass imshow() standardmäßig eine Heatmap verwendet.

Ein Hinweis: Da dieser Block im Tutorial mehrfach verwendet wird, ist es sinnvoll, sich zu überlegen, wie man ihn zu einer Funktion machen kann.

Diese beiden Schritte sind sehr einfach; andere Operationen, die Sie auf Momentaufnahmen anwenden können (Rotation, Unschärfe, Verschiebung, Helligkeitsänderung), führen zu einer Vergrößerung der Daten. Mithilfe dieser Funktion können Sie auch die gesamte Abfolge der Schritte automatisieren, die Sie mit Ihren Bildern durchführen.

Ist soweit verständlich wie TensorFlow funktioniert?

Wie setzt man KI in Ihrem Umfeld ein?

Diese und weitere Fragen beantwortet gerne das AI United Team per Email oder in dem Q&A Bereich.

Quelle

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.