Dichtungen gegen neuronales Netzwerk 2. Oder führen Sie SqueezeNet v.1.1 auf Raspberry Zero in Echtzeit aus (fast).

    Hallo an alle!

    Nach dem Schreiben war es nicht ganz ernst und in der praktischen Art des ersten Teils nicht besonders nützlich. Ich war mit dem Gewissen etwas festgefahren. Und ich beschloss, die Arbeit zu beenden. Das heißt, dieselbe Implementierung des neuronalen Netzwerks zu wählen, um auf dem Rasperry Pi Zero W in Echtzeit zu laufen (natürlich auf einer solchen Hardware, soweit möglich). Führen Sie die Daten aus der Praxis aus und markieren Sie die auf Habré erzielten Ergebnisse.

    Vorsicht! Es gibt einen funktionsfähigen Code unter dem Schnitt und etwas mehr Dichtungen als im ersten Teil. Das Bild zeigt die ko bzw. ko.

    Bild

    Welches Netzwerk soll man wählen?


    Ich möchte Sie daran erinnern, dass aufgrund der Schwäche des Malinki-Eisens die Wahl der Implementierungen des neuronalen Netzwerks gering ist. Nämlich:

    1. SqueezeNet.
    2. YOLOv3 Tiny.
    3. MobileNet.
    4. ShuffleNet.

    Wie richtig war die Entscheidung für SqueezeNet im ersten Teil ? ... Jedes der oben genannten neuronalen Netzwerke auf seiner Hardware zu betreiben, ist ein ziemlich langes Ereignis. Da ich von vagen Zweifeln geplagt wurde, entschied ich mich zu googeln, wenn sich jemand eine ähnliche Frage gestellt hatte. Es stellte sich heraus, dass er es eingehender fragte und untersuchte. Interessenten können sich auf die Quelle beziehen . Ich werde mich auf das einzige Bild davon beschränken:

    Bild

    Aus dem Bild geht hervor, dass die Verarbeitungszeit eines Bildes für verschiedene auf ImageNet trainierte Modelle die kürzeste Zeit für SqueezeNet v.1.1 ist. Wir nehmen dies als Handlungsanweisung. Der Vergleich beinhaltete nicht YOLOv3, aber wie ich mich erinnere, ist YOLO teurer als MobileNet. Ie In der Geschwindigkeit sollte es auch SqueezeNet nachgeben.

    Implementieren des ausgewählten Netzwerks


    Gewichte und die SqueezeNet-Topologie, die mit dem ImageNet-Datensatz (dem Caffe-Framework) trainiert wurde, finden Sie auf GitHub . Nur für den Fall, dass ich beide Versionen heruntergeladen habe, um sie später vergleichen zu können. Warum ImageNet? Dieser Satz von allen verfügbaren Klassen hat die maximale Anzahl von Klassen (1000 Stück), daher versprechen die Ergebnisse des neuronalen Netzwerks recht interessant zu sein.

    Lassen Sie uns zu diesem Zeitpunkt sehen, wie Raspberry Zero mit der Erkennung von Bildern von der Kamera fertig wird. Hier ist unser bescheidener Mitarbeiter des heutigen Postens:

    Bild

    Für die Grundlage des Codes habe ich die Quelle aus dem Blog Adrian Rosebrock genommen, der im ersten Teil erwähnt wurde , und zwar von hier . Ich musste es jedoch erheblich zusammenbauen:

    1. Ersetzen Sie das mit MobileNetSSD verwendete Modell durch SqueezeNet.
    2. Die Ausführung von Punkt 1 führte zu einem Anstieg der Anzahl der Klassen auf 1000. Gleichzeitig musste jedoch die Funktion zum Auswählen von Objekten mit mehrfarbigen Rahmen (SSD-Funktionalität) leider entfernt werden.
    3. Entfernen Sie den Argumentempfang über die Befehlszeile (aus irgendeinem Grund stelle ich die Eingabe von Parametern fest).
    4. Entfernen Sie die VideoStream-Methode und damit die von Adrian geliebte Imutils-Bibliothek. Die ursprüngliche Methode wurde verwendet, um den Videostream von der Kamera abzurufen. Aber da die Kamera an den Himbeer-Nullpunkt angeschlossen war, funktionierte er dumm nicht und gab so etwas wie „illegalen Unterricht“ aus.
    5. Fügen Sie die Bildrate (FPS) zum erkannten Bild hinzu, und schreiben Sie die FPS-Berechnung neu.
    6. Erstellen Sie Frames, um diesen Beitrag zu schreiben.

    Auf Malinka mit Rapbian Stretch OS, Python 3.5.3 und Installation über Pip3 installieren Sie OpenCV 3.4.1. Folgendes ist geschehen und gestartet:

    Code hier
    import picamera
    from picamera.array import PiRGBArray
    import numpy as np
    import time
    from time import sleep
    import datetime as dt
    import cv2
    # загружаем параметры сети
    prototxt = 'models/squeezenet_v1.1.prototxt'
    model = 'models/squeezenet_v1.1.caffemodel'
    labels = 'models/synset_words.txt'# загружаем распознаваемые классы
    rows = open(labels).read().strip().split("\n")
    classes = [r[r.find(" ") + 1:].split(",")[0] for r in rows]
    # загружаем модель сети
    print("[INFO] loading model...")
    net = cv2.dnn.readNetFromCaffe(prototxt, model)
    print("[INFO] starting video stream...")
    # инициализируем камеру
    camera = picamera.PiCamera()
    camera.resolution = (640, 480)
    camera.framerate = 25# прогреваем камеру
    camera.start_preview()
    sleep(1)
    camera.stop_preview()
    # инициализируем кадр в формате raw 
    rawCapture = PiRGBArray(camera)
    # сбрасываем счетчик FPS
    t0 = time.time()
    # цикл обработки видео потокаfor frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
        # захватываем кадр как blob
        frame = rawCapture.array
        blob = cv2.dnn.blobFromImage(frame, 1, (224, 224), (104, 117, 124))
        # загружаем в сеть blob, получаем класс и вероятность
        net.setInput(blob)
        preds = net.forward()
        preds = preds.reshape((1, len(classes)))
        idxs = int(np.argsort(preds[0])[::-1][:1])
        # вычисляем FPS
        FPS = 1/(time.time() - t0)
        t0 = time.time()
        # помещаем на кадр класс, вероятность и FPS, выводим в консоль
        text = "Label: {}, p = {:.2f}%, fps = {:.2f}".format(classes[idxs], preds[0][idxs] * 100, FPS)
        cv2.putText(frame, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
        print(text)
        cv2.imshow("Frame", frame)     # выводим кадр на дисплее Raspberry 
        fname = 'pic_' + dt.datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '.jpg'
        cv2.imwrite(fname, frame)      # сохраняем кадр на SD диске
        key = cv2.waitKey(1) & 0xFF# если нажата кнопка `q` выходим из циклаif key == ord("q"): break# очищаем поток raw данных с камеры перед следующим циклом
        rawCapture.truncate(0)
    print("[INFO] video stream is terminated")
    # прибираем за собой
    cv2.destroyAllWindows()
    camera.close()


    Ergebnisse


    Der Code wird auf dem Bildschirm des an die Raspberry angeschlossenen Monitors angezeigt, ein weiterer erkannter Frame in diesem Formular. Am oberen Rand des Rahmens wird nur die wahrscheinlichste Klasse angezeigt.

    Bild

    Eine Computermaus wurde also mit sehr hoher Wahrscheinlichkeit als Maus definiert. Gleichzeitig werden Bilder mit einer Frequenz von 0,34 FPS (dh etwa alle drei Sekunden) aktualisiert. Es ist ein bisschen ärgerlich, die Kamera zu halten und zu warten, bis das nächste Bild verarbeitet wird, aber Sie können leben. Wenn Sie den Sicherungsrahmen von der SD-Karte entfernen, erhöht sich die Verarbeitungsgeschwindigkeit übrigens auf 0,37 ... 0,38 FPS. Sicher gibt es andere Wege, sich zu zerstreuen. Wir werden diese Frage auf jeden Fall für die nächsten Beiträge hinterlassen.

    Separat entschuldige ich mich für den Weißabgleich. Tatsache ist, dass die IR-Kamera mit eingeschalteter Hintergrundbeleuchtung mit Rapberry verbunden war, so dass die meisten Bilder eher seltsam wirken. Aber je wertvoller jedes neuronale Netz. Offensichtlich war der Weißabgleich des Trainingssatzes korrekter. Außerdem habe ich mich entschieden, nur RAW-Frames einzufügen, damit der Leser sie genauso sehen kann, wie er ein neuronales Netzwerk sieht.

    Vergleichen wir zunächst die Arbeit der SqueezeNet-Versionen 1.0 (links) und 1.1 (rechts): Sie

    Bild

    sehen, dass Version 1.1 zwei- und viertelmal schneller arbeitet als 1.0 (0,34 FPS vs. 0,15). Der Geschwindigkeitsgewinn ist spürbar. Erkenntnisse über die Erkennungsgenauigkeit in diesem Beispiel sind nicht wert, da die Genauigkeit stark von der Position der Kamera in Bezug auf das Objekt, Beleuchtung, Blendung, Schatten usw. abhängt.

    Aufgrund des erheblichen Geschwindigkeitsvorteils von Version 1.1 gegenüber Version 1.0 wurde in der Zukunft nur noch SqueezeNet Version 1.1 verwendet. Um die Arbeit des Modells zu bewerten, richtete ich die Kamera auf verschiedene Objekte, die zur Hand kamen, und erhielt am Ausgang folgende Einstellungen: Die

    Bild

    Tastatur ist bestimmt schlechter als die Maus. Es ist möglich, dass die meisten Tastaturen im Trainingsbeispiel weiß waren.

    Bild

    Handy ist ziemlich gut bestimmt, wenn Sie den Bildschirm einschalten. Cellular mit dem Bildschirm aus dem neuronalen Netzwerk für die Zelle zählt nicht.

    Bild

    Eine leere Tasse wird als Kaffeetasse definiert. So weit so gut.

    Bild

    Bei einer Schere ist die Situation schlimmer, sie wird hartnäckig vom Netzwerk als Haarnadel bestimmt. Ist der Treffer allerdings nicht im Apfel, dann zumindest im Apfelbaum)

    Kompliziere die Aufgabe


    Neuronale Netze versuchen , ein zu setzen Schwein ist schwierig etwas. Ich habe gerade ein selbstgemachtes Kinderspielzeug bekommen. Ich glaube, dass die meisten Leser sie als Spielzeugkatze erkennen. Was wird interessanterweise unsere rudimentäre künstliche Intelligenz finden?

    Bild

    Auf dem Rahmen links löschte die IR-Beleuchtung alle Streifen vom Stoff. Infolgedessen wurde das Spielzeug mit relativ guter Wahrscheinlichkeit als Sauerstoffmaske definiert. Warum nicht? Die Form des Spielzeugs ähnelt wirklich einer Sauerstoffmaske.

    Im Rahmen rechts deckte ich den IR-Strahler mit meinen Fingern auf, so dass die Streifen auf dem Spielzeug auftauchten und der Weißabgleich glaubwürdiger wurde. Eigentlich ist dies der einzige Frame in diesem Beitrag, der mehr oder weniger normal aussieht. Aber das neuronale Netzwerk verwirrte eine solche Fülle von Details im Bild. Sie identifizierte das Spielzeug als Sweatshirt (Sweatshirt). Ich muss sagen, dass auch dies nicht wie ein "Finger zum Himmel" aussieht. Wenn nicht im "Apfelbaum", dann zumindest im Apfelgarten).

    Nun, wir sind nahtlos an den Höhepunkt unseres Handelns herangegangen. Der unbestrittene Sieger des Kampfes, der im ersten Posten gründlich geweiht wurde , tritt in den Ring . Und das Gehirn unseres neuronalen Netzwerks lässt sich von Anfang an leicht herausnehmen.

    Bild

    Es ist merkwürdig, dass die Katze die Position praktisch nicht ändert, sondern jedes Mal anders bestimmt wird. Und in dieser Perspektive ist es einem Stinktier am ähnlichsten. An zweiter Stelle steht die Ähnlichkeit mit dem Hamster. Versuchen wir den Winkel zu ändern.

    Bild

    Ja, wenn Sie ein Foto einer Katze von oben machen, wird sie richtig bestimmt, aber Sie müssen nur etwas die Position des Katzenkörpers auf dem Rahmen ändern. Für ein neuronales Netzwerk wird es zu einem Hund - Siberian Husky und Malamute (Eskimo-Schlittenhund).

    Bild

    Und diese Auswahl ist schön, weil auf jedem Rahmen der Katze eine Katze einer anderen Rasse definiert ist. Und die Rasse wiederholt sich nicht)

    Bild

    Es gibt übrigens Posen, in denen das neuronale Netzwerk deutlich wird, dass es sich immer noch um eine Katze handelt, nicht um einen Hund. Das heißt, SqueezeNet v.1.1 konnte sich selbst auf einem so komplexen Objekt zur Analyse noch zeigen. In Anbetracht des Erfolgs des neuronalen Netzwerks bei der Erkennung von Objekten zu Beginn des Tests und der Erkennung einer Katze als Katze am Ende dieses Mal erklären wir ein solides Kampfspiel.)

    Nun, das ist alles. Ich empfehle jedem, den vorgeschlagenen Code auf seiner Himbeere und allen animierten und unbelebten Objekten, die in Sicht kamen, auszuprobieren. Ich bin besonders dankbar für diejenigen, die FPS auf Rapberry Pi B + messen. Ich verspreche, die Ergebnisse in diesen Beitrag mit Bezug auf die Person aufzunehmen, die die Daten gesendet hat. Ich glaube, es sollte deutlich mehr als 1 FPS ausfallen!

    Ich hoffe, dass die Informationen aus diesem Beitrag für Unterhaltungs- oder Bildungszwecke nützlich sind und dass Sie vielleicht sogar zu neuen Ideen gezwungen werden.

    Alle erfolgreiche Arbeitswoche! Und zu neuen Meetings)

    Bild

    UPD1: Auf dem Raspberry Pi 3B + arbeitet das obige Skript mit einer Frequenz von 2 mit einem kleinen FPS.

    UPD2: Auf RPi 3B + mit Movidius NCS wird das Skript mit 6 FPS ausgeführt.

    Jetzt auch beliebt: