KI, die nicht nach Brot fragt

Ein Artikel darüber, wie wir unsere KI Schritt für Schritt aufgebaut haben. Lesezeit 10+ Minuten.







Einführung . Ein Computer Vision Startup mit kostengünstiger Entwicklung als Grundkonzept. Das Team steht im Einklang mit dem Geist: 3 - 5 Studenten von Entwicklern unterschiedlicher Ebenen und Richtungen, je nach Wochentag und Tageszeit (von 0,25 bis 1,25). Meine Erfahrung mit dem Tag-Spielen ist hier sehr nützlich.



Kurz über das Produkt (PC + Software) - ein intelligentes System , Videoüberwachung mit einem lokalen Netzwerk verbunden und produziert Videoverarbeitung auf seinem eigenen . Zwei Voraussetzungen: das Vorhandensein einer Benutzeroberfläche mit unterschiedlichen Rechten und die maximale Autonomie der Algorithmen.



Auf der technischen Seite gab es keine Einschränkungen für die Hardware. Hauptsache, es funktionierte gut. aber mit dem finanziellen waren. Für alles über alles ~ 500 $. Natürlich nur neue und moderne Komponenten. Ihre Wahl ist nicht großartig, aber es gibt!



Wir haben uns für die Hardware und dann für die Software entschieden. Die Wahl fiel aus irgendeinem Grund auf eine Microservice-Architektur mit Docker.



Die Entwicklung der Funktionen ging von einfach und notwendig (Arbeiten mit Streams und Videodateien) zu komplex mit regelmäßigen Überprüfungen über. Wir haben einen MVP zusammengestellt, mehrere Optimierungssprints haben uns unserem geschätzten Ziel spürbar näher gebracht - alle 4 Punkte gleichzeitig und nicht separat zu erreichen:



  1. 16+ IP-Kameras (FHD / 25fps) Live-, Event- oder Zeitwiedergabe und -aufzeichnung
  2. Parallelbetrieb aller verfügbaren CV-Algorithmen
  3. Der Benutzer nutzt die Benutzeroberfläche intensiv und ohne Verzögerungen - er sieht sich Streams an
  4. Die CPU-Auslastung beträgt weniger als 90% und alles funktioniert (!)


Ein wenig über den Stack fiel die Wahl auf: C / C +, Python + TensorFlow, PHP, NodeJS, TypeScript, VueJS, PostgreSQL + Socket.io und andere kleine Dinge.



Die implementierten Funktionen wurden absichtlich ausgeblendet, um auf die vielleicht interessanteste und reizvollste Funktion aus dem Bereich Lebenslauf und in gewissem Umfang - ML - näher einzugehen.



"Eindeutiger Benutzer"



Ein Anwendungsbeispiel ist das Sammeln des Besuchsverlaufs jedes einzelnen Besuchers. Mitarbeiter sollten separat berücksichtigt werden, auch wenn wir nicht wissen, dass es sich um einen Mitarbeiter handelt (Beispiel - ein Einkaufszentrum).

Und es scheint, dass dieses Problem mehr als 100.500 Mal gelöst wurde und Telefone und alles andere bereits Gesichter erkennen und sich daran erinnern können, sie irgendwohin senden, speichern. 95% der Lösungen werden jedoch in ACS verwendet, wo der Benutzer selbst, der versucht, erkannt zu werden, einige Sekunden lang in einem Abstand von 30 bis 50 cm vor einer 5-Megapixel-Kamera steht, bis sein Gesicht mit einem oder mehreren Gesichtern aus der Datenbank überprüft wird.



In unserem Fall waren solche Bedingungen ein Luxus. Benutzer bewegten sich unregelmäßig und schauten auf ihr Smartphone in ausreichendem Abstand von der an der Decke montierten Kamera. Darüber hinaus führten die Kameras selbst zu Schwierigkeiten. Meist handelt es sich dabei um Budgetkameras mit 1,3 bis 2 MP und einer unverständlichen Farbwiedergabe, die immer unterschiedlich ist.



Teilweise wurde dieses Problem durch die Bildung technischer Spezifikationen für die Bedingungen für die Installation von Kameras gelöst, aber im Allgemeinen sollte das System in der Lage sein, solche Bedingungen zu erkennen (natürlich schlimmer).



Lösungsansatz: Die Aufgabe wurde in 2 Aufgaben + Datenbankstruktur zerlegt.



Kurzzeitgedächtnis



Ein separater Dienst, bei dem der Echtzeitprozess hauptsächlich stattfindet, am Eingang ein Bild von der Kamera (tatsächlich ein anderer Dienst), am Ausgang - eine http-Anfrage mit einem normalisierten 512-dimensionalen X-Vektor (Gesichts-ID) und einigen Metadaten; zum Beispiel Zeitstempel.

Es gibt viele interessante Lösungen auf dem Gebiet der Logik und Optimierung, aber das ist alles; für jetzt alles ...



Langzeitgedächtnis



Ein separater Dienst, bei dem die Echtzeitanforderungen nicht akut sind, der jedoch in einigen Fällen wichtig ist (z. B. eine Person von einer Stoppliste). Im Allgemeinen haben wir uns für die Verarbeitung auf 3 Sekunden beschränkt.

Am Eingang zum Dienst - http aus dem Kurzzeitgedächtnis mit einem 512-dimensionalen Vektor im Inneren; am Ausgang - die ID des Besuchers.



Die ersten Gedanken sind offensichtlich, die Lösung des Problems ist ganz einfach: Ich habe http → ging in die Datenbank, nahm, was ich habe → verglich es mit der http-Füllung, wenn es eine gibt, dann ist es; wenn nicht, dann neu.

Die Vorteile einer solchen Lösung sind unzählig, aber nur ein Minus - es funktioniert nicht.



Das Problem wurde gelöst, obwohl wir dem Weg der Samurai folgten, verschiedene Ansätze ausprobierten und uns regelmäßig mit der Weite des Internets befassten. Im Allgemeinen erwies sich die Entscheidung als mäßig lakonisch. Das Konzept ist recht einfach und basiert auf Clustering:



  1. Jeder Vektor (a-Vektor) gehört einem Benutzer. Jeder Cluster (nicht mehr als M Vektoren, standardmäßig M = 30) gehört einem Benutzer. Ob der a-Vektor zu Cluster A gehört, ist keine Tatsache. Die Vektoren im Cluster definieren die Interaktion des Clusters, die Vektoren im Benutzer definieren nur den Verlauf des Benutzers.
  2. Jeder Cluster hat einen Schwerpunkt (tatsächlich einen A-Vektor) und einen eigenen Radius (im Folgenden als Bereich bezeichnet) der Wechselwirkung mit anderen Vektoren oder Clustern.
  3. Der Schwerpunkt und der Bereich sind eine Clusterfunktion, nicht statisch.
  4. Die Nähe von Vektoren wird durch den quadratischen euklidischen Abstand bestimmt (in besonderen Fällen - ansonsten). Während es hier ein paar andere anständige Methoden gibt, haben wir dort einfach aufgehört.


Hinweis: seit Wir haben normalisierte Vektoren verwendet, der Abstand zwischen ihnen wurde von 0 bis 2 garantiert. Als nächstes über den Algorithmus zur Implementierung des Konzepts.



# 1 Der Kreis der Verdächtigen. Schwerpunkt als Hash-Funktion



Der aus dem Kurzzeitgedächtnis erhaltene X-Vektor wird mit den in der Datenbank verfügbaren Cluster-Zentroiden (A-Vektor) für nahe entfernte verglichen, wobei Bereich [X, A]> 1 - verworfen wurden. Wenn niemand mehr übrig ist, wird ein neuer Cluster erstellt.



Als nächstes wird das Minimum zwischen dem X-Vektor und allen verbleibenden a-Vektoren gesucht (min_range [X, a])



# 2 Einzigartige Eigenschaften des Clusters. Selbstregulierende Einheit



Der Cluster-eigene range_A wird berechnet, dessen Vektor dem X-Vektor am nächsten liegt. Hier verwenden wir die inverse lineare Funktion der Anzahl der Vektoren (N), die sich bereits in diesem Cluster befinden (const * (1 - N / 2M)); out of the box const = 0,67).



# 3 Validierung und Missverständnis. Wenn nicht jemand - wer dann?



Wenn range_A> min_range [X, a] ist, wird der X-Vektor als zum A-Cluster gehörend markiert. Wenn nicht, dann ... Oh ... Dies ähnelt in gewisser Weise der Beschreibung des mathematischen Modells des Missverständnisses.

Wir haben beschlossen, in diesem Fall einen neuen Cluster zu erstellen und dabei absichtlich einen Fehler der ersten Art „Fehlendes Ziel“ zu machen.



# 4 Zusätzliches Training. Wie Zahlen Zeichen bilden



Subjektive Erfahrung ist, wenn Daten zu einem Werkzeug werden. Wir haben früher erkannt, aber möglicherweise mit einem Fehler. Sollte ich darauf vertrauen, dass der X-Vektor ihn im nächsten Spiel verwendet! Überprüfung! Der X-Vektor muss:



  • nahe genug am Schwerpunkt A sein (range_A> range [X, A])
  • nützlich und vielfältig sein, weil wir einerseits das Fehlerrisiko minimieren, andererseits auch keine Kopien benötigen (Config_Max [0.35]> Bereich [X, a]> Config_Max [0.125]). Somit bestimmen die Konfigurationen die Geschwindigkeit und Richtigkeit des "Lernens".


Um diese Bedingungen zu erfüllen, ist der X-Vektor in Cluster A enthalten (zuvor gehörte er einfach dem Benutzer). Wenn der Cluster mehr Vektoren enthält, entfernen wir den zentralsten (min_range [A, a]) - er führt die geringste Vielfalt ein und ist nur eine Funktion der anderen; Darüber hinaus ist der Schwerpunkt bereits am Matching beteiligt.



# 5 Arbeit an Fehlern. Wir machen aus Nachteilen Vorteile



Bei jeder schwierigen Auswahl haben wir einen Schritt in Richtung des Fehlers "Fehlendes Ziel" gemacht - wir haben einen neuen Cluster und Benutzer erstellt. Es ist Zeit, sie noch einmal zu besuchen ... alle. Nach # 4 haben wir einen modifizierten Cluster A. Als nächstes berechnen wir seinen Schwerpunkt (A-Vektor) neu und suchen nach dem Mindestabstand zu allen verfügbaren Schwerpunkten in unserem 512-dimensionalen Raum. In diesem Fall wird die Entfernung als schwieriger angesehen, aber dies ist jetzt nicht so wichtig. Wenn der Abstand min_range [A, B] kleiner als ein bestimmter Wert ist (out of the box range_unity = 0.25), kombinieren wir zwei Mengen, berechnen einen neuen Schwerpunkt und entfernen weniger "nützliche" Vektoren, wenn zu viele vorhanden sind.

Mit anderen Worten: Wenn es tatsächlich mehr als 2 Cluster gibt, die demselben Benutzer gehören, werden sie nach einer Reihe von Erkennungen eng und verschmelzen mit ihren Geschichten zu einem.



# 6 Kombinatorische Merkmale. Wenn das Auto ... denkt !?



Es lohnt sich, hier in diesem Artikel einen neuen Begriff zu definieren. Ein Phantomvektor ist ein Vektor, der nicht als Ergebnis der Kurzzeitgedächtnisaktivität erhalten wurde, sondern als Ergebnis einer Funktion über N Vektoren des Clusters (a1, a2, a3, a4 ...). Natürlich werden die auf diese Weise erhaltenen Vektoren separat gespeichert und bilanziert und stellen keinen Wert dar, bis sie als Ergebnis der Übereinstimmung als die nächsten bestimmt werden (siehe # 3). Der Hauptvorteil von Phantomvektoren besteht darin , das frühe Lernen eines Clusters zu beschleunigen .



Das System ist bereits in Produktion. Das Ergebnis wurde mit realen Daten außerhalb der Testumgebung für mehr als 5000 Benutzer erhalten. Es wurde auch eine Reihe von "Schwachstellen" festgestellt, die in diesem Text verstärkt und berücksichtigt wurden.



Interessanterweise hat dieser Ansatz keine Benutzereinstellungen und alle Arbeiten werden in keiner Weise gesteuert, alles ist völlig autonom . Darüber hinaus können Sie mithilfe der Zeitreihenanalyse Benutzer auf ähnliche Weise in verschiedene Kategorien einteilen und so Assoziationen aufbauen. So wurde die Frage gelöst - wer sind die Mitarbeiter und wer sind die Besucher.



Die Rolle des Systembenutzers ist einfach: Sie müssen Ihre E-Mails oder die Systemschnittstelle regelmäßig auf neue Aktivitätsberichte überprüfen.



Ergebnis



Der Näherungswert für die Erkennung basierend auf dem Langzeitgedächtnis beträgt ~ 0,12-0,25 für einen mäßig trainierten Cluster (enthält 6-15 a-Vektoren). Ferner verlangsamt sich das Lernen aufgrund einer Zunahme der Wahrscheinlichkeit von "Vektorkopien", aber auf lange Sicht tendiert die Nähe zu Werten von ~ 0,04 bis 0,12, wenn der Cluster bereits mehr als 20 a-Vektoren enthält. Beachten Sie, dass im Kurzzeitgedächtnis von Bild zu Bild derselbe Parameter einen Wert von ~ 0,5-1,2 hat, was ungefähr so ​​klingt: "Eine Person sieht vor 2 Jahren eher wie eine Brille aus als vor 100 ms." Solche Möglichkeiten eröffnen sich durch den Einsatz von Clustering im Langzeitgedächtnis .



Rätsel



Einer der Tests ergab eine interessante Beobachtung.



Anfangsbedingungen:



  • Auf zwei absolut identischen PCs wird ein absolut identisches Videoüberwachungssystem mit absolut identischen Einstellungen bereitgestellt. Sie sind an eine einzige IP-Kamera angeschlossen, die laut TOR korrekt positioniert ist.


Handlung:



  • Die Systeme werden zur gleichen Zeit gestartet und eine Woche lang alleine gelassen, wobei alle Algorithmen funktionieren. Der Verkehr entspricht dem normalen Verkehr ohne Änderung.


Ergebnis:



  • Die Anzahl der erstellten Benutzer, Cluster und a-Vektoren ist gleich, aber die Schwerpunkte sind unterschiedlich, nicht signifikant - aber unterschiedlich. Die Frage ist warum? Wer weiß - schreiben Sie in die Kommentare oder hier )


Es ist schade, dass ich hier nicht über viele Dinge schreiben kann, aber vielleicht kann ich in einem anderen Artikel etwas im gleichen Detail beschreiben. Vielleicht wurde dies alles bereits in einem wunderbaren Handbuch beschrieben, aber zu meinem Bedauern habe ich nie eines gefunden.



Abschließend möchte ich sagen, dass es sehr interessant ist, von innen heraus zu beobachten, wie ein autonomes KI-System den umgebenden Raum klassifiziert und dabei verschiedene ihm innewohnende Merkmale implementiert. Menschen bemerken aufgrund der gesammelten Wahrnehmungserfahrung nicht viele Dinge (Schritt 4).




Ich hoffe wirklich, dass dieser Artikel für jeden in seinem Projekt nützlich sein wird.



All Articles