Freigeben über


Erstellen Eines eigenen Bildklassifizierers mithilfe von Transfer Learning

Inhaltsverzeichnis

Zusammenfassung

imageimageimageimage

Die obigen Bilder sind Testbilder, die im zweiten Teil dieses Lernprogramms verwendet werden. Die Aufgabe besteht darin, einen Klassifizierer zu trainieren, der verschiedene Kategorien von Bildern (in unserem Beispiel Schaf und Wolf) durch Ändern eines vorhandenen Klassifizierermodells, des Basismodells, unterscheiden kann. Hier verwenden wir ein ResNet_18 Modell, das im ImageNet-Korpus trainiert wurde. Wir trainieren nur 15 Bilder pro Klasse in wenigen Sekunden und prognostizieren alle 10 Testbilder richtig (beachten Sie die wenigen Salzkornen).

Im Folgenden finden Sie die wichtigsten Ressourcen für das Lernprogramm für den Transfer:

Rezept TransferLearning.py und TransferLearning_Extended.py (siehe Beispiele/Image/TransferLearning).
vorab trainierte Modelle Als Basismodell für Transferlernen verwenden wir ein vortrainiertes ResNet_18-Modell.
Daten Die Blumendatensätze mit 102 Kategorien und Beispielbildern von Schafen und Wolfen (siehe Setup).
So wird's ausgeführt Folgen Sie der nachstehenden Beschreibung.

Setup

Um den Code in diesem Beispiel auszuführen, benötigen Sie eine CNTK Python-Umgebung (siehe hier zur Setuphilfe).

Um die erforderlichen Daten herunterzuladen und das vortrainierte Modell führen Sie den folgenden Befehl aus dem Ordner "Beispiele/Image/TransferLearning " aus:

python install_data_and_model.py

Ausführen des Beispiels

imageimageimageimage

In diesem Abschnitt erstellen wir einen Klassifizierer für den Blumen-Datensatz. Der Datensatz wurde von der Visual Geometry Group an der Universität Oxford für Bildklassifizierungsaufgaben erstellt. Es besteht aus 102 verschiedenen Kategorien von Blumen, die für großbritannien gemeinsam sind und ungefähr 8000 Bilder enthalten, die in drei Sätze von einmal 6000 und zweimal 1000 Bildern unterteilt sind. Weitere Details finden Sie auf der VGG-Homepage.

So trainieren und bewerten Sie ein Transfer-Lernmodell im Datensatz "Blumen"

python TransferLearning.py

Das Modell erreicht 93 % Genauigkeit auf dem Blumen-Datensatz nach dem Training für 20 Epochen.

Grundlegendes Konzept des Transferlernens

Wenn wir ein Basismodell zum Transfer-Lernen verwenden, bauen wir im Wesentlichen auf die Features und Konzepte, die während der Schulung des Basismodells gelernt wurden. Bei einem konvolutierenden DNN ResNet_18 in unserem Fall bedeutet dies beispielsweise, dass wir die endgültige dichte Schicht abschneiden , die für die Prognose der Klassenbezeichnungen des ursprünglichen Basismodells verantwortlich ist und durch eine neue dichte Ebene ersetzt wird, die die Klassenbeschriftungen unserer neuen Aufgabe vorhersagt. Die Eingabe an die alte und neue Vorhersageebene ist identisch, wir verwenden einfach die trainierten Features. Anschließend trainieren wir dieses geänderte Netzwerk, entweder nur die neuen Gewichte der neuen Vorhersageschicht oder alle Gewichtungen des gesamten Netzwerks.

Der folgende Code ist der Teil TransferLearning.py , der das neue Modell aus dem Basismodell erstellt:

    # Load the pretrained classification net and find nodes
    base_model   = load_model(base_model_file)
    feature_node = find_by_name(base_model, feature_node_name)
    last_node    = find_by_name(base_model, last_hidden_node_name)

    # Clone the desired layers with fixed weights
    cloned_layers = combine([last_node.owner]).clone(
        CloneMethod.freeze if freeze else CloneMethod.clone,
        {feature_node: Placeholder(name='features')})

    # Add new dense layer for class prediction
    feat_norm  = input_features - Constant(114)
    cloned_out = cloned_layers(feat_norm)
    z          = Dense(num_classes, activation=None, name=new_output_node_name) (cloned_out)

Erstellen Eines eigenen benutzerdefinierten Bildklassifizierers

Im vorherigen Abschnitt haben wir einen Klassifizierer trainiert, der 102 verschiedene Kategorien von Blumen mit etwa 6000 Bildern für Schulungen unterscheidet. In diesem Abschnitt verwenden wir nur 15 Bilder pro Kategorie, um einen Klassifizierer zu erstellen, der einen Wolf von einem Schaf erzählen kann. Wir verwenden das gleiche ResNet_18 Basismodell für transfer learning. So trainieren und bewerten Sie den Modelllauf

python TransferLearning_Extended.py

Das Modell wird auf fünf Bildern von Schafen und Wolf getestet und prognostiziert alle Bezeichnungen richtig. Die Ausgabedatei enthält pro Zeile eine JSON-Darstellung der Prognoseergebnisse:

[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":0.997, "Wolf":0.003}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.994, "Wolf":0.006}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.614, "Wolf":0.386}, "image": "..."}]
[{"class": "unknown", "predictions": {"Wolf":0.980, "Sheep":0.020}, "image": "..."}]

Beachten Sie, dass die letzten drei Bilder keine Boden-Wahrheitsklasse zugewiesen haben, die natürlich ein gültiges Szenario ist, z. B. zum Bewerten nicht angezeigter Bilder in einem Webdienst. Die tatsächlichen Bilder sind die drei Vogelbilder, die unten gezeigt werden. Die Grund-Wahrheitsklasse für diese in der JSON-Ausgabe ist auf unknownfestgelegt. Beachten Sie, dass die Vorhersagen für die Konzepte, auf die der Klassifizierer trainiert wurde, trotz der wenigen Schulungsbilder ziemlich gut sind. Dies ist in großen Teilen aufgrund des vortrainierten Basismodells. Die Prognosen für nicht angezeigte Konzepte, z. B. Bilder von Vögeln, sind natürlich nicht sehr sinnvoll, da der Klassifizierer nur Schafe und Wolf kennt. Weitere Informationen dazu später.

imageimageimage

Ordnerstruktur für benutzerdefinierte Bildsätze

Sie können das TransferLearning_Extended.py Skript mit ihren eigenen Bildern verwenden. Hier erfahren Sie, was Sie benötigen:

  1. class_mapping - Ein Array, das die Namen Ihrer Kategorien enthält, z. B. ['wolf', 'sheep']
  2. train_map_file - Eine Textdatei, die zuerst eine Bild-URL enthält und die Registerkarte den entsprechenden Kategorieindex getrennt hat, z. B. 0 für Wolf oder 1 Schafe:
  3. test_map_file - Eine Textdatei, in der die Karten Bilder ihrer entsprechenden Kategorie testen. Für unbekannte Kategorien in Testbildern wird als Kategorieindex verwendet -1 .

Das Skript kann alle drei oben genannten Elemente für Sie generieren, wenn Sie Ihre Bilder auf folgende Weise strukturieren:

<image root folder>
    Train
        Sheep
        Wolf
    Test
        Sheep
        Wolf
        <optional: image files with unknown label directly here>

Sehen Sie <cntk root>/Examples/Image/DataSets/Animals/ sich ein Beispiel an. Jeder Unterordner im Train Ordner wird als eine Kategorie betrachtet (nur eine Ebene, keine Rekursion). Für die Schulung einzelner Bilder im Train Stammordner werden ignoriert, da sie keine zugewiesene Kategorie haben. Zusätzliche Unterordner im Ordner, die Test nicht im Train Ordner auftreten, werden ignoriert. Zum Testen einzelne uncategorisierter Bilder werden auch zur Bewertung verwendet, d. h. Bilder, die direkt im Ordner wie die drei Vogelbilder in Test unserem Beispiel gespeichert werden.

Um Ihre benutzerdefinierten Bildordner zu verwenden, müssen Sie am test_image_folder oberen Rand des TransferLearning_Extended.py Skripts festlegentrain_image_folder:

# define data location and characteristics
train_image_folder = "<your_image_root_folder>/Train"
test_image_folder = "<your_image_root_folder>/Test"

Führen Sie dann einfach aus python TransferLearning_Extended.py. Die Verwendung eines anderen Basismodells wird unten beschrieben.

Für die Bewertung müssen test_map_fileSie keine einzelnen Bilder verwenden, z. B. wenn Sie einzelne Bilder nacheinander bewerten möchten. Laden Sie einfach einmal das trainierte Transfer-Lernmodell und rufen eval_single_image Sie dann an, wann immer Sie Vorhersagen für ein neues Bild erhalten möchten:

    # once:
    # load the trained transfer learning model
    trained_model = load_model(new_model_file)

    # for every new image:
    # get predictions for a single image
    probs = eval_single_image(trained_model, img_file, image_width, image_height)

Ein paar Getreide von Salz

Ihre Schulungsbilder sollten ausreichend die Szenarien abdecken, die Sie später scoren möchten. Wenn der Klassifizierer vollständig neue Konzepte oder Kontexte sieht, wird es wahrscheinlich schlecht ausgeführt. Nur ein paar Beispiele:

  • Sie trainieren nur Bilder aus einer Einschränkungsumgebung (z. B. Innen) und versuchen, Bilder aus einer anderen Umgebung (außen) zu scoren.
  • Sie trainieren nur auf Bildern eines bestimmten Make und versuchen, andere zu scoren.
  • Ihre Testbilder haben weitgehend unterschiedliche Merkmale, z. B. im Hinblick auf Beleuchtung, Hintergrund, Farbe, Größe, Position usw.
  • Ihre Testbilder enthalten völlig neue Konzepte.

Das Hinzufügen einer Fangen-All-Kategorie kann eine gute Idee sein, aber nur, wenn die Schulungsdaten für diese Kategorie Bilder enthalten, die wieder ausreichend ähnlich sind wie die Bilder, die Sie zur Bewertungszeit erwarten. Wie im obigen Beispiel, wenn wir einen Klassifizierer mit Bildern von Schafen und Wolf trainieren und es zum Scoren eines Bilds eines Vogels verwenden, kann der Klassifizierer weiterhin nur ein Schaf oder eine Wolfsbezeichnung zuweisen, da es keine anderen Kategorien kennt. Wenn wir eine Kategorie hinzufügen und Schulungsbilder von Vögeln hinzufügen, könnte der Klassifizierer die Klasse für das Vogelbild richtig voraussagen. Wenn wir es jedoch präsentieren, z. B. ein Bild eines Autos, sieht es das gleiche Problem wie zuvor aus, wie es nur Schafe, Wolf und Vogel kennt (was wir gerade als Fang-All bezeichnet haben). Daher muss Ihre Schulungsdaten, auch für fangend, ausreichend diese Konzepte und Bilder abdecken, die Sie später zur Bewertungszeit erwarten.

Ein weiterer Aspekt, der berücksichtigt werden soll, ist, dass ein bestimmtes Basismodell sehr gut für einige Transfer-Lernaufgaben und nicht so gut für andere funktioniert. Das obige ResNet_18 Modell wurde beispielsweise auf dem ImageNet-Korpus vortrainiert, das viele Bilder von Tieren, Menschen, Autos und vielen anderen täglichen Objekten enthält. Die Verwendung dieses Basismodells im Transfer-Lernen zum Erstellen eines Klassifizierers für ähnliche Tägliche Objekte kann gut funktionieren. Das gleiche Modell wie ein Basismodell zum Erstellen eines Klassifizierers für Bilder von Mikroorganismen oder Bleistiftzeichnungen kann nur mittelmäßigen Ergebnissen liefern.

Verwenden eines anderen Basismodells

Um ein anderes Modell als Basismodell zu verwenden, müssen Sie die folgenden Parameter TransferLearning.py anpassen (gleiches für TransferLearning_Extended.py):

# define base model location and characteristics
_base_model_file = os.path.join(base_folder, "..", "..", "..", "PretrainedModels", "ResNet_18.model")
_feature_node_name = "features"
_last_hidden_node_name = "z.x"
_image_height = 224
_image_width = 224
_num_channels = 3

Um zu untersuchen, welche Knotennamen sich in Ihrem Modell befinden und welche sie auswählen möchten, da last_hidden_node Sie alle Knotennamen und Knotenformen mithilfe der folgenden Zeilen drucken können (siehe __main__ Methode in TransferLearning.py):

    # You can use the following to inspect the base model and determine the desired node names
    node_outputs = get_node_outputs(load_model(_base_model_file))
    for out in node_outputs: print("{0} {1}".format(out.name, out.shape))