Cat Ghonim: Comment faire en sorte que les chats ne se soulagent pas sur la pelouse à la maison?

Il y avait Robert Bond, un programmeur californien de 65 ans. Et il avait une femme jardinière qui aimait beaucoup sa pelouse propre. Mais c'est la Californie, il n'y a pas de clôtures de deux mètres avec un système de protection pour les chats. Les chats voisins marchent sur la pelouse et la merde!



Le problème devait être résolu. Comment Robert a-t-il décidé cela? Il a acheté du fer à son ordinateur, y a connecté une caméra de surveillance extérieure, puis a fait quelque chose d'inhabituel.Il a téléchargé le logiciel gratuit Open Source disponible - un réseau de neurones, et a commencé à l'entraîner à reconnaître les chats dans l'image de la caméra. Et la tâche au début semble insignifiante, car si vous apprenez quelque chose et que c'est facile, c'est pour les chats, parce que les chats sont jonchés d'Internet, il y en a des dizaines de millions. Si tout était si simple, mais que les choses sont pires, dans la vraie vie, les chats vont faire la merde surtout la nuit. Il n'y a pratiquement pas de photos de chats nocturnes faisant pipi sur la pelouse sur Internet. Et certains chats parviennent même à boire dans le système d'irrigation pendant le travail, mais le jettent quand même.



Ci-dessous, nous fournissons une description du projet de l'auteur, la version anglaise peut être trouvée ici .

Ce projet était motivé par deux choses: le désir d'en savoir plus sur les logiciels de réseau neuronal et le désir d'encourager les chats voisins à sortir ailleurs que sur ma pelouse.

Le projet ne comprend que trois composants matériels: la carte Nvidia Jetson TX1 , la caméra IP Foscam FI9800P et le photon à particules connecté au relais . La caméra est montée sur le côté de la maison sur le côté de la pelouse. Elle contacte le point d'accès WI-FI, suivie de Jetson. Le photon à particules et les relais sont installés dans l'unité de contrôle de mon système d'irrigation et connectés à un point d'accès WI-FI dans la cuisine.

Dans le processus, la caméra est configurée pour surveiller les changements dans la cour. Lorsque quelque chose change, la caméra transmet un ensemble de 7 images à Jetson, une par seconde. Le service propulsé par Jetson suit les images entrantes, les transférant vers le réseau neuronal d'entraînement en profondeur de Caffe. Si le réseau détecte un chat, Jetson envoie un signal au serveur Particle Photon dans le cloud, qui envoie un message à Photon. Photon répond en allumant les gicleurs pendant deux minutes.

Ici, le chat est entré dans le cadre, allumant l'appareil photo:



Après quelques secondes, le chat est entré au milieu de la cour, rallumant la caméra et actionnant les arroseurs du système d'irrigation:



Installation de la caméra


Il n'y avait rien d'inhabituel à installer une caméra. La seule connexion permanente est une connexion filaire de 12 volts qui passe à travers un petit trou sous le rebord. J'ai monté la caméra sur une boîte en bois pour capturer la cour avant avec une pelouse. Un tas de fils sont connectés à la caméra, que j'ai caché dans une boîte.

Suivez les instructions de Foscam pour l'associer à l'AP de Jetson (voir ci-dessous). Dans ma configuration, Jetson est à 10.42.0.1. J'ai attribué une adresse IP fixe de 10.42.0.11 à la caméra afin qu'elle soit facile à trouver. Une fois cela fait, connectez l'ordinateur portable Windows à la caméra et configurez le paramètre «Avertissement» pour activer le changement. Configurez le téléchargement de 7 images via FTP par avertissement (alerte). Donnez-lui ensuite l'ID utilisateur et le mot de passe sur Jetson. Mon appareil photo envoie des images 640 x 360 par FTP à son répertoire personnel.

Ci-dessous, vous pouvez voir les paramètres qui ont été sélectionnés pour la configuration de la caméra.



Configuration du photon de particules


Photon était facile à installer. Je l'ai mis dans l'unité de contrôle de l'irrigation.



La boîte noire sur la gauche avec la LED bleue est un convertisseur 24 V AC (5 V) à 5 V DC acheté sur eBay. Vous pouvez voir le relais blanc sur la carte relais et le connecteur bleu à l'avant. Le photon lui-même est à droite. Les deux sont collés sur un morceau de carton pour les maintenir ensemble.

La sortie 5 V du convertisseur est connectée au connecteur VIN de photons de particules. La carte relais est principalement analogique: elle possède un transistor NPN à collecteur ouvert avec une entrée nominale de 3,3 V à la base du transistor et un relais 3 V. Le contrôleur de photons ne pouvait pas fournir suffisamment de courant pour contrôler le relais, j'ai donc connecté le collecteur de l'entrée du transistor à 5 V via une résistance avec une résistance de 15 Ohms et une puissance de 1/2 W, limitant le courant. Les contacts de relais sont connectés au ventilateur d'eau en parallèle avec le circuit de commande normal.

Voici le schéma de connexion:

Convertisseur 24VAC 24VAC <---> Boîtier de commande 24VAC OUT
Convertisseur 24VAC + 5V <---> Photon VIN, résistance à la carte relais + 3,3V
Convertisseur 24VAC GND <---> Photon GND, Relais GND
Photon D0 <---> Entrée de signal de la carte relais
Relais COM <---> Boîtier de commande 24VAC OUT
Relais NO <---> Vanne d'eau de cour avant

Installer Jetson


Les seuls composants matériels ajoutés à Jetson sont un SSD SATA et un petit concentrateur USB Belkin. Le concentrateur possède deux touches sans fil qui connectent un clavier et une souris.

Le SSD est apparu sans problème. Je l'ai reformaté en EXT4 et l'ai installé sous / caffe. Je recommande fortement de supprimer tout le code de votre projet, les référentiels git et les données d'application de votre carte SD interne Jetson, car il est souvent plus facile d'effacer votre système lors de la mise à niveau de Jetpack.



La configuration d'un point d'accès sans fil était assez simple (vrai!) Si vous avez suivi ce guide . Utilisez simplement le menu Ubuntu comme indiqué et assurez-vous d'ajouter ce paramètre de configuration .

J'ai installé vsftpd en tant que serveur FTP . La configuration est largement d'origine. Je n'ai pas activé le FTP anonyme. J'ai donné à la caméra un nom d'utilisateur et un mot de passe qui ne sont plus utilisés pour rien.

J'ai installé Caffe en utilisant la recette JetsonHacks . Je crois qu'il n'y a plus de problème LMDB_MAP_SIZE dans les versions actuelles, alors essayez de le construire avant d'apporter des modifications. Vous devriez être en mesure d'exécuter les tests et la démo de synchronisation mentionnés dans le script shell JetsonHacks. J'utilise actuellement Cuda 7.0, mais je ne suis pas sûr que ce soit significatif à ce stade. Utilisez CDNN, il économise une quantité importante de mémoire dans ces petits systèmes. Une fois qu'il est construit, ajoutez le répertoire de construction à la variable PATH afin que les scripts puissent trouver Caffe. Ajoutez également le répertoire lib de Caffe Python à votre PYTHONPATH.

~ $ echo $PATH /home/rgb/bin:/caffe/drive_rc/src:/caffe/drive_rc/std_caffe/caffe/build/tools:/usr/local/cuda-7.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin ~ $ echo $PYTHONPATH /caffe/drive_rc/std_caffe/caffe/python: ~ $ echo $LD_LIBRARY_PATH /usr/local/cuda-7.0/lib:/usr/local/lib 

J'utilise l'option de réseau entièrement convolutionnel pour la segmentation sémantique (FCN). Voir Berkeley Model Zoo , github .

J'ai essayé plusieurs autres réseaux et j'ai finalement opté pour FCN. En savoir plus sur le processus de sélection dans le prochain article. Le Fcn32s fonctionne bien sur TX1 - il prend un peu plus de 1 Go de mémoire, s'exécute en environ 10 secondes et segmente une image 640x360 en environ un tiers de seconde. Il existe un bon ensemble de scripts dans le référentiel github actuel, et le paramètre est indépendant de la taille de l'image - il redimensionne le réseau pour s'adapter à ce que vous y jetez.

Pour l'essayer, vous devrez déployer les modèles Caffe déjà formés. Cela prend quelques minutes: la taille du fichier fcn32s-heavy-pascal.caffemodel dépasse 500 Mo.

 $ cd voc-fcn32s $ wget `cat caffemodel-url` 

Modifiez infer.py en modifiant le chemin d'accès dans la commande Image.open () par le fichier .jpg correspondant. Modifiez la ligne "net" pour qu'elle pointe vers le modèle qui vient d'être chargé:

  -net = caffe.Net('fcn8s/deploy.prototxt', 'fcn8s/fcn8s-heavy-40k.caffemodel', caffe.TEST) +net = caffe.Net('voc-fcn32s/deploy.prototxt', 'voc-fcn32s/fcn32s-heavy-pascal.caffemodel', caffe.TEST) 

Vous aurez besoin du fichier voc-fcn32s / deploy.prototxt. Il est facilement généré à partir de voc-fcn32s / train.prototxt. Regardez les changements entre voc-fcn8s / train.prototxt et voc-fcn8s / deploy.prototxt pour voir comment faire, ou vous pouvez l'obtenir à partir de mon référentiel chasing-cats sur github. Vous devriez maintenant pouvoir exécuter.

  $ python infer.py 

Mon référentiel comprend plusieurs versions de infer.py, plusieurs utilitaires Python qui connaissent les fichiers segmentés, le code Photon et les scripts de gestion et les scripts d'exploitation que j'utilise pour démarrer et surveiller le système. En savoir plus sur le logiciel ci-dessous.

Sélection du réseau


Les réseaux de neurones pour la reconnaissance d'images sont généralement formés pour reconnaître un ensemble d'objets. Supposons que nous donnons à chaque objet un index de un à n. Le réseau de classification répond à la question "Quels objets dans cette image?" renvoyer un tableau de zéro à n-1, où chaque entrée de tableau a une valeur de zéro à un. Zéro signifie que l'objet n'est pas dans l'image. Une valeur non nulle signifie qu'elle peut être là avec une probabilité croissante lorsque la valeur approche de l'unité. Voici un chat et un homme dans un tableau de 5 éléments:



Un réseau segmenté segmente les pixels de l'image des zones occupées par des objets de notre liste. Elle répond à la question en renvoyant un tableau avec un enregistrement correspondant à chaque pixel de l'image. Chaque enregistrement a une valeur de zéro s'il s'agit d'un pixel d'arrière-plan ou une valeur de un à n pour n objets différents qu'il peut reconnaître. Cet exemple fictif peut être le pied d'une personne:



Ce projet fait partie d'un projet plus vaste visant à contrôler une voiture radiocommandée à l'aide d'un ordinateur. L'idée est d'utiliser un réseau de neurones pour déterminer la position (position et orientation tridimensionnelles globales) d'une voiture pour lui transmettre des commandes de navigation. La caméra est fixe et la pelouse est généralement plate. Je peux utiliser un peu le déclencheur pour changer la position 3D afin que le réseau neuronal puisse trouver les pixels et l'orientation de l'écran. Le rôle du chat dans tout cela est le «but recherché».

J'ai commencé par penser principalement à la voiture, car je ne savais pas comment ça allait se passer, en supposant que reconnaître un chat avec un réseau pré-formé serait trivial. Après beaucoup de travail, que je ne décrirai pas en détail dans cet article, j'ai décidé que vous pouvez déterminer l'orientation de la voiture avec un degré de fiabilité assez élevé. Voici un plan d'entraînement à un angle de 292,5 degrés:



La plupart de ces travaux ont été réalisés avec le réseau de classification, le modèle Caffe bvlc_reference_caffenet. Par conséquent, j'ai décidé de laisser la tâche de réseau de segmentation déterminer la position de la machine sur l'écran.

Le premier réseau que j'ai utilisé est Faster R-CNN [1]. Il renvoie des boîtes englobantes pour les objets de l'image, pas les pixels. Mais le réseau sur Jetson était trop lent pour cette application. L'idée d'une boîte englobante était très attrayante, j'ai donc également examiné le réseau axé sur la conduite [2]. Elle était également trop lente. FCN [3] était le réseau de segmentation le plus rapide que j'ai essayé. «FCN» signifie «réseau entièrement convolutionnel», réseau entièrement convolutionnel, car il ne nécessite plus de taille d'image particulière pour être entré et se compose uniquement de convolutions / regroupements. Passer uniquement aux couches convolutives conduit à une accélération significative, classant mes images d'environ 1/3 de seconde sur Jetson. FCN comprend un bon ensemble de scripts Python pour la formation et le déploiement facile. Les scripts Python redimensionnent le réseau pour s'adapter à n'importe quelle taille de l'image entrante, ce qui facilite le traitement de l'image principale. J'ai eu un gagnant!

La version FCN GitHub propose plusieurs options. J'ai d'abord essayé le voc-fcn32s. Cela a parfaitement fonctionné. Voc-fcn32s a été pré-formé dans 20 classes vocales standard. Comme c'est trop simple, j'ai essayé pascalcontext-fcn32s. Il a été formé dans 59 classes, y compris l'herbe et les arbres, donc j'ai pensé que ça devrait être mieux. Mais il s'est avéré que pas toujours - les images de sortie avaient beaucoup plus de jeux de pixels, et la segmentation des chats et des personnes superposées à l'herbe et aux buissons n'était pas si précise. La segmentation à partir de siftflow était encore plus complexe, donc je suis rapidement revenu aux options voc.

Choisir des réseaux vocaux signifie toujours trois choses à considérer: voc-fcn32s, voc-fcn16s et voc-fcn8s. Ils diffèrent par le «pas» de la segmentation de la sortie. L'étape 32 est l'étape principale du réseau: l'image 640x360 est réduite à un réseau 20x11 au moment où les couches convolutionnelles sont terminées. Cette segmentation brute «déconvolue» ensuite à 640x360, comme décrit dans [3]. Les étapes 16 et 8 sont réalisées en ajoutant plus de logique au réseau pour une meilleure segmentation. Je n'ai même pas essayé - la segmentation sur 32 segments est la première que j'ai essayée et elle est venue, et je m'en suis tenue parce que la segmentation semble assez bonne pour ce projet, et la formation, comme décrit, semble plus compliquée pour les deux autres réseaux.

La formation


La première chose que j'ai remarquée lorsque j'ai allumé et démarré le système était que seulement environ 30% des chats étaient reconnus par le réseau. J'ai trouvé deux raisons à cela. Premièrement, les chats viennent souvent la nuit, donc la caméra les voit à la lumière infrarouge. Cela peut être facilement résolu - il suffit d'ajouter quelques images infrarouges segmentées de chats pour la formation. Le deuxième problème que j'ai découvert après avoir examiné plusieurs centaines de photos de chats dans le kit de formation est que la plupart des photographies appartiennent à la variété «regardez mon joli chat». Ce sont des images frontales d'un chat au niveau de l'œil d'un chat. Soit le chat est allongé sur le dos, soit allongé sur les genoux de son propriétaire. Ils ne ressemblent pas à des chats errant dans ma cour. Encore une fois, il peut être facilement corrigé avec certaines images diurnes segmentées.



Comment segmenter un objet dans une image d'entraînement? Mon approche consiste à soustraire l'image d'arrière-plan puis à traiter les pixels de premier plan pour indiquer de suivre l'objet. En pratique, cela fonctionne plutôt bien, car dans mes archives de la caméra, il y a généralement une image qui a été prise quelques secondes avant l'image segmentée. Mais il y a des artefacts qui doivent être nettoyés, et la segmentation a souvent besoin d'être clarifiée, j'ai donc écrit un utilitaire de préparation grossière pour l'édition des segments d'image, src / extract_fg.cpp. Voir la note en haut du fichier source pour l'utilisation. C'est un peu maladroit et a de petites erreurs de vérification et a besoin d'être raffiné, mais cela fonctionne assez bien pour la tâche.

Maintenant que nous avons des images pour la formation, voyons comment procéder. J'ai cloné voc-fcn32s dans le répertoire rgb_voc_fcn32s. Tous les noms de fichiers feront référence à ce répertoire jusqu'à la fin de cette leçon.

  $ cp -r voc-fcn32s rgb_voc_fcn32s 

Code sur mon github, y compris un exemple de fichier de formation dans data / rgb_voc. Les principaux changements sont indiqués ci-dessous.

Format de fichier de formation


La couche de données distribuées attend des images codées en dur et des répertoires de segmentation. Le fichier de formation a une ligne par fichier; puis la couche de données obtient les noms des fichiers image et des segments, en ajoutant des noms de répertoire codés en dur. Cela n'a pas fonctionné pour moi, car j'ai plusieurs classes de données d'entraînement. Mes données d'entraînement ont un ensemble de lignes, chacune contenant une image et une segmentation pour cette image.

  $ head data/rgb_voc/train.txt /caffe/drive_rc/images/negs/MDAlarm_20160620-083644.jpg /caffe/drive_rc/images/empty_seg.png /caffe/drive_rc/images/yardp.fg/0128.jpg /caffe/drive_rc/images/yardp.seg/0128.png /caffe/drive_rc/images/negs/MDAlarm_20160619-174354.jpg /caffe/drive_rc/images/empty_seg.png /caffe/drive_rc/images/yardp.fg/0025.jpg /caffe/drive_rc/images/yardp.seg/0025.png /caffe/drive_rc/images/yardp.fg/0074.jpg /caffe/drive_rc/images/yardp.seg/0074.png /caffe/drive_rc/images/yard.fg/0048.jpg /caffe/drive_rc/images/yard.seg/0048.png /caffe/drive_rc/images/yard.fg/0226.jpg /caffe/drive_rc/images/yard.seg/0226.png 

J'ai remplacé voc_layers.py par rgb_voc_layers.py, qui comprend le nouveau schéma:

  --- voc_layers.py 2016-05-20 10:04:35.426326765 -0700 +++ rgb_voc_layers.py 2016-05-31 08:59:29.680669202 -0700 ... - # load indices for images and labels - split_f = '{}/ImageSets/Segmentation/{}.txt'.format(self.voc_dir, - self.split) - self.indices = open(split_f, 'r').read().splitlines() + # load lines for images and labels + self.lines = open(self.input_file, 'r').read().splitlines() 

Et modifié train.prototxt pour utiliser mon code rgb_voc_layers. Notez que les arguments sont également différents.

  --- voc-fcn32s/train.prototxt 2016-05-03 09:32:05.276438269 -0700 +++ rgb_voc_fcn32s/train.prototxt 2016-05-27 15:47:36.496258195 -0700 @@ -4,9 +4,9 @@ top: "data" top: "label" python_param { - module: "layers" - layer: "SBDDSegDataLayer" - param_str: "{\'sbdd_dir\': \'../../data/sbdd/dataset\', \'seed\': 1337, \'split\': \'train\', \'mean\': (104.00699, 116.66877, 122.67892)}" + module: "rgb_voc_layers" + layer: "rgbDataLayer" + param_str: "{\'input_file\': \'data/rgb_voc/train.txt\', \'seed\': 1337, \'split\': \'train\', \'mean\': (104.00699, 1 

Presque le même changement dans val.prototxt:

  --- voc-fcn32s/val.prototxt 2016-05-03 09:32:05.276438269 -0700 +++ rgb_voc_fcn32s/val.prototxt 2016-05-27 15:47:44.092258203 -0700 @@ -4,9 +4,9 @@ top: "data" top: "label" python_param { - module: "layers" - layer: "VOCSegDataLayer" - param_str: "{\'voc_dir\': \'../../data/pascal/VOC2011\', \'seed\': 1337, \'split\': \'seg11valid\', \'mean\': (104.00699, 116.66877, 122.67892)}" + module: "rgb_voc_layers" + layer: "rgbDataLayer" + param_str: "{\'input_file\': \'data/rgb_voc/test.txt\', \'seed\': 1337, \'split\': \'seg11valid\', \'mean\': (104.00699, 116.66877, 122.67892)}" 

Solver.py


Exécutez résoudre.py pour commencer votre séance d'entraînement:

  $ python rgb_voc_fcn32s / solve.py 

Il modifie certains des mécanismes normaux de Caffe. En particulier, le nombre d'itérations est défini en bas du fichier. Dans ce paramètre particulier, l'itération est une image car la taille du réseau change pour chaque image et les images sont ignorées une par une.

L'un des avantages de travailler avec Nvidia est que de très bons équipements sont disponibles. J'ai un Titan intégré dans un poste de travail, et ma direction n'a pas hésité à me laisser l'utiliser pour quelque chose d'aussi douteux que ce projet. Ma dernière course d'entraînement était de 4000 itérations, ce qui a pris un peu plus de deux heures sur Titan.

J'ai appris quelques trucs


  • Une poignée d'images (moins de 50) ont suffi pour entraîner le réseau à reconnaître les intrus nocturnes.
  • Les prises de vue nocturnes ont appris au réseau à penser que les ombres sur le sentier sont des chats.
  • Les prises de vue négatives, c'est-à-dire des images sans pixels segmentés, aident à résoudre le problème des ombres.
  • Il est facile de recycler le réseau à l'aide d'une caméra fixe afin que tout ce qui diffère soit classé comme quelque chose de aléatoire.
  • Les chats et les humains, superposés à des arrière-plans aléatoires, aident à résoudre les problèmes liés au surentraînement.

Comme vous pouvez le voir, le processus est itératif.

Recommandations


[1] R-CNN plus rapide: vers la détection d'objets en temps réel avec les réseaux de propositions de régions Shaoqing Ren, Kaiming He, Ross Girshick, Jian Sun abs / 1506.01497v3 .
[2] Une évaluation empirique de l'apprentissage en profondeur sur la conduite sur route Brody Huval, Tao Wang, Sameep Tandon, Jeff Kiske, Will Song, Joel Pazhayampallil, Mykhaylo Andriluka, Pranav Rajpurkar, Toki Migimatsu, Royce Cheng-Yue, Fernando Cojuj, Andrew Y. Ng arXiv: 1504.01716v3 , github.com/brodyh/caffe.git .
[3] Réseaux entièrement convolutifs pour la segmentation sémantique Jonathan Long, Evan Shelhamer, Trevor Darrell arXiv: 1411.4038v2 , github.com/shelhamer/fcn.berkeleyvision.org.git .

Conclusions


Afin d'apprendre au réseau neuronal à reconnaître les chats de nuit, il a fallu ajouter les données nécessaires, en les accumulant. Après cela, la dernière étape a été prise - le système est connecté à la vanne, qui démarre le pulvérisateur. L'idée est que dès que le chat pénètre dans la pelouse et veut s'adapter, il commence à être arrosé. Le chat se vide. La tâche est ainsi résolue, la femme est heureuse, et tout cet étrange miracle est un réseau neuronal qui enseigne à reconnaître les chats, découvre qu'Internet n'a pas assez d'images sources pour la formation et qui l'a appris, est devenu le seul réseau neuronal au monde à pouvoir reconnaître les chats de nuit.

Il convient de noter que tout cela a été fait par une personne qui n'est pas un hyperprogrammeur qui a travaillé dans Yandex ou Google toute sa vie et avec l'aide de matériel, assez bon marché, compact et simple.

Un peu de publicité :)


Merci de rester avec nous. Aimez-vous nos articles? Vous voulez voir des matériaux plus intéressants? Soutenez-nous en passant une commande ou en le recommandant à vos amis, une réduction de 30% pour les utilisateurs Habr sur un serveur d'entrée de gamme analogique unique que nous avons inventé pour vous: Toute la vérité sur VPS (KVM) E5-2650 v4 (6 cœurs) 10 Go DDR4 240 Go SSD 1 Gbps à partir de 20 $ ou comment diviser le serveur? (les options sont disponibles avec RAID1 et RAID10, jusqu'à 24 cœurs et jusqu'à 40 Go de DDR4).

Dell R730xd 2 fois moins cher? Nous avons seulement 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV à partir de 199 $ aux Pays-Bas! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - à partir de 99 $! Pour en savoir plus sur la création d'un bâtiment d'infrastructure. classe utilisant des serveurs Dell R730xd E5-2650 v4 coûtant 9 000 euros pour un sou?

Source: https://habr.com/ru/post/fr473334/


All Articles