[PYTHON] TensorFlow Tutorial-Bilderkennung (Übersetzung)

TensorFlow Tutorial (Bilderkennung) https://www.tensorflow.org/versions/master/tutorials/image_recognition Es ist eine Übersetzung von. Wir freuen uns darauf, auf Übersetzungsfehler hinzuweisen.


Unser Gehirn scheint das Sehen zu erleichtern. Man muss sich nicht bemühen, zwischen einem Löwen und einem Jaguar zu unterscheiden, ein Zeichen zu lesen und ein menschliches Gesicht zu erkennen. In Wirklichkeit sind dies jedoch Probleme, die auf einem Computer schwer zu lösen sind. Es scheint einfach zu sein, nur weil unser Gehirn sehr gut darin ist, Bilder zu verstehen.

In den letzten Jahren hat das Gebiet des maschinellen Lernens enorme Fortschritte bei der Bewältigung dieser schwierigen Probleme erzielt. Insbesondere ein Modelltyp namens Deep Convolution Neural Network weist bei schwierigen visuellen Erkennungsaufgaben eine anständige Leistung auf. Es stellt sich heraus, dass es im Bereich so gut oder besser sein kann als Menschen.

Forscher haben stetige Fortschritte im Bereich Computer Vision erzielt, indem sie ihre Erfolge mit ImageNet (akademischer Maßstab für Computer Vision) überprüft haben. Ich tat. QuocNet, [AlexNet](http://www.cs.toronto.edu/%7Efritz /absps/imagenet.pdf), Inception (GoogLeNet), BN-Inception-v2 usw. Die nacheinander erscheinenden Modelle zeigen weiterhin Verbesserungen und erzielen in jeder Phase Spitzenergebnisse. Forscher innerhalb und außerhalb von Google haben Artikel veröffentlicht, in denen diese Modelle beschrieben werden. Es ist jedoch immer noch schwierig, diese Ergebnisse zu reproduzieren. Wir machen den nächsten Schritt, indem wir den Code veröffentlichen, der die Bilderkennung für unser neuestes Modell Inception-v3 durchführt.

Inception-v3 wurde seit 2012 mit Daten für die groß angelegte visuelle Erkennungsherausforderung ImageNet trainiert. Dies ist eine Standardaufgabe in der Bildverarbeitung, bei der das Modell das gesamte Bild zur "1000-Klasse" (http://image-net.org/, wie "Shimauma", "Dalmesian", "Geschirrspüler") macht. Versuche, in Herausforderungen zu klassifizieren (LSVRC / 2014 / Blowse-Synsets). Beispielsweise klassifiziert AlexNet einige Bilder wie folgt:

図

Um die Modelle zu vergleichen, schauen Sie sich an, wie oft die vom Modell vorhergesagten Top 5 nicht die richtige Antwort hatten (als "Top 5-Fehlerrate" bezeichnet). AlexNet erreichte eine Top-5-Fehlerrate von 15,3% gegenüber dem Validierungsdatensatz 2012, BN-Inception-v2 erreichte 6,66% und Inception-v3 erreichte 3,46%.

Wie gut kann eine Person die ImageNet-Herausforderung ausführen? [Blog-Artikel] von Andrej Karpathy, der versuchte, seine eigene Leistung zu messen (http://karpathy.github.io/2014/09/02/what-i-learned-from-competing-against-a-convnet-on- Es gibt imagenet /). Er hatte eine Top 5 Fehlerrate von 5,1%.

In diesem Tutorial erfahren Sie, wie Sie [Inception-v3] verwenden (http://arxiv.org/abs/1512.00567). Erfahren Sie, wie Sie Bilder in Python oder C ++ in 1000 Klassen klassifizieren. Außerdem wird beschrieben, wie Sie aus diesem Modell höhere Funktionen extrahieren, die für andere Sehaufgaben wiederverwendet werden können.

Wir freuen uns, uns vorstellen zu können, dass die Community dieses Modell ist.

Verwendung in der Python-API

Wenn Sie das Programm classify_image.py zum ersten Mal ausführen, wird das trainierte Modell von tensorflow.org heruntergeladen. Sie benötigen ca. 200 Millionen verfügbaren freien Speicherplatz auf Ihrer Festplatte.

Bei den folgenden Schritten wird davon ausgegangen, dass Sie TensorFlow aus dem PIP-Paket installiert haben und sich Ihr Terminal im TensorFlow-Stammverzeichnis befindet.

cd tensorflow/models/image/imagenet
python classify_image.py

Der obige Befehl klassifiziert das Bild eines bestimmten Pandas.

図

Wenn das Modell korrekt ausgeführt wird, erzeugt das Skript eine Ausgabe ähnlich der folgenden:

giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca (score = 0.88493)
indri, indris, Indri indri, Indri brevicaudatus (score = 0.00878)
lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens (score = 0.00317)
custard apple (score = 0.00149)
earthstar (score = 0.00127)

Sie können andere JPEG-Bilder angeben, indem Sie das Argument --image_file bearbeiten.

Wenn Sie die Modelldaten in ein anderes Verzeichnis herunterladen möchten, müssen Sie das Verzeichnis angeben, das für --model_dir verwendet werden soll.

Verwendung in der C ++ API

Das gleiche Modell Inception-v3 kann in C ++ für Produktionsumgebungen ausgeführt werden. Sie können ein Archiv herunterladen, das GraphDef enthält und ein solches Modell definiert (indem Sie es aus dem Stammverzeichnis des TensorFlow-Repositorys ausführen):

wget https://storage.googleapis.com/download.tensorflow.org/models/inception_dec_2015.zip -O tensorflow/examples/label_image/data/inception_dec_2015.zip

unzip tensorflow/examples/label_image/data/inception_dec_2015.zip -d tensorflow/examples/label_image/data/

Als Nächstes müssen Sie eine C ++ - Binärdatei kompilieren, die den Code enthält, der das Diagramm lädt und ausführt. Wenn Sie TensorFlow von der Quelle auf Ihrer Plattform installiert haben (http://www.tensorflow.org/versions/master/get_started/os_setup.html#source), führen Sie den folgenden Befehl von Ihrem Shell-Terminal aus: Sie sollten in der Lage sein, das Beispiel auszuführen und zu erstellen:

bazel build tensorflow/examples/label_image/...

Eine ausführbare Binärdatei sollte erstellt werden und Sie sollten in der Lage sein, sie wie folgt auszuführen:

bazel-bin/tensorflow/examples/label_image/label_image

Das im Framework enthaltene Standardbeispielbild sollte verwendet werden und die Ausgabe sollte folgendermaßen aussehen:

I tensorflow/examples/label_image/main.cc:200] military uniform (866): 0.647296
I tensorflow/examples/label_image/main.cc:200] suit (794): 0.0477196
I tensorflow/examples/label_image/main.cc:200] academic gown (896): 0.0232411
I tensorflow/examples/label_image/main.cc:200] bow tie (817): 0.0157356
I tensorflow/examples/label_image/main.cc:200] bolo tie (940): 0.0145024

Hier identifiziert das Netzwerk anhand des Standardbilds Admiral Grace Hopper das Tragen von Militärkleidung mit einer hohen Punktzahl von 0,6 korrekt. Sie können sehen, dass es fertig ist.

図

Versuchen Sie es dann mit Ihrem eigenen Bild, indem Sie beispielsweise das Argument --image = angeben

bazel-bin/tensorflow/examples/label_image/label_image --image=my_image.png

tensorflow / examples / label_image / main.cc Wenn Sie sich den Inhalt der Datei ansehen, wie er aussieht Sie können sehen, ob es funktioniert. Schauen wir uns die Hauptfunktion genauer an, damit dieser Code dazu beitragen kann, TensorFlow in Ihre eigene Anwendung zu integrieren:

Befehlszeilenflags steuern die Quelle der Datei und die Eigenschaften des Eingabebilds. Das Modell verwendet ein quadratisches 299 x 299-RGB-Bild als Eingabe. Setzen Sie sie daher auf die Flags input_width und input_height. Sie müssen auch die Pixelwerte von Ganzzahlen zwischen 0 und 255 auf die Gleitkommawerte skalieren, bei denen das Diagramm arbeitet. Steuern Sie die Skalierung mit den Flags input_mean und input_std: Subtrahieren Sie zuerst input_mean von jedem Pixelwert und dividieren Sie dann durch input_std.

Diese Werte, die etwas magisch erscheinen mögen, basieren auf dem, was der ursprüngliche Modellierer als Trainingseingabebild verwendet hat. Wenn Sie ein Diagramm verwenden, das Sie selbst trainiert haben, müssen Sie die Werte an die Werte anpassen, die Sie während des Trainingsprozesses verwendet haben.

In der Funktion ReadTensorFromImageFile () (https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/label_image/main.cc#L88) können Sie sehen, wie Sie sie auf das Bild anwenden.

// Given an image file name, read in the data, try to decode it as an image,
// resize it to the requested size, and then scale the values as desired.
Status ReadTensorFromImageFile(string file_name, const int input_height,
                               const int input_width, const float input_mean,
                               const float input_std,
                               std::vector<Tensor>* out_tensors) {
  tensorflow::GraphDefBuilder b;

Beginnen Sie mit der Generierung eines GraphDefBuilder. Dies ist das Objekt, mit dem das auszuführende oder zu ladende Modell angegeben wird.

  string input_name = "file_reader";
  string output_name = "normalized";
  tensorflow::Node* file_reader =
      tensorflow::ops::ReadFile(tensorflow::ops::Const(file_name, b.opts()),
                                b.opts().WithName(input_name));

Generieren Sie dann einen kleinen Modellknoten. Dieser Knoten lädt, ändert die Größe und skaliert Pixelwerte, um die Ergebnisse zu erhalten, die das Hauptmodell als Eingabe erwartet. Der erste Knoten, den Sie erstellen, ist eine Const-Operation, die nur einen Tensor mit dem Dateinamen des zu ladenden Bildes enthält. Es wird dann als erste Eingabe für die ReadFile-Operation übergeben. Haben Sie bemerkt, dass wir b.opts () als letztes Argument jeder Operationserstellungsfunktion übergeben? Dieses Argument garantiert, dass der Knoten zur Modelldefinition von GraphDefBuilder hinzugefügt wird. Benennen Sie außerdem die ReadFile-Operation, indem Sie WithName () nach b.opts () aufrufen. Dies gibt dem Knoten einen Namen. Wenn Sie dem Knoten keinen Namen geben, wird ihm automatisch ein Name zugewiesen, sodass dies nicht unbedingt erforderlich ist, das Debuggen jedoch etwas einfacher ist.

  // Now try to figure out what kind of file it is and decode it.
  const int wanted_channels = 3;
  tensorflow::Node* image_reader;
  if (tensorflow::StringPiece(file_name).ends_with(".png ")) {
    image_reader = tensorflow::ops::DecodePng(
        file_reader,
        b.opts().WithAttr("channels", wanted_channels).WithName("png_reader"));
  } else {
    // Assume if it's not a PNG then it must be a JPEG.
    image_reader = tensorflow::ops::DecodeJpeg(
        file_reader,
        b.opts().WithAttr("channels", wanted_channels).WithName("jpeg_reader"));
  }
  // Now cast the image data to float so we can do normal math on it.
  tensorflow::Node* float_caster = tensorflow::ops::Cast(
      image_reader, tensorflow::DT_FLOAT, b.opts().WithName("float_caster"));
  // The convention for image ops in TensorFlow is that all images are expected
  // to be in batches, so that they're four-dimensional arrays with indices of
  // [batch, height, width, channel]. Because we only have a single image, we
  // have to add a batch dimension of 1 to the start with ExpandDims().
  tensorflow::Node* dims_expander = tensorflow::ops::ExpandDims(
      float_caster, tensorflow::ops::Const(0, b.opts()), b.opts());
  // Bilinearly resize the image to fit the required dimensions.
  tensorflow::Node* resized = tensorflow::ops::ResizeBilinear(
      dims_expander, tensorflow::ops::Const({input_height, input_width},
                                            b.opts().WithName("size")),
      b.opts());
  // Subtract the mean and divide by the scale.
  tensorflow::ops::Div(
      tensorflow::ops::Sub(
          resized, tensorflow::ops::Const({input_mean}, b.opts()), b.opts()),
      tensorflow::ops::Const({input_std}, b.opts()),
      b.opts().WithName(output_name));

Fügen Sie weitere Knoten hinzu. Diese Knoten decodieren die Dateidaten in Bilder, wandeln Ganzzahlen in Gleitkommazahlen um, ändern ihre Größe und führen schließlich Pixelwertsubtraktions- und -divisionsoperationen durch.

  // This runs the GraphDef network definition that we've just constructed, and
  // returns the results in the output tensor.
  tensorflow::GraphDef graph;
  TF_RETURN_IF_ERROR(b.ToGraphDef(&graph));

Am Ende des vorherigen Abschnitts wird die Modelldefinition in der Variablen b gespeichert. Die Funktion ToGraphDef () wandelt dies in eine vollständige Diagrammdefinition um.

  std::unique_ptr<tensorflow::Session> session(
      tensorflow::NewSession(tensorflow::SessionOptions()));
  TF_RETURN_IF_ERROR(session->Create(graph));
  TF_RETURN_IF_ERROR(session->Run({}, {output_name}, {}, out_tensors));
  return Status::OK();

Erstellen Sie anschließend ein Objekt Session (eine Schnittstelle zum tatsächlichen Ausführen des Diagramms) und erstellen Sie es. Geben Sie an, von welchem Knoten Sie die Ausgabe erhalten möchten und wo die Ausgabedaten abgelegt werden sollen, und führen Sie sie aus.

Dies gibt einen Vektor von Tensorobjekten zurück. Dies ist einfach ein einzelnes Objekt, das wir in diesem Fall schon lange kennen. In diesem Zusammenhang können Sie sich Tensor als mehrdimensionales Array vorstellen. Es enthält ein 299 Pixel hohes, 299 Pixel breites 3-Kanal-Bild als Gleitkommawert. Wenn Ihr Produkt ein eigenes Bildverarbeitungsframework verwendet, sollten Sie es stattdessen verwenden können, bevor Sie das Bild dem Hauptdiagramm zuführen, solange Sie dieselben Transformationen anwenden.

Dies ist ein einfaches Beispiel für die dynamische Erstellung eines kleinen TensorFlow-Diagramms in C ++, es wird jedoch eine viel größere Definition aus der Datei geladen, um das vorab trainierte Inception-Modell zu verwenden. Sie können sehen, wie dies mit der Funktion LoadGraph () gemacht wird.

// Reads a model graph definition from disk, and creates a session object you
// can use to run it.
Status LoadGraph(string graph_file_name,
                 std::unique_ptr<tensorflow::Session>* session) {
  tensorflow::GraphDef graph_def;
  Status load_graph_status =
      ReadBinaryProto(tensorflow::Env::Default(), graph_file_name, &graph_def);
  if (!load_graph_status.ok()) {
    return tensorflow::errors::NotFound("Failed to load compute graph at '",
                                        graph_file_name, "'");
  }

Wenn Sie sich den Bildladecode ansehen, sollten Ihnen viele Begriffe bekannt vorkommen. Laden Sie die Protobuf-Datei, die GraphDef enthält, anstatt GraphDefBuilder zum Generieren des GraphDef-Objekts zu verwenden.

  session->reset(tensorflow::NewSession(tensorflow::SessionOptions()));
  Status session_create_status = (*session)->Create(graph_def);
  if (!session_create_status.ok()) {
    return session_create_status;
  }
  return Status::OK();
}

Anschließend wird aus diesem GraphDef ein Sitzungsobjekt erstellt und zur späteren Ausführung an den Aufrufer übergeben.

Die GetTopLabels () -Funktion ähnelt weitgehend dem Laden von Bildern, verwendet jedoch das Ergebnis der Ausführung des Hauptdiagramms und konvertiert es in eine sortierte Liste von Beschriftungen mit den höchsten Punktzahlen. Wie ein Bildlader erstellt er einen GraphDefBuilder, fügt ihm zwei Knoten hinzu und führt ein kurzes Diagramm aus, um ein Paar von Ausgangstensoren zu erhalten. Das Ausgangstensorpaar repräsentiert die sortierte Punktzahl und die beste Indexposition.

// Analyzes the output of the Inception graph to retrieve the highest scores and
// their positions in the tensor, which correspond to categories.
Status GetTopLabels(const std::vector<Tensor>& outputs, int how_many_labels,
                    Tensor* indices, Tensor* scores) {
  tensorflow::GraphDefBuilder b;
  string output_name = "top_k";
  tensorflow::ops::TopK(tensorflow::ops::Const(outputs[0], b.opts()),
                        how_many_labels, b.opts().WithName(output_name));
  // This runs the GraphDef network definition that we've just constructed, and
  // returns the results in the output tensors.
  tensorflow::GraphDef graph;
  TF_RETURN_IF_ERROR(b.ToGraphDef(&graph));
  std::unique_ptr<tensorflow::Session> session(
      tensorflow::NewSession(tensorflow::SessionOptions()));
  TF_RETURN_IF_ERROR(session->Create(graph));
  // The TopK node returns two outputs, the scores and their original indices,
  // so we have to append :0 and :1 to specify them both.
  std::vector<Tensor> out_tensors;
  TF_RETURN_IF_ERROR(session->Run({}, {output_name + ":0", output_name + ":1"},
                                  {}, &out_tensors));
  *scores = out_tensors[0];
  *indices = out_tensors[1];
  return Status::OK();

Die Funktion PrintTopLabels () verwendet diese Sortierergebnisse und gibt sie auf einfach zu lesende Weise aus. Die CheckTopLabel () -Funktion ist sehr ähnlich, aber stellen Sie zum Debuggen sicher, dass das obere Label Ihren Erwartungen entspricht.

Schließlich bindet main () alle diese Aufrufe zusammen.

int main(int argc, char* argv[]) {
  // We need to call this to set up global state for TensorFlow.
  tensorflow::port::InitMain(argv[0], &argc, &argv);
  Status s = tensorflow::ParseCommandLineFlags(&argc, argv);
  if (!s.ok()) {
    LOG(ERROR) << "Error parsing command line flags: " << s.ToString();
    return -1;
  }

  // First we load and initialize the model.
  std::unique_ptr<tensorflow::Session> session;
  string graph_path = tensorflow::io::JoinPath(FLAGS_root_dir, FLAGS_graph);
  Status load_graph_status = LoadGraph(graph_path, &session);
  if (!load_graph_status.ok()) {
    LOG(ERROR) << load_graph_status;
    return -1;
  }

Laden Sie das Hauptdiagramm.

  // Get the image from disk as a float array of numbers, resized and normalized
  // to the specifications the main graph expects.
  std::vector<Tensor> resized_tensors;
  string image_path = tensorflow::io::JoinPath(FLAGS_root_dir, FLAGS_image);
  Status read_tensor_status = ReadTensorFromImageFile(
      image_path, FLAGS_input_height, FLAGS_input_width, FLAGS_input_mean,
      FLAGS_input_std, &resized_tensors);
  if (!read_tensor_status.ok()) {
    LOG(ERROR) << read_tensor_status;
    return -1;
  }
  const Tensor& resized_tensor = resized_tensors[0];

Laden Sie das Eingabebild, ändern Sie die Größe und verarbeiten Sie es.

  // Actually run the image through the model.
  std::vector<Tensor> outputs;
  Status run_status = session->Run({{FLAGS_input_layer, resized_tensor}},
                                   {FLAGS_output_layer}, {}, &outputs);
  if (!run_status.ok()) {
    LOG(ERROR) << "Running model failed: " << run_status;
    return -1;
  }

Hier führen wir das geladene Diagramm aus und verwenden ein Bild als Eingabe.

  // This is for automated testing to make sure we get the expected result with
  // the default settings. We know that label 866 (military uniform) should be
  // the top label for the Admiral Hopper image.
  if (FLAGS_self_test) {
    bool expected_matches;
    Status check_status = CheckTopLabel(outputs, 866, &expected_matches);
    if (!check_status.ok()) {
      LOG(ERROR) << "Running check failed: " << check_status;
      return -1;
    }
    if (!expected_matches) {
      LOG(ERROR) << "Self-test failed!";
      return -1;
    }
  }

Zu Testzwecken können Sie hier überprüfen, ob Sie die erwartete Ausgabe erhalten.

  // Do something interesting with the results we've generated.
  Status print_status = PrintTopLabels(outputs, FLAGS_labels);

Drucken Sie abschließend das gefundene Etikett.

  if (!print_status.ok()) {
    LOG(ERROR) << "Running print failed: " << print_status;
    return -1;
  }

Die Fehlerbehandlung verwendet hier das TensorFlow-Statusobjekt. Dieses Objekt ist sehr nützlich, da der OK () -Prüfer Ihnen mitteilen kann, ob ein Fehler aufgetreten ist, und eine Fehlermeldung drucken kann.

In diesem Fall demonstrieren wir die Objekterkennung, aber in verschiedenen Bereichen sollten Sie in der Lage sein, sehr ähnlichen Code in anderen Modellen zu verwenden, die Sie gefunden und trainiert haben. Hoffentlich gibt Ihnen dieses kleine Beispiel einige Ideen, wie Sie TensorFlow in Ihrem eigenen Produkt verwenden können.

Übung: Transferlernen ist die Idee, dass Sie, wenn Sie wissen, wie man eine Aufgabe gut löst, in der Lage sein sollten, einen Teil dieses Verständnisses auf die Lösung verwandter Probleme zu übertragen. Eine Möglichkeit, Transferlernen durchzuführen, besteht darin, die letzte klassifizierte Schicht des Netzwerks (die vorletzte Schicht des CNN) (http://arxiv.org/abs/1310.1531), in diesem Fall 2048 Dimensionen, zu entfernen. Ist den Vektor von zu extrahieren. Dies kann angegeben werden, indem --output_layer = pool_3 festgelegt und die Behandlung von Ausgabe-Tensoren in [C ++ API-Beispiel](# C ++ API-Verwendung) geändert wird. Versuchen Sie, diese Funktion aus einer Sammlung von Bildern zu extrahieren, und stellen Sie sicher, dass Sie neue Kategorien vorhersagen können, über die ImageNet nicht verfügt.

Ressourcen, um mehr zu erfahren

Das kostenlose Online-Buch von Michael Nielsen (http://neuralnetworksanddeeplearning.com/chap1.html) ist eine großartige Ressource zum Erlernen neuronaler Netze im Allgemeinen. Insbesondere im Faltungsnetzwerk gibt es einige [großartige Blog-Beiträge] von Chris Olah (http://colah.github.io/posts/2014-07-Conv-Nets-Modular/) und Michael Nielsens Buch Es gibt ein großes Kapitel, das sie behandelt.

Um mehr über die Implementierung eines Faltungsnetzwerks zu erfahren, springen Sie zu TensorFlows Deep Convolution Network Tutorial oder etwas lockerer ML-Anfänger und ML-Experte Sie können mit dem MNIST Starter Tutorial in) beginnen. Wenn Sie die neuesten Informationen zur Forschung in diesem Bereich erhalten möchten, lesen Sie die neuesten Erkenntnisse in den Artikeln, auf die in diesem Lernprogramm verwiesen wird.

Recommended Posts

TensorFlow Tutorial-Bilderkennung (Übersetzung)
TensorFlow Tutorial-Mandelbrot Set (Übersetzung)
TensorFlow Tutorial - TensorFlow Mechanics 101 (Übersetzung)
TensorFlow Tutorial-MNIST Daten herunterladen (Übersetzung)
TensorFlow Tutorial-Sequenztransformationsmodell (Übersetzung)
TensorFlow Tutorial-Convolution Neuronales Netz (Übersetzung)
TensorFlow MNIST Für ML Anfänger Übersetzung
TensorFlow Deep MNIST für Expertenübersetzung
Gesichtserkennung für Momokuro-Mitglieder durch TensorFlow (Teil 2)
Versuchen Sie die Objekterkennung in Echtzeit mit YOLOv2 (TensorFlow).