Une IA qui ne demande pas de pain

Un article sur la façon dont nous avons construit notre IA étape par étape. Temps de lecture 10+ minutes.







Introduction . Une startup de vision par ordinateur utilisant le développement à faible coût comme concept de base. L'équipe est assez cohérente avec l'esprit: 3 à 5 étudiants de développeurs de différents niveaux et directions, selon le jour de la semaine et l'heure de la journée (de 0,25 à 1,25 taux). Mon expérience de jouer au tag est très utile ici.



En bref sur le produit (pc + logiciel) - un système de vidéosurveillance intelligent connecté à un réseau local et produisant seul le traitement vidéo . Deux prérequis: la présence d'une interface utilisateur avec des droits différents et une autonomie maximale des algorithmes.



Sur le plan technique, il n'y avait aucune restriction sur le matériel, l'essentiel était que cela fonctionnait bien; mais avec le financier étaient. Pour tout sur tout ~ 500 $. Bien sûr, seuls des composants nouveaux et modernes. Leur choix n'est pas génial, mais il y en a!



Nous avons décidé du matériel, puis du logiciel. Le choix s'est porté sur une architecture de microservice utilisant docker pour une raison suffisante.



Le développement des fonctionnalités est passé de simple et nécessaire (travail avec des flux et des fichiers vidéo) à complexe, avec un examen périodique. Nous avons assemblé MVP, plusieurs sprints d'optimisation nous ont sensiblement rapprochés de notre objectif chéri - compléter les 4 points simultanément, et non séparément:



  1. 16+ caméras IP (FHD / 25fps) Lecture et enregistrement en direct, événementiel ou temporel
  2. Fonctionnement en parallèle de tous les algorithmes CV disponibles
  3. L'utilisateur utilise intensivement l'interface sans délai - en regardant les flux
  4. La charge du processeur est inférieure à 90% et tout fonctionne (!)


Un peu sur la pile, le choix s'est porté sur: C / C +, Python + TensorFlow, PHP, NodeJS, TypeScript, VueJS, PostgreSQL + Socket.io et d'autres petites choses.



Les fonctionnalités implémentées ont été délibérément cachées afin de s'attarder plus en détail sur, peut-être, la fonctionnalité la plus intéressante et la plus agréable du domaine du CV et dans une certaine mesure - ML.



"Utilisateur unique"



Un exemple d'utilisation est de collecter l'historique des visites de chaque visiteur spécifique, et les employés doivent être pris en compte séparément, même si nous ne savons pas qu'il s'agit d'un employé (exemple - un centre commercial).

Et il semblerait que ce problème ait été résolu plus de 100 500 fois et que les téléphones et tout le reste puissent déjà reconnaître les visages et les mémoriser, les envoyer quelque part, les enregistrer. Mais 95% des solutions sont utilisées dans ACS, où l'utilisateur lui-même, essayant d'être reconnu, se tient devant une caméra 5MP à une distance de 30 à 50 cm pendant plusieurs secondes jusqu'à ce que son visage vérifie avec un ou plusieurs visages de la base de données.



Dans notre cas, de telles conditions étaient un luxe. Les utilisateurs se déplaçaient de manière erratique, regardant leur smartphone à une distance suffisante de la caméra montée au plafond. De plus, les caméras elles-mêmes ont introduit des difficultés, le plus souvent des caméras économiques avec 1,3-2MP et une sorte de rendu des couleurs incompréhensible, toujours différent.



En partie, ce problème a été résolu par la formation de spécifications techniques pour les conditions d'installation des caméras, mais en général, le système aurait dû être capable de reconnaître dans de telles conditions (bien sûr, pire).



Approche de la solution: la tâche a été décomposée en 2 tâches + structure de la base de données.



Mémoire à court terme



Un service séparé, où le processus en temps réel a lieu principalement, à l'entrée se trouve une image de la caméra (en fait, un autre service), à ​​la sortie - une requête http avec un vecteur X normalisé de 512 dimensions (face-id) et des métadonnées par exemple horodatage.

À l'intérieur, il y a de nombreuses solutions intéressantes dans le domaine de la logique et de l'optimisation, mais c'est tout; pour l'instant tout ...



Memoire à long terme



Un service distinct, où les exigences en temps réel ne sont pas aiguës, mais dans certains cas, il est important (par exemple, une personne d'une liste d'arrêt). En général, nous nous sommes limités à 3 secondes pour le traitement.

À l'entrée du service - http à partir de la mémoire à court terme avec un vecteur de 512 dimensions à l'intérieur; à la sortie - ID visiteur.



Les premières pensées sont évidentes, la solution au problème est assez simple: j'ai obtenu http → je suis allé à la base de données, j'ai pris ce que j'ai → comparé avec le bourrage http, s'il y en a un, alors c'est; sinon, alors nouveau.

Les avantages d'une telle solution sont innombrables, et un seul inconvénient - cela ne fonctionne pas.



Le problème a été résolu, bien que nous ayons suivi le chemin du samouraï, essayant diverses approches, examinant périodiquement l'immensité de l'Internet. En général, la décision s'est avérée modérément laconique. Le concept est assez simple et repose sur le clustering:



  1. Chaque vecteur (un vecteur) appartiendra à un utilisateur; chaque cluster (pas plus de M vecteurs, hors de la boîte M = 30) appartient à un utilisateur. Le fait que le vecteur a appartienne au cluster A n'est pas un fait. Les vecteurs du cluster définissent l'interaction du cluster, les vecteurs de l'utilisateur définissent uniquement l'historique de l'utilisateur.
  2. Chaque cluster aura un centre de gravité (en fait, un vecteur A) et son propre rayon (ci-après dénommé plage) d'interaction avec d'autres vecteurs ou clusters.
  3. Le centre de gravité et la plage seront une fonction de cluster, pas statique.
  4. La proximité des vecteurs est déterminée par la distance euclidienne au carré (dans des cas particuliers, sinon). Bien qu'il existe quelques autres méthodes décentes ici, nous nous sommes arrêtés là.


Remarque: depuis Nous avons utilisé des vecteurs normalisés, la distance entre eux était garantie de 0 à 2. Ensuite, à propos de l'algorithme d'implémentation du concept.



# 1 Le cercle des suspects. Centroïde comme fonction de hachage



Le vecteur X obtenu à partir de la mémoire à court terme est comparé aux centroïdes de cluster (vecteur A) disponibles dans la base de données pour la proximité, les distants, où la plage [X, A]> 1 - a été écartée. S'il n'y a plus personne, un nouveau cluster est créé.



Ensuite, le minimum entre le vecteur X et tous les vecteurs a restants est recherché (min_range [X, a])



# 2 Propriétés uniques du cluster. Entité autorégulée



Le propre range_A du cluster est calculé, dont le vecteur est le plus proche du vecteur X. Ici, nous utilisons la fonction linéaire inverse du nombre de vecteurs (N) déjà dans ce cluster (const * (1 - N / 2M)); hors de la boîte const = 0,67).



# 3 Validation et malentendu. Si ce n'est pas quelqu'un - alors qui!?



Si range_A> min_range [X, a], alors le vecteur X est marqué comme appartenant au A-cluster. Sinon, alors ... Oh ... C'est un peu similaire à la description du modèle mathématique du malentendu.

Nous avons décidé que dans ce cas nous créerions un nouveau cluster, faisant ainsi délibérément une erreur du 1er type «Cible manquante».



# 4 Formation supplémentaire. Comment les nombres forment des signes



L'expérience subjective, c'est quand les données deviennent un outil. Nous avons reconnu plus tôt, mais peut-être avec une erreur. Dois-je faire confiance au vecteur X pour l'utiliser lors du prochain match!? Vérification! Le vecteur X doit:



  • être suffisamment proche du centre de gravité A (range_A> range [X, A])
  • être utile et diversifié, car d'une part, on minimise les risques d'erreurs, d'autre part, on n'a pas besoin de copies non plus (Config_Max [0.35]> range [X, a]> Config_Max [0.125]). Ainsi, les configurations déterminent la vitesse et l'exactitude de "l'apprentissage".


Remplissant ces conditions, le vecteur X est inclus dans le cluster A (avant cela, il appartenait simplement à l'utilisateur). S'il y a plus de vecteurs dans le cluster, alors nous supprimons le plus central (min_range [A, a]) - il introduit le moins de variété et n'est qu'une fonction des autres; de plus, le centroïde est déjà impliqué dans l'appariement.



# 5 Travaillez sur les bugs. Nous transformons les inconvénients en avantages



Dans chaque choix difficile, nous avons fait un pas vers l'erreur «Cible manquante» - nous avons créé un nouveau cluster et un nouvel utilisateur. Il est temps de les revoir ... tous. Après le n ° 4, nous avons un cluster A modifié. Ensuite, nous recalculons son centroïde (vecteur A) et cherchons la distance minimale à tous les centroïdes disponibles dans notre espace de 512 dimensions. Dans ce cas, la distance est considérée comme plus difficile, mais ce n'est pas si important maintenant. Lorsque la distance min_range [A, B] est inférieure à une certaine valeur (hors de la boîte range_unity = 0,25), nous combinons deux ensembles, calculons un nouveau centre de gravité et nous débarrassons des vecteurs moins «utiles» s'il y en a trop.

En d'autres termes: s'il y a 2+ clusters, en fait, appartenant au même utilisateur, alors, après une série de détections, ils deviendront proches et fusionneront en un avec leurs histoires.



# 6 Caractéristiques combinatoires. Quand la voiture ... pense!?



Il vaut la peine de définir un nouveau terme ici dans cet article. Un vecteur fantôme est un vecteur qui a été obtenu non pas à la suite d'une activité mémoire à court terme, mais à la suite d'une fonction sur N vecteurs du cluster (a1, a2, a3, a4 ...). Bien entendu, les vecteurs obtenus de cette manière sont stockés et comptabilisés séparément et ne représentent aucune valeur jusqu'à ce que, à la suite de l'appariement, ils soient déterminés comme les plus proches (voir # 3). Le principal avantage des vecteurs fantômes est d' accélérer l'apprentissage d'un cluster à ses débuts.



Le système est déjà en production. Le résultat a été obtenu sur des données réelles en dehors de l'environnement de test pour plus de 5000 utilisateurs; on a également remarqué un tas de points «faibles», qui ont été renforcés et pris en compte dans ce texte.



Fait intéressant, cette approche n'a pas de paramètres utilisateur et tout le travail n'est contrôlé d'aucune façon, tout est complètement autonome . De plus, l'analyse des séries chronologiques vous permet de classer l'utilisateur dans différentes catégories de la même manière, créant ainsi des associations. C'est ainsi que la question a été résolue - qui sont les employés et qui sont les visiteurs.



Le rôle de l'utilisateur système est simple: vous devez vérifier périodiquement votre courrier ou l'interface système pour de nouveaux rapports d'activité.



Résultat



La valeur de proximité pour la reconnaissance basée sur la mémoire à long terme est d'environ 0,12 à 0,25 pour un cluster modérément formé (contient 6 à 15 vecteurs a). En outre, l'apprentissage ralentit en raison d'une augmentation de la probabilité de «copies vectorielles», mais à long terme, la proximité tend vers des valeurs de ~ 0,04-0,12, lorsque le cluster contient déjà plus de 20 vecteurs a. Notez qu'à l'intérieur de la mémoire à court terme, d'une image à l'autre, le même paramètre a une valeur de ~ 0,5-1,2, ce qui ressemble à quelque chose comme: "Une personne se ressemble plus avec des lunettes il y a 2 ans qu'il y a 100 ms." De telles opportunités sont ouvertes par l' utilisation du clustering dans la mémoire à long terme .



énigme



L'un des tests a abouti à une observation intéressante.



Conditions initiales:



  • Sur deux PC absolument identiques, un système de vidéosurveillance absolument identique avec exactement les mêmes paramètres est déployé. Ils sont connectés à une seule caméra IP, située correctement, conformément au TOR.


Acte:



  • Les systèmes sont démarrés en même temps et laissés seuls pendant une semaine avec tous les algorithmes fonctionnant. Le trafic correspond au trafic normal sans changement.


Résultat:



  • Le nombre d'utilisateurs, de clusters et de vecteurs a créés est le même, mais les centres de gravité sont différents, pas de manière significative - mais différents. La question est pourquoi? Qui sait - écrivez dans les commentaires ou ici )


C'est dommage que je ne puisse pas écrire sur beaucoup de choses ici, mais peut-être que je peux décrire quelque chose avec le même détail dans un autre article. Peut-être que tout cela a déjà été décrit dans un merveilleux manuel, mais à mon grand regret, je n'en ai jamais trouvé.



En conclusion, je dirai qu'il est très intéressant d'observer de l'intérieur comment un système d'IA autonome classe l'espace environnant, en mettant en œuvre diverses fonctionnalités qui lui sont inhérentes en cours de route. Les gens ne remarquent pas beaucoup de choses en raison de l'expérience accumulée de la perception (étape 4).




J'espère vraiment que cet article sera utile à n'importe qui dans son projet.



All Articles