Cat Ghonim: ¿Cómo hacer que los gatos no se alivien en el césped en casa?

Estaba Robert Bond, un programador de 65 años con sede en California. Y tenía una esposa de jardinería que amaba mucho su césped limpio. Pero esto es California, no hay cercas de dos metros con un sistema de protección para gatos. ¡Los gatos vecinos caminan por el césped y cagan!



El problema tuvo que ser resuelto. ¿Cómo lo decidió Robert? Compró algo de hierro en su computadora, conectó una cámara de vigilancia exterior que miraba hacia el césped, y luego hizo algo inusual, descargó el software gratuito de código abierto disponible, una red neuronal, y comenzó a entrenarla para reconocer a los gatos en la imagen de la cámara. Y la tarea al principio parece trivial, porque si aprendes algo y es fácil, es para gatos, porque los gatos están llenos de Internet, hay decenas de millones de ellos. Si todo era tan simple, pero las cosas son peores, en la vida real los gatos se cagan a la mierda principalmente por la noche. Prácticamente no hay imágenes de gatos nocturnos que orinen en el césped en Internet. Y algunos de los gatos incluso logran beber del sistema de riego durante el trabajo, pero aún lo tiran.



A continuación proporcionamos una descripción del proyecto del autor, la versión en inglés se puede encontrar aquí .

Este proyecto fue motivado por dos cosas: el deseo de aprender más sobre el software de redes neuronales y el deseo de alentar a los gatos vecinos a pasar el rato en otro lugar además de mi jardín.

El proyecto incluye solo tres componentes de hardware: la placa Nvidia Jetson TX1 , la cámara IP Foscam FI9800P y el Particle Photon conectado al relé . La cámara está montada en el costado de la casa al costado del césped. Ella se pone en contacto con el punto de acceso WI-FI, seguido de Jetson. El fotón de partículas y los relés se instalan en la unidad de control de mi sistema de riego y se conectan a un punto de acceso WI-FI en la cocina.

En el proceso, la cámara está configurada para monitorear los cambios en el patio. Cuando algo cambia, la cámara transmite un conjunto de 7 imágenes a Jetson, una por segundo. El servicio impulsado por Jetson rastrea las imágenes entrantes y las transfiere a la red neuronal de entrenamiento profundo de Caffe. Si la red detecta un gato, Jetson señala al servidor Particle Photon en la nube, que envía un mensaje a Photon. El fotón responde encendiendo los aspersores durante dos minutos.

Aquí el gato entró en el cuadro, encendiendo la cámara:



Después de unos segundos, el gato se metió en el centro del patio, volvió a encender la cámara y activó los aspersores del sistema de riego:



Configuración de la cámara


No había nada inusual en instalar una cámara. La única conexión permanente es una conexión cableada de 12 voltios que atraviesa un pequeño orificio debajo de la repisa. Monté la cámara en una caja de madera para capturar el patio delantero con césped. Hay un montón de cables conectados a la cámara, que escondí en una caja.

Siga las instrucciones de Foscam para asociarlo con el AP de Jetson (ver más abajo). En mi configuración, Jetson está en 10.42.0.1. Asigne una dirección IP fija de 10.42.0.11 a la cámara para que sea fácil de encontrar. Una vez hecho esto, conecte el portátil con Windows a la cámara y configure el parámetro "Advertencia" para activar el cambio. Configure la carga de 7 imágenes a través de FTP mediante advertencia (alerta). Luego proporcione el ID de usuario y la contraseña en Jetson. Mi cámara envía imágenes de 640x360 a través de FTP a su directorio de inicio.

A continuación puede ver los parámetros que se seleccionaron para la configuración de la cámara.



Configuración de fotones de partículas


Photon fue fácil de configurar. Lo puse en la unidad de control de riego.



El cuadro negro a la izquierda con el LED azul es un convertidor de 24 V CA (5 V) a 5 V CC comprado en eBay. Puede ver el relé blanco en la placa de relés y el conector azul en el frente. El fotón en sí está a la derecha. Ambos están pegados a un trozo de cartón para mantenerlos unidos.

La salida de 5 V del convertidor está conectada al conector VIN de Particle Photon. La placa de relés es principalmente analógica: tiene un transistor NPN de colector abierto con una entrada nominal de 3.3 V a la base del transistor y un relé de 3 V. El controlador de fotones no podía suministrar suficiente corriente para controlar el relé, por lo que conecté el colector de la entrada del transistor a 5 V a través de una resistencia con una resistencia de 15 ohmios y una potencia de 1/2 W, lo que limita la corriente. Los contactos del relé están conectados al ventilador de agua en paralelo con el circuito de control normal.

Aquí está el diagrama de conexión:

Convertidor de 24 VCA 24 VCA <---> Caja de control SALIDA DE 24 VCA
Convertidor de 24 VCA + 5 V <---> Photon VIN, resistencia a la placa de relé + 3,3 V
Convertidor 24VAC GND <---> Photon GND, Relay GND
Photon D0 <---> Entrada de señal de placa de relé
Relé COM <---> Caja de control 24VAC OUT
Relé NO <---> Válvula de agua del patio delantero

Instalar Jetson


Los únicos componentes de hardware agregados a Jetson son un SSD SATA y un pequeño concentrador USB de Belkin. El concentrador tiene dos llaves inalámbricas que conectan un teclado y un mouse.

SSD surgió sin problemas. Lo reformateé a EXT4 y lo instalé como / caffe. Recomiendo eliminar todo el código de su proyecto, los repositorios git y los datos de la aplicación de su tarjeta SD interna de Jetson, porque a menudo es más fácil borrar su sistema al actualizar Jetpack.



Configurar un punto de acceso inalámbrico era bastante simple (¡cierto!) Si seguía esta guía . Simplemente use el menú de Ubuntu como se indica, y asegúrese de agregar este parámetro de configuración .

Instalé vsftpd como un servidor FTP . La configuración es en gran parte stock. No habilité el FTP anónimo. Le di a la cámara un nombre de usuario y una contraseña que ya no se usan para nada.

Instalé Caffe usando la receta JetsonHacks . Creo que ya no hay un problema LMDB_MAP_SIZE en las versiones actuales, así que intente compilarlo antes de realizar cualquier cambio. Debería poder ejecutar las pruebas y la demostración de sincronización mencionadas en el script de shell JetsonHacks. Actualmente estoy usando Cuda 7.0, pero no estoy seguro de si esto es significativo en esta etapa. Use CDNN, ahorra una cantidad significativa de memoria en estos pequeños sistemas. Una vez que está construido, agregue el directorio de construcción a la variable PATH para que los scripts puedan encontrar Caffe. Agregue también el directorio lib de Caffe Python a su 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 

Estoy usando la opción Red totalmente convolucional para la segmentación semántica (FCN). Ver Berkeley Model Zoo , github .

Probé varias otras redes y finalmente me decidí por FCN. Lea más sobre el proceso de selección en el próximo artículo. Fcn32s funciona bien en TX1: ocupa un poco más de 1 GB de memoria, se ejecuta en aproximadamente 10 segundos y segmenta una imagen de 640x360 en aproximadamente un tercio de segundo. Hay un buen conjunto de scripts en el repositorio actual de github, y la configuración es independiente del tamaño de la imagen: cambia el tamaño de la red para que se ajuste a lo que arroja.

Para probarlo, deberá implementar los modelos Caffe ya entrenados. Tarda unos minutos: el tamaño del archivo fcn32s-heavy-pascal.caffemodel supera los 500 MB.

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

Edite infer.py cambiando la ruta en el comando Image.open () al correspondiente .jpg. Cambie la línea "net" para que apunte al modelo recién cargado:

  -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) 

Necesitará el archivo voc-fcn32s / deploy.prototxt. Se genera fácilmente desde voc-fcn32s / train.prototxt. Mire los cambios entre voc-fcn8s / train.prototxt y voc-fcn8s / deploy.prototxt para ver cómo hacerlo, o puede obtenerlo desde mi repositorio de chasing-cats en github. Ahora deberías poder correr.

  $ python infer.py 

Mi repositorio incluye varias versiones de infer.py, varias utilidades de Python que conocen archivos segmentados, código Photon y scripts de administración y scripts operativos que utilizo para iniciar y monitorear el sistema. Lea más sobre el software a continuación.

Selección de red


Las redes neuronales para el reconocimiento de imágenes generalmente están entrenadas para reconocer un conjunto de objetos. Supongamos que le damos a cada objeto un índice de uno a n. La red de clasificación responde a la pregunta "¿Qué objetos en esta imagen?" devolver una matriz de cero a n-1, donde cada entrada de matriz tiene un valor de cero a uno. Cero significa que el objeto no está en la imagen. Un valor distinto de cero significa que puede estar allí con una probabilidad creciente cuando el valor se acerca a la unidad. Aquí hay un gato y un hombre en una serie de 5 elementos:



Una red segmentada segmenta píxeles de imagen de áreas que están ocupadas por objetos de nuestra lista. Ella responde la pregunta devolviendo una matriz con un registro correspondiente a cada píxel de la imagen. Cada registro tiene un valor de cero si es un píxel de fondo, o un valor de uno a n para n objetos diferentes que puede reconocer. Este ejemplo ficticio puede ser el pie de una persona:



Este proyecto es parte de un proyecto más grande destinado a controlar un automóvil controlado por radio usando una computadora. La idea es utilizar una red neuronal para determinar la posición (posición y orientación tridimensional global) de un automóvil para transmitirle comandos de navegación. La cámara está fija y el césped es en su mayor parte plano. Puedo usar el gatillo un poco para cambiar la posición 3D para que la red neuronal pueda encontrar los píxeles y la orientación de la pantalla. El papel del gato en todo esto es el "propósito previsto".

Comencé pensando principalmente en el automóvil, porque no sabía cómo resultaría, suponiendo que reconocer un gato con una red pre-entrenada sería trivial. Después de mucho trabajo, que no describiré en detalle en este artículo, decidí que puede determinar la orientación del automóvil con un grado bastante alto de confiabilidad. Aquí hay un tiro de entrenamiento en un ángulo de 292.5 grados:



La mayor parte de este trabajo se ha realizado con la red de clasificación, el modelo Caffe bvlc_reference_caffenet. Por lo tanto, decidí dejar que la tarea de red de segmentación determinara la posición de la máquina en la pantalla.

La primera red que utilicé es Faster R-CNN [1]. Devuelve cuadros delimitadores para objetos en la imagen, no píxeles. Pero la red en Jetson era demasiado lenta para esta aplicación. La idea de un cuadro delimitador era muy atractiva, así que también miré la red orientada a la conducción [2]. Ella también era demasiado lenta. FCN [3] fue la red de segmentación más rápida que probé. “FCN” significa “red totalmente convolucional”, red totalmente convolucional, ya que ya no requiere que se ingrese ningún tamaño de imagen en particular y consiste solo en convoluciones / agrupaciones. Cambiar solo a capas convolucionales conduce a una aceleración significativa, clasificando mis imágenes en aproximadamente 1/3 de segundo en Jetson. FCN incluye un buen conjunto de scripts de Python para capacitación y fácil implementación. Los scripts de Python redimensionan la red para que se adapte a cualquier tamaño de la imagen entrante, lo que facilita el procesamiento de la imagen principal. Tuve un ganador!

El lanzamiento de FCN GitHub tiene varias opciones. Primero probé voc-fcn32s. Funcionó perfectamente. Voc-fcn32s fue pre-entrenado en 20 clases de voc estándar. Como esto es demasiado simple, probé pascalcontext-fcn32s. Fue entrenado en 59 clases, incluyendo césped y árboles, así que pensé que debería ser mejor. Pero resultó que no siempre: las imágenes de salida tenían muchos más conjuntos de píxeles, y la segmentación de gatos y personas superpuestas en hierba y arbustos no era tan precisa. La segmentación de siftflow era aún más compleja, por lo que rápidamente volví a las opciones de voc.

Elegir redes voc aún significa tres cosas a tener en cuenta: voc-fcn32s, voc-fcn16s y voc-fcn8s. Se diferencian en el "paso" de la segmentación de salida. El paso 32 es el paso principal de la red: la imagen de 640x360 se reduce a una red de 20x11 cuando se completan las capas convolucionales. Esta segmentación cruda luego "deconvoluciona" de nuevo a 640x360, como se describe en [3]. Los pasos 16 y 8 se logran agregando más lógica a la red para una mejor segmentación. Ni siquiera lo intenté: la segmentación de 32 segmentos es la primera que probé y surgió, y me apegué a ella porque la segmentación se ve lo suficientemente buena para este proyecto, y la capacitación, como se describe, parece más complicada para las otras dos redes.

Entrenamiento


Lo primero que noté cuando encendí y comencé el sistema fue que solo alrededor del 30% de los gatos eran reconocidos por la red. Encontré dos razones para esto. En primer lugar, los gatos suelen venir de noche, por lo que la cámara los ve con luz infrarroja. Esto se puede solucionar fácilmente: solo agregue algunas imágenes infrarrojas segmentadas de gatos para entrenar. El segundo problema que descubrí después de revisar varios cientos de fotografías de gatos del kit de entrenamiento es que muchas de las fotografías pertenecen a la variedad "mira mi lindo gatito". Estas son imágenes frontales de un gato al nivel del ojo de un gato. O el gato se acuesta boca arriba o se acuesta en el regazo de su dueño. No parecen gatos deambulando por mi patio. Una vez más, se puede arreglar fácilmente con algunas imágenes diurnas segmentadas.



¿Cómo segmentar un objeto en una imagen de entrenamiento? Mi enfoque es restar la imagen de fondo y luego procesar los píxeles de primer plano para indicar el seguimiento del objeto. En la práctica, esto funciona bastante bien, porque en mi archivo de la cámara generalmente hay una imagen que se tomó unos segundos antes de la imagen segmentada. Pero hay artefactos que deben limpiarse, y la segmentación a menudo necesita aclaración, por lo que escribí una utilidad de preparación aproximada para editar segmentos de imagen, src / extract_fg.cpp. Consulte la nota en la parte superior del archivo fuente para su uso. Es un poco torpe y tiene pequeños errores de verificación y necesita un poco de refinamiento, pero funciona lo suficientemente bien para la tarea.

Ahora que tenemos algunas imágenes para entrenamiento, veamos cómo hacerlo. Cloné voc-fcn32s en el directorio rgb_voc_fcn32s. Todos los nombres de archivo se referirán a este directorio hasta el final de esta lección.

  $ cp -r voc-fcn32s rgb_voc_fcn32s 

Código en mi github, incluido un archivo de entrenamiento de muestra en data / rgb_voc. Los principales cambios se indican a continuación.

Formato de archivo de entrenamiento


La capa de datos distribuidos espera imágenes codificadas y directorios de segmentación. El archivo de entrenamiento tiene una línea por archivo; luego la capa de datos obtiene los nombres de los archivos y segmentos de imagen, agregando nombres de directorio codificados. Esto no funcionó para mí, porque tengo varias clases de datos de entrenamiento. Mis datos de entrenamiento tienen un conjunto de líneas, cada una de las cuales contiene una imagen y una segmentación para esa imagen.

  $ 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 

Reemplacé voc_layers.py con rgb_voc_layers.py, que comprende el nuevo esquema:

  --- 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() 

Y modifiqué train.prototxt para usar mi código rgb_voc_layers. Tenga en cuenta que los argumentos también son diferentes.

  --- 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 

Casi el mismo cambio en 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


Ejecute solve.py para comenzar su entrenamiento:

  $ python rgb_voc_fcn32s / solve.py 

Modifica algunos de los mecanismos normales de Caffe. En particular, el número de iteraciones se establece en la parte inferior del archivo. En esta configuración particular, la iteración es una imagen porque el tamaño de la red cambia para cada imagen y las imágenes se saltan de una en una.

Una de las mejores cosas de trabajar con Nvidia es que hay equipos realmente excelentes disponibles. Tengo un Titan integrado en una estación de trabajo, y a mi gerencia no le importó dejarme usarlo para algo tan dudoso como este proyecto. Mi última carrera de entrenamiento fue de 4,000 iteraciones, lo que tomó un poco más de dos horas en Titán.

Aprendi algunas cosas


  • Un puñado de imágenes (menos de 50) fueron suficientes para entrenar a la red a reconocer a los intrusos nocturnos.
  • Los disparos nocturnos le enseñaron a la red a pensar que las sombras en el sendero son gatos.
  • Las tomas negativas, es decir, las imágenes sin píxeles segmentados, ayudan a lidiar con el problema de las sombras.
  • Es fácil volver a entrenar la red con una cámara fija para que todo lo que difiere se clasifique como algo aleatorio.
  • Los gatos y los humanos, superpuestos sobre fondos aleatorios, ayudan con los problemas derivados del sobreentrenamiento.

Como puede ver, el proceso es iterativo.

Recomendaciones


[1] R-CNN más rápido: hacia la detección de objetos en tiempo real con redes de propuestas regionales Shaoqing Ren, Kaiming He, Ross Girshick, Jian Sun abs / 1506.01497v3 .
[2] Una evaluación empírica del aprendizaje profundo en conducción en carretera Brody Huval, Tao Wang, Sameep Tandon, Jeff Kiske, Will Song, Joel Pazhayampallil, Mykhaylo Andriluka, Pranav Rajpurkar, Toki Migimatsu, Royce Cheng-Yue, Fernando Cojuju, Fernando Mujica, Andrew Y. Ng arXiv: 1504.01716v3 , github.com/brodyh/caffe.git .
[3] Redes totalmente convolucionales para la segmentación semántica Jonathan Long, Evan Shelhamer, Trevor Darrell arXiv: 1411.4038v2 , github.com/shelhamer/fcn.berkeleyvision.org.git .

Conclusiones


Para enseñar a la red neuronal a reconocer a los gatos nocturnos, fue necesario agregar los datos necesarios y acumularlos. Después de eso, se dio el último paso: el sistema está conectado a la válvula, que inicia el pulverizador. La idea es que tan pronto como el gato ingrese al césped y quiera adaptarse, comience a regar. El gato se tira. La tarea está resuelta, la esposa está feliz y todo este extraño milagro es una red neuronal que enseña a reconocer a los gatos, descubre que Internet no tiene suficientes fuentes de imágenes para el entrenamiento y que, al enterarse de esto, se convirtió en la única red neuronal en el mundo que puede reconocer a los gatos nocturnos.

Vale la pena señalar que todo esto fue hecho por una persona que no es un hiperprogramador que trabajó en Yandex o Google toda su vida y con la ayuda de hardware, bastante barato, compacto y simple.

Un poco de publicidad :)


Gracias por quedarte con nosotros. ¿Te gustan nuestros artículos? ¿Quieres ver más materiales interesantes? Apóyenos haciendo un pedido o recomendándolo a sus amigos, un descuento del 30% para los usuarios de Habr en un servidor de nivel de entrada analógico único que inventamos para usted: toda la verdad sobre VPS (KVM) E5-2650 v4 (6 núcleos) 10GB DDR4 240GB SSD 1Gbps desde $ 20 o cómo dividir el servidor? (las opciones están disponibles con RAID1 y RAID10, hasta 24 núcleos y hasta 40GB DDR4).

Dell R730xd 2 veces más barato? ¡Solo tenemos 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV desde $ 199 en los Países Bajos! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - ¡desde $ 99! Lea sobre Cómo construir un edificio de infraestructura. clase utilizando servidores Dell R730xd E5-2650 v4 que cuestan 9,000 euros por un centavo?

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


All Articles