Sent from Hauptstadt!

ein Blog für den geneigten Leser

Kaputte Bilddateien mit TensorFlow finden

Tags: ,

Kategorie Software Engineering | Keine Kommentare »

Ich spiele mal wieder etwas mit TensorFlow rum, denn ich will endlich das gesellschaftlich sehr relevante Problem lösen, Hunde- und Katzenbilder automatisiert zu unterscheiden. Dabei stolpere ich über alle Anfängerfehler, etwa wie man kaputte Bilddateien erkennt.

Im Internet gibt es viele Datensätze für KI Experimente, etwa eine Sammlung mit 25.000 Hunde- und Katzenbilder. Normalerweise sollte man diese Bilder mittels folgender Anweisung vollautomatisch herunterladen und einbinden können:

import tensorflow_datasets as tfds

(raw_training, raw_validation, raw_testing), metadata = tfds.load(
    'cats_vs_dogs',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Leider klappt das momentan nicht, weil anscheinend eine alte URL hinterlegt ist.

Deshalb habe ich den gesamten Datensatz direkt heruntergeladen und in ein Verzeichnis „cats_vs_dogs/“ unterhalb meines Jupyter Notebooks entpackt. Alle Hundebilder befinden sich im Unterordner „dog/“ und alle Katzenbilder in „cat/“.

Leider gibt es im offiziellen Datensatz viele korrupte Bilddateien, die sich nicht laden lassen. Die offizielle Seite spricht von gut 1.700 kaputten Dateien. Um möglichst viele Dateien und damit Beispiele zu retten, öffne und speichere ich jede Bilddatei mit dem sehr robusten Kommandozeilenwerkzeug ImageMagick neu:

mogrify -set comment "image rewritten with ImageMagick" *.jpg

Anschließend habe ich die Bilddateien in meinem Jupyter Notebook folgendermaßen eingelesen:

import matplotlib.pyplot as plt
import tensorflow as tf

batch_size = 32
img_height = 128
img_width = 128

train_ds = tf.keras.utils.image_dataset_from_directory(
    'cats_vs_dogs',
    validation_split=0.1,
    subset='training',
    seed=123,
    image_size=(img_height, img_width), 
    batch_size=batch_size
    )
val_ds = tf.keras.utils.image_dataset_from_directory(
    'cats_vs_dogs',
    validation_split=0.1,
    subset='validation',
    seed=123,
    image_size=(img_height, img_width), 
    batch_size=batch_size
    )

Anschließend erstelle ich mein Modell und versuche es mit dem Trainingsdatensatz train_ds zu trainieren. Nach Verarbeitung von ca. 2/3 der Trainingsbilder bricht das Training mit einer wenig hilfreichen Fehlermeldung ab:

InvalidArgumentError: Input is empty.
	 [[{{node decode_image/DecodeImage}}]] [Op:IteratorGetNext]

Meine Vermutung: Mindestens eine der Bilddateien ist immer noch kaputt, nur welche von den 25.000? Als lang gedienter Internetnutzer bin ich im Durchschauen von Katzen- und Hundebildern geübt, verspüre aber trotzdem irgendwie keine Lust auf eine Scroll- und Klickorgie. Ein manuelles Durchsuchen der Bilder könnte auch ergebnislos bleiben, denn vielleicht kann ja nur die von TensorFlow genutzte Grafikbibliothek die Datei nicht richtig laden, aber eine andere Anwendung schon?

Deshalb möchte ich jedes Bild mit der TensorFlow Funktion tf.image.decode_image laden und habe folgendes kleines Python Skript geschrieben:

from os import listdir

for filename in listdir('cats_vs_dogs/dog'):
    fullname = 'cats_vs_dogs/dog/' + filename
    with open(fullname, mode='rb') as f:
        image = f.read()

        try:
            tf.image.decode_image(image)
        except Exception:
            print(fullname)

Dieses Skript lädt alle Hundebilder und gibt die Namen der Dateien aus, die TensorFlow nicht laden kann. Damit konnte ich die restlichen kaputten Dateien finden und anschließend löschen. Schlußendlich habe ich aus dem ursprünglichen Datensatz lediglich eine handvoll Beispielbilder entfernen müssen. Ich konnte also fast alle 1.700 kaputten Bilder retten!

Mein Modell zur Klassifizierung von Hunde- und Katzenbildern zeige ich an dieser Stelle lieber nicht, denn so richtig toll funktioniert es noch nicht. Es bleibt also noch Arbeit, um die Welt zu retten!

Schreiben sie ein Kommentar