Ideas Locas

Ideas Locas

Ciberseguridad
Stack SMS: ejemplo IoT con Raspberry Pi y actualización del repositorio
Coincidiendo con la grabación del último Code Talks For Devs, el cual trata precisamente de Stack SMS IoT, hemos realizado una serie de actualizaciones en el repositorio GitHub de esta herramienta. En dicho talk, que pertenece a nuestra serie de webinars para desarrolladores, hemos hablado de la aplicación práctica de Stack SMS como posible solución a un ataque DDoS, creando un canal alternativo de comunicaciones en nuestra infraestructura. De esta forma, sería posible acceder al resto de los dispositivos que componen nuestra red IoT e incluso llegar a ejecutar acciones complejas directamente sobre ellos. Puedes obtener más información sobre Stack SMS y dicho ejemplo en este artículo que escribimos en el blog de Chema Alonso o en el paper publicado. Implementando Stack SMS IoT con Raspberry Pi y módulo GSM Figura 1. Implementación con Rasbperry Pi y módulo GSM de Stack SMS IoT. Resumiendo, la solución mostrada se basa en una Rasbperry Pi y un módulo (shield) de GSM que permite realizar acciones sobre dicha infraestructura simplemente enviando mensajes SMS desde una aplicación. Esta aplicación también la hemos implementado en Android la cual nos permite controlar los dispositivos desde el móvil. Este ejemplo es un buen punto de partida para que puedas crear tu propia implementación de Stack SMS sea cual sea el entorno o la aplicación que necesites ejecutar, ya que se muestra en detalle como interactuar y codificar y decodificar los SMS utilizando el SDK de Stack SMS. Stack SMS en el repositorio de GitHub Pues precisamente, este ejemplo que explicamos en el Code Talk es la principal actualización que hemos realizado al repositorio de Stack SMS. En la carpeta "examples" podéis encontrar ahora la implementación completa, tanto de la aplicación Android que mostramos como del código necesario para ejecutar Stack SMS como servidor en la Raspberry Pi. Dentro existen dos carpetas, una para la aplicación Android y su código fuente llamada SmsHomeStackApp y otra con la implementación para la Rasbperry Pi llamada sms-home-stack. La carpeta sms-home-stack, es decir, la aplicación en Python para su utilización en una Raspberry Pi como ya hemos comentado, contiene varios ficheros que pasamos a describir brevemente: sms_broadcaster.py: es el encargado de enviar el mensaje o las acciones a través de SMS, utilizando la codificación serie con el comando AT, como se puede apreciar en este ejemplo: 'AT+CMGS="{}"\r' sms_layer_rasp.py: aquí podemos encontrar la implementación del layer (o capa) de Stack SMS. Recordemos que es un protocolo que se encapsula según la aplicación que queramos controlar, en este caso orientado a la Raspberry Pi. En otras palabras, podríamos decir que esta sería la implementación de la capa de aplicación. sms_stack_Controller: este módulo es el encargado de ir recibiendo y enviando los SMS. Utiliza varios métodos propios de Stack SMS como la gestión de un paquete/mensaje, si recibimos todo el stream de paquetes/mensajes de un hilo en concreto, etc. sms_stack_base.py:es la implementación principal que centraliza todas las peticiones y las gestiones de comunicación SMS. También es aquí donde se implementa la comunicación y la ejecución de los comandos que recibirá la Rasbperry Pi y el tipo de ejecución que realizará. Esta implementación se explica en detalle en el Code Talk antes mencionado. La carpeta SmsHomeStackApp contiene el código fuente de la aplicación en Android que hemos utilizado para gestionar el envío y recepción de SMSs codificados con Stack SMS entre la Raspberry Pi y la aplicación, así como su decodificación. Figura 2. Esquema de la solución usando Stack SMS en un ataque DDoS Esperamos que la publicación del código de de este ejemplo os anime a experimentar con Stack SMS. Recordar que nuestra serie de Code Talks For Devs contiene otros proyectos interesantes como Stack SMS, así que no dudéis en echarle un vistazo. #CodeTalks4Devs sobre StackSMS ya disponible
19 de diciembre de 2019
AI & Data
Deep Learning con Python: Introducción a TensorFlow (Parte III)
Hemos llegado al tercer y último artículo de nuestra serie de introducción al Deep Learning con Python haciendo uso del framework TensorFlow. Recordemos que en el artículo anterior, Deep Learning con Python: Introducción a TensorFlow (Parte II), una vez asimilados los conceptos básicos de sesión, grafo, variable y placeholder explicados en el primer artículo Deep Learning con Python: Introducción a TensorFlow (Parte I), realizamos algunos ejemplos de regresión lineal con datasets de datos cocinados por nosotros. Como adelantamos en el anterior post, en este artículo os mostraremos cómo definir una red convolucional para abordar la clasificación de uno de los datasets más conocidos: CIFAR-10. Para la definición del modelo de red profunda, haremos uso de Keras, una librería Python de Deep Learning que proporciona una interfaz de alto nivel con las librerías Theano y TensorFlow. Instalar Keras es muy sencillo. Se pueden encontrar instrucciones para ello en el siguiente enlace. Además, se indica cómo abordar la instalación tanto de TensorFlow como de Theano, además de CNTK, en el caso de que se desee cambiar el backend de la librería Keras. TensorFlow viene como el backend por defecto para Keras. Este hecho se puede comprobar en el fichero ~/.keras/keras.json: { "image_dim_ordering": "tf", "epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow" } Para cambiar el backend a Theano, sólo es necesario cambiar el contenido del fichero anterior por lo siguiente: { "image_dim_ordering": "th", "epsilon": 1e-07, "floatx": "float32", "backend": "theano" } El data-set que vamos a usar en el siguiente Jupyter Notebook es el CIFAR-10, habitual en el entrenamiento de modelos dedicados a reconocimiento de imágenes. Está formado en 60,000 imágenes a color de 32x32 con 10 clases asignadas, por lo que obtenemos unas 6000 imágenes por clase. Las etiquetas en este dataset son: ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']. Figura 1: Ejemplo de imágenes del CIFAR-10 dataset ordenadas por clases. Fuente: Computer Science University of Toronto En este post veremos cómo una red neuronal profunda es capaz de tener un buen comportamiento a la hora de clasificar imágenes. Incluso si el entrenamiento no se extiende demasiado, las precisiones en la clasificación pueden ser superiores al 70%. Como ya vimos en la serie de Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos ( Parte I, Parte II y Parte III) las redes profundas tienen la capacidad de aprender funciones de abstracción a lo largo de sus niveles de abstracción. Os animamos a leer los artículos para ver distintas aplicaciones de este tipo de arquitecturas, así como para introducirse en la teoría detrás de este tipo de redes. Por ejemplo, al entrenar una CNN profunda para clasificar imágenes, encontraremos que la primera capa se entrenará para reconocer cosas muy básicas como los bordes, la siguiente capa se entrenará para reconocer colecciones de formas, la siguiente capa se adiestrará en el reconocimiento de colecciones de formas (como ruedas, piernas, colas, caras como es nuestro caso) y la siguiente capa aprenderá incluso características de orden superior como objetos (camión, barco, perro, rana, etc.). La capacidad de generalización de este tipo de modelos es excelente, ya que se aprenden todas las características intermedias entre la entrada en bruto y la clasificación de alto nivel, que es la que obtenemos a la salida de la arquitectura. La arquitectura que hemos usado sigue el esquema habitual para este tipo de redes: Capa(s) convolucional(es) Capa de Pooling Capa de Flattening Arquitectura Densa Capa de Output Nuestra red está compuesta por dos conjuntos de dos capas convolucionales seguidas de una capa de pooling. De la última capa de pooling se concatenan una serie de capas densas totalmente conectadas (fully-connected) que van disminuyendo su dimensionalidad hasta el número de clases que compone nuestro dataset y que queremos predecir. A continuación, incluimos un resumen de las capas del modelo, dimensionalidades y número de parámetros implicados en el entrenamiento: Figura 2: resumen del modelo de red convolucional entrenado para la clasificación de imágenes de CIFAR-10. Como vemos en el resumen del modelo superior, tendremos que entrenar algo más de 1,2 millones de parámetros en nuestro modelo. Con la arquitectura indicada y haciendo uso de una máquina virtual en Oracle VirtualBox con Sistema Operativo Ubuntu 16.04.4 LTS a la que se le asignaron los siguientes parámetros: • Procesador: 2x Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz, • Memoria: 8776MB (4894MB used), tardamos 1h 9min en entrenar el modelo durante 10 épocas para conseguir una precisión del 79.05% sobre las 10,000 imágenes que constituyen el test dataset. A continuación mostramos el .ipynb donde mostramos todos los pasos necesarios a dar para poder reproducir el ejercicio de entrenamiento de una red convolucional con CIFAR-10. https://gist.github.com/eblancoh/d379d92a3680360857581d8937ef114b.js'%20defer%20onload='' defer onload=' Si disponéis de tiempo para entrenar durante más de 10 épocas y de una máquina más potente que la usada para plasmar los resultados que se pueden encontrar Jupyter Notebook anterior, os animamos a jugar con la arquitectura, funciones de pérdida y optimizadores para conseguir más precisión a la hora de clasificar imágenes. Dado el tamaño del dataset y del tiempo de entrenamiento dedicado, ser capaz de clasificar correctamente aproximadamente 8 de cada 10 imágenes se puede considerar un buen registro. Se debe tener en cuenta que cada vez que se modifique la arquitectura del modelo el checkpoint que hayáis almacenado del modelo anterior será inservible, no siendo posible retomar el entrenamiento desde el punto anterior. Para todos aquellos que en nuestra encuesta de Twitter votasteis por la clasificación de números escritos a mano del dataset MNIST, a continuación os dejamos otro Jupyter Notebook donde, haciendo uso de un modelo lineal más sencillo al usado en CIFAR-10, somos capaces de estimar con alta tasa de acierto ante qué número nos enfrentamos. https://gist.github.com/eblancoh/4866a93d7193326ee1677f758a81ecf9.js'%20defer%20onload='' defer onload=' En este último caso el modelo se ha construido haciendo única y exclusivamente uso de TensorFlow, por lo que podréis ver con mayor detalle la definición de variables en TensorFlow, la elección y definición del modelo a optimizar, la posterior construcción de la función de coste para la optimización y el método de optimización elegido. Además, se incluyen algunos ejemplos sencillos de rutinas de monitorización del entrenamiento que pueden resultar útiles. Los post más interesantes de LUCA Data Speaks 2018 organizados por series y temáticas Deep Learning con Python: Introducción a TensorFlow (Parte I) Deep Learning con Python: Introducción a TensorFlow (Parte II) Deep Learning con Python: Introducción a TensorFlow (Parte III)
26 de julio de 2018
AI & Data
Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos (Parte III)
En este post, daremos detalles sobre las arquitecturas elegidas para los modelos, la lógica que sigue el entrenamiento del agente y los resultados tras concluir el aprendizaje de la IA. Este artículo supone la conclusión de nuestro experimento de Deep Learning y Aprendizaje Reforzado en juegos generados por la librería OpenAI Gym. Recomendamos leer los dos artículos anteriores de esta serie. Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos (Parte I) Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos (Parte II) Como ya indicamos en el anterior artículo de esta serie, todo el contenido presentado en estos artículos está disponible en el siguiente webinar. Figura 0: Jugador de videojuegos. Redes Convolucionales. Arquitecturas de los modelos Nuestro agente debe utilizar una política de acciones adecuada que nos permita aproximar satisfactoriamente la función que maximice la recompensa a obtenida tras la aplicación una acción a dado un estado. Para poder lidiar con la complejidad derivada de un conjunto de estados complejos y aproximar esta función, necesitamos aplicar los algoritmos conocidos de Aprendizaje Reforzado (RL) a Redes Neuronales Profundas – Deep Neural Networks (DNNs). Este tipo de redes también se conocen como Deep Q-Networks (DQN). Para este tipo de entrenamiento, las redes neuronales a usar son las llamadas Convolutional Neural Networks, las cuales han demostrado a lo largo de la historia del Deep Learning ser arquitecturas con un excelente comportamiento a la hora de reconocer y aprender patrones basados en imágenes. Este tipo de redes toman los valores de los píxeles de los fotogramas que se le entregan como input. De manera genérica, una Red Neuronal Profunda ( DNN) tomará los valores de los píxeles como input a su modelo. Generalmente, se comienza con una capa de dimensiones similares al input del modelo y se termina con una capa de dimensión reducida al espacio de acciones del entorno. Las representaciones de las entradas se irán abstrayendo en mayor medida según se profundice en la arquitectura, y terminarán reducidas a una capa densa final con un número de salidas igual al espacio de acciones del entorno ( 4 en el caso de Breakout-v0, 6 en el caso de SpaceInvaders-v0). Tener una arquitectura con varias capas, nos permitirá extraer estructuras difícilmente identificables en entradas complejas. El número de las capas y su dimensión deben ser también cuidadosamente elegidos. Como se verá posteriormente, incluir un elevado número de capas en nuestro modelo, puede resultar contraproducente si lo que queremos es optimizar el tiempo de entrenamiento. A pesar de que es habitual colocar operaciones de pooling entre capas convolucionales, en este caso no se han incluido entre las tres primeras capas. Esto se debe a que al incluirlo entre capas convolucionales, las representaciones aprendidas por el modelo se vuelven invariantes a su situación espacial, por lo que la red se le complica determinar la localización de un objeto en la imagen. Esta característica es conveniente cuando la localización del objeto en la imagen no es del todo reseñable (como por ejemplo, en identificación de imágenes). Sin embargo, para el caso que nos aplica, la localización relativa de los objetos en el juego es imprescindible a la hora de determinar la acción que se debe tomar para maximizar la recompensa. Para Breakout-v0, se ha elegido una arquitectura con varias capas convolucionales que recoge el estado devuelto por la capa anterior, aplicando una función de activación de rectificación lineal ( ReLU). La primera capa convolucional consta de 16 filtros con un kernel 3x3 y stride 2. La segunda capa convolucional tiene 32 filtros con kernel 3x3 y stride 2. La tercera capa convolucional aumenta hasta los 64 filtros con kernel 3x3 y stride 1. Posteriormente se incluyen, con la misma activación que las capas convolucionales a excepción de la última capa: Una capa densa totalmente conectada (fully-connected) de 1024 unidades. Otra capa densa fully-connected de 516 unidades. Una última capa de salida con tantas unidades como env.action_space.n tengamos (4 para este entorno). Para SpaceInvaders-v0, se optó por una arquitectura convolucional similar a la usada en Breakout-v0. La primera capa convolucional consta de 16 filtros con un kernel 3x3 y stride 2. La segunda capa convolucional tiene 32 filtros con kernel 3x3 y stride 2. La tercera capa convolucional aumenta hasta los 64 filtros con kernel 3x3 y stride 2. Con la misma activación que las capas convolucionales con excepción de la última capa, se incluyen: Una capa densa fully-connected de 516 unidades. Una última capa de salida con 6 unidades. Los hiperparámetros de este modelo son los mismos que los usados para el entorno de Breakout-v0. Lógica del entrenamiento del agente A grandes rasgos, el algoritmo usado por el agente para las soluciones propuestas sigue los siguientes pasos. Inicializar todos los Q-values alrededor de cero. Se genera el modelo llamando a la clase de la red neuronal, dedicada a estimar los Q-values dada una determinada imagen del juego. Genera un estado a partir de la clase dedicada al pre-procesado de las imágenes del entorno del juego. La estructura de esta clase depende de la estrategia elegida. Si se usa una única imagen del entorno, resultará imposible determinar tanto la dirección de movimiento como la velocidad de la pelota y la pala. Una alternativa inmediata es contemplar la opción de incluir en el estado una segunda imagen procesada que muestra las trazas de los movimientos más recientes en el entorno de juegos. Otra alternativa, se basa incluir en el mismo estado las últimas 4 imágenes de juego, con la intención de que se pueda deducir dirección, velocidad y aceleración de los elementos del entorno de juego. Independientemente de la estrategia empleada, la misión de esta clase es generar un estado con el que alimentar al modelo para poder obtener los Q-values. Una vez generado el input, se introduce en el modelo. Se toma una acción bien aleatoria con probabilidad epsilon bien en base al Q-value más elevado. Esta política de toma de decisiones viene definida en la clase EpsilonGreedy. Añade el estado obtenido 2., la acción tomada y la recompensa obtenida a la ReplayMemory. Cuando la ReplayMemory esté llena o lo suficientemente llena, recorrer hacia atrás la memoria y actualizar todos los Q-values de acuerdo a las recompensas observadas. Se ejecutar una optimización del modelo tomando batches aleatorios de la ReplayMemory para mejorar la estimación de los Q-values impidiendo el overfitting durante las fases iniciales del entrenamiento, garantizando un mapeo eficiente de todos los estados posibles del entorno. Se guarda un checkpoint del modelo. Este punto es importante para retomar el entrenamiento. Se introduce en el modelo una imagen reciente del entorno al pre-procesado de imágenes y repetir desde el paso 3. Figura 1: Lógica del agente durante el entrenamiento del modelo en entornos de OpenAI Gym Para el testeo del agente, la lógica a seguir es la misma que durante el entrenamiento pero omitiendo los pasos representados por los recuadros verdes, adaptando la política de acciones a una con épsilon muy bajo para evitar decisiones caóticas. Resultados del entrenamiento Para contrastar la experiencia ganada por nuestro agente, hemos tomado, con una arquitectura modificada, la alternativa de entrenamiento realizado siguiendo la primera aproximación por Hvass-Labs. En su caso, su modelo fue entrenado hasta los 1,2e8 episodios, consiguiendo una muy buena actuación del agente. Para la segunda aproximación de input al modelo procedimos a guardar en logs para cada episodio durante el entrenamiento incluyendo la recompensa obtenida para cada episodio, la recompensa media de los últimos 30 episodios, la evolución de los Q-values estimados por el modelo (incluyendo el valor máximo de los Q-values, el valor mínimo de los Q-values, la media de la estimación de la acción, la desviación típica de los Q-values). De igual forma, se han almacenado todos los valores de hiperparámetros aplicables antes de comenzar la optimización de la red (tasa de aprendizaje ( learning rate, loss-limit permitido en cada optimización de la red, número máximo de épocas sobre las que optimizar el modelo y los porcentajes en la ReplayMemory de estados que han arrojado malas estimaciones de los Q-values). La tendencia de la media de los Q-values como función del número de episodios queda representada en la siguiente figura modo de comparativa en el entrenamiento de ambos modelos. Como se puede observar, la tendencia de la media de los Q-values es similar, aunque ligeramente más rápida haciendo uso de nuestro modelo tomando 4 frames consecutivos como entrada. Lo mismo ocurre con la evolución de la recompensa media con el tiempo de entrenamiento. El aprendizaje de ambos modelos es similar, y termina convergiendo hacia el final de nuestro entrenamiento. Figura 2: Evolución de la puntuación media de los últimos 30 episodios (Breakout-v0) Figura 3: Evolución del valor medio de los Q-values (Breakout-v0) Con respecto al SpaceInvaders-v0, en términos de puntuación, se ve cómo el agente aprende durante los primeros 2e4 episodios, pero a partir de ese momento el aprendizaje se estanca alrededor de los 300 puntos de media. En la siguiente figura se representa la evolución de la media de los Q-values como función del número de episodios. Puede verse una rápida evolución hasta los 8e3 episodios. Esta tendencia creciente se mantiene, pero de manera más paulatina a partir de esa fase del entrenamiento. Figura 4: Evolución de la puntuación media de los últimos 30 episodios (SpaceInvaders-v0) Figura 5: Evolución del valor medio de los Q-values (SpaceInvaders-v0) Durante el entrenamiento de este agente, nos encontramos con algunas dificultades en su manejo en este entorno. La evolución del porcentaje de estados en la ReplayMemory que arrojaba una incorrecta estimación de los Q-values no es todo lo buena que se esperaba. Al principio del entrenamiento llega a ser del 72 %, y apenas decrece conforme el agente explora el juego. Es cierto que la caída relativa respecto al máximo es drástica una vez la tasa de aprendizaje se estabiliza y la política de toma de acciones se hace menos estocástica, pero el hecho de determinar de manera incorrecta la acción a tomar en más del 50% de los casos no inspira mucha confianza en las capacidades de predicción del modelo entrenado. Tras haber dejado entrenando nuestro modelo en el entorno Breakout-v0 hasta casi los 4e4 episodios, consideramos suficientemente entrenada la red, por lo que se procedió a testear la capacidad del agente en Breakout-v0. Se lanzaron 200 episodios de prueba, con una epsilon = 0.05, dirigido a minimizar la aleatoriedad de las acciones a realizar. La máxima puntuación que ha conseguido nuestra IA durante la prueba es de 340 puntos, mientras que durante el entrenamiento llegó a conseguir 361.0 puntos en el episodio 6983. Estas puntuaciones tan elevadas se consiguen cuando nuestro agente es capaz de abrir un túnel en la capa de ladrillos, estrategia a la que debería recurrir con más frecuencia conforme fuera avanzando el entrenamiento. Podéis ver la mejor puntuación obtenida por el agente en el siguiente vídeo. Nuestro modelo en SpaceInvaders-v0 se entrenó durante más de 5e4 episodios, tras lo cual se decidió testear su capacidad. Al igual que con Breakout-v0, se lanzaron 200 episodios de prueba, con una epsilon = 0.05. La máxima puntuación que ha conseguido nuestra IA durante la prueba es de 715 puntos, mientras que durante el entrenamiento llegó a conseguir 1175.0 puntos en el episodio 15187. A continuación os ofrecemos una muestra de lo que es capaz de hacer la IA en este entorno. Conclusiones A lo largo de estos artículos, hemos demostrado cómo es posible entrenar a una IA o agente en el entorno Breakout-v0 generado por OpenAI Gym. Tras un largo tiempo de entrenamiento, haciendo uso de 4 frames consecutivos como entrada al modelo, se ha conseguido una actuación aceptable de la IA en el entorno de juego, consiguiéndose superar la puntuación media obtenida por otros modelos bien caracterizados. Hemos llegado a la conclusión de que es recomendable ejecutar el entrenamiento en una máquina con buena memoria y con GPU. Se ha decidido intentar entrenar un agente en el entorno SpaceInvaders-v0. Para este último entorno se ha reducido el tamaño de la arquitectura, siguiéndose la misma estrategia de input al modelo que en Breakout-v0. En este caso no se han obtenido malos resultados, pues el agente ha aprendido a conseguir una media de 310 puntos por episodio, pero la mejora con los episodios no ha sido tan notable como en el caso de Breakout-v0. Durante la realización de este breve proyecto, han quedado algunos puntos abiertos y se han observado algunas posibilidades de mejora. Quedan resumidas a continuación: Sería conveniente investigar arquitecturas más eficientes para acelerar la convergencia a la solución. Hemos observado que acumular un número excesivo de capas hace el entrenamiento considerablemente más lento a pesar de haber habilitado GPU en nuestra máquina. Se podrían disminuir número de capas, sobre todo densas al final de la arquitectura. Podría realizarse un cambio de enfoque en la arquitectura, haciendo uso de Double DQN (DDQN). Las modificaciones en la arquitectura y en el valor de los hiperparámetros para entrenar SpaceInvaders-v0 han sido mínimas, y no debemos olvidar que Space Invaders es un juego mucho más complejo que Breakout-v0, donde el número de eventos que te pueden quitar una vida es mucho mayor y además contamos con dos vidas menos. Se podrían explorar nuevos valores de hiperparámetros (i.e., disminuir el tamaño de batch, factor de descuento, punto de partida de la tasa de aprendizaje...) Se podría investigar qué efecto tendría modificar el decaimiento de epsilon, haciéndolo más lento. De la experiencia obtenida, para el caso de Breakout-v0, se ve conveniente mejorar la política de acciones, obviando en el entrenamiento la opción de que tome la acción 'FIRE' == 1. Podría ahorrar tiempo de entrenamiento y no desvirtuar tanto el aprendizaje. Para ambos entornos, durante el entrenamiento, se podría forzar un mínimo porcentaje de acciones a ejecutar por el agente. En el SpaceInvaders-v0, se podrían eliminar las acciones 'NOOP', 'RIGHTFIRE' y 'LEFTFIRE', con la intención de mejorar la exploración del entorno y acelerar el aprendizaje. Se deberían abordar técnicas de pre-procesado de imágenes más agresivas, dirigido a juego más complejos. Una alternativa pendiente de estudiar y que podría dar buenos resultados, además de acelerar el procesado de las imágenes (permitiendo incluso meter un mayor número de frames en un mismo estado) es el uso de Principal Component Analysis (PCA). La aplicación de esta alternativa permitiría disminuir drásticamente la dimensionalidad del input, haciendo posible disminuir el número de capas y el tamaño de cada capa de la red neuronal También puedes seguirnos en nuestras redes sociales: @Telefonica, @LUCA_D3, @ElevenPaths
27 de junio de 2018
AI & Data
Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos (Parte II)
En este artículo, el segundo de nuestro experimento de Aprendizaje Reforzado (RL) y Deep Learning en entornos generados por OpenAI, continuamos el post del blog de LUCA Deep Learning vs Atari: entrena tu IA para dominar videojuegos clásicos (Parte I), donde se ofrecen los resultados obtenidos tras el entrenamiento de un agente en los entornos Breakout-v0 y SpaceInvaders-v0. Para aquellos que no tuvieron oportunidad de ver la charla del pasado martes 29 de mayo, en este artículo podéis encontrar el enlace al webinar, donde mostramos el contenido resumido en este post. Introducción Como ya dejamos indicados en anteriores posts pertenecientes a las series que versan sobre Aprendizaje Reforzado ( RL), vimos que el RL es una área del Machine Learning capaz de dotar a un agente con los algoritmos que le permitan examinar y aprender del entorno en el cual se está ejecutando para conseguir un objetivo a cambio de una determinada recompensa. Estos algoritmos ayudan al agente a aprender mediante ensayo y error a maximizar la recompensa que puede obtener en función de las variables que observe en el juego sin necesidad de ninguna intervención por parte del ser humano. Algunos conceptos recurrentes de aprendizaje reforzado cuya definición es importante tener clara son: Entorno: se refiere al juego en el que el agente debe actuar y aprender a desenvolverse. Recompensa: incentivo que obtiene el agente tras realizar una determinada acción. en el caso del Breakout-v0, el agente conseguirá una recompensa positiva en el caso de que consiga devolver la pelota y destruir uno de los ladrillos. Estado: es generalmente un tensor obtenido del espacio de observaciones del entorno. En este caso, los estados consisten en un conjunto de imágenes pre-procesadas con la función de facilitar el entrenamiento del modelo. Acción es el conjunto posible de respuestas dentro del espacio de acciones que el agente puede realizar en función del estado o histórico de estados que ha observado. Por ejemplo, en el caso que nos ocupa sería moverse a izquierda, derecha o quedarse quieto en función de la dirección y velocidad de la pelota observada. Política de control (control policy) determina la elección de la acción que debe hacer el agente. Esta política de elección es determinada por el programador. Normalmente, se suele elegir una acción aleatoria al principio y, una vez el modelo está lo suficientemente entrenado, se toma la acción en función de qué valor máximo ha obtenido el modelo en el espacio de acciones. Figura 1: diagrama del proceso de aprendizaje de un agente durante el entrenamiento Inicialización del entrenamiento El algoritmo implementado busca maximizar la recompensa en cada episodio. El agente recoge imágenes del entorno del juego para ser inyectadas en una red neuronal, lo cual le permitirá estimar qué acción elegir dado el input al modelo. Tanto para construir la arquitectura de la red profunda como para hacer los cálculos pertinentes, haremos uso de la librería TensorFlow. También recomendamos leer los posts Deep Learning con Python: Introducción a TensorFlow (Parte I y Parte II) en el caso de que queráis una introducción al funcionamiento de esta librería. Los valores de las acciones estimadas por el modelo dada una cierta entrada, son generalmente referidos como Q-values. En el caso de que estos valores fueran conocidos de antemano, el agente sólo tendría que seleccionar la acción que maximiza el Q-value correspondiente para cada estado del juego observado. Sin embargo, estos Q-values deben ser explorados mediante un proceso de entrenamiento extenso, dado el ingente número posible de estados que se debe explorar. Política de toma de acciones En un principio, los valores de las acciones se inicializan en torno a cero, dejando al agente tomar acciones aleatorias en el juego. Cada vez que el agente obtiene una recompensa positiva (i.e., destruye un ladrillo o mata a un marciano), los pesos y bias de las capas de la arquitectura se actualizan, lo que permitirá que la estimación de los Q-values sea cada vez más refinada. Las técnicas de Aprendizaje Reforzado ( RL) suelen ser bastante inestable cuando se usa en una red neuronal profunda a la hora de aproximar el mapa de estados y acciones del entorno. Esto viene provocado por la no-linealidad de estas redes o por el hecho de que pequeñas actualizaciones de los Q-values junto con una política de control poco adecuada puede cambiar drásticamente la acción a realizar y, por ello, conducir a estados del entorno muy diferentes. Por todo esto, y con la intención de mitigar las inestabilidades que pudieran aparecer durante el entrenamiento, se suele recurrir a un muestreo aleatorio de un gran número de estados, acciones y recompensas para explorar la mayor cantidad de posibilidades dentro de la casuística existente y así evitar divergencias o estancamientos en el entrenamiento del modelo Q-function La misión del agente es interactuar con el emulador con la intención de aprender qué acción tomar dado un cierto estado o subconjunto de estados con la misión de maximizar la recompensa a obtener derivada de esa acción. Una función que devuelve la acción óptima a realizar dado un cierto estado queda definida como: Q(s,a) = reward(s,a) + γ · max(Q(s’,a’)) Esta función se conoce como la ecuación de Bellman. Esto indica que el valor de la función Q para un cierto estado s y una acción a representa la recompensa actual r para ese estado s y acción a más la recompensa esperada derivada de una acción nueva a’ y un estado posterior s’ corregida por un factor de descuento γ ∈ [0,1]. Este hiperparámetro de descuento nos permite decidir cómo de importantes son las recompensas futuras con respecto a la recompensa actual. Los valores cercanos a γ≃1 serán más óptimos para el juego Breakout, dado que los recompensas no se obtienen inmediatamente después de aplicar una acción, sino tras la ejecución de varias acciones posteriores una vez conocido si una acción concreta fue acertada. Función de pérdida y optimizador Dada la gran cantidad de frames por segundo a procesar y la elevada dimensionalidad de los estados a manejar, un mapeo directo de la causalidad estado-acción resulta impracticable. Por ello, nos vemos obligados a aproximar la función Q mediante el muestreo aleatorio de un elevado número de estados, recompensas y acciones recogidos por el agente. Generalmente la función de pérdida (loss-function) elegida y que se busca minimizar es el error cuadrático medio (Root Mean-Squared Error) entre los Q-values obtenidos como resultado de aplicar nuestro modelo y los Q-values esperados. sqrt(loss) = Q(s’, a’) - Q(s, a) = reward(s, a) + gamma · max(Q(s’, a’) - Q(s, a)) Para encontrar el mínimo de la función anterior se hace uso del algoritmo de optimización iterativo Gradient Descent. A través de este algoritmo se calculan los gradientes de la función de pérdida para cada peso y desplaza los mismos en la dirección que minimice la función. Sin embargo, encontrar los mínimos de una función no lineal puede resultar complicado, especialmente por la posibilidad de quedarnos estancados en un mínimo local lejos del mínimo global que se quiere conseguir o pasar múltiples iteraciones en una parte plana o cuasi plana de la función. Optimizar una red neuronal es una tarea complicada, altamente dependiente de la calidad y cantidad de los datos con los que se entrene el modelo. La complicación de optimizar la red también vendrá dada por la arquitectura de la misma, entendiendo que a mayor número de capas y mayor dimensionalidad de las mismas, se tendrá que abordar la optimización de un mayor número de pesos y biases. Preprocesado de los inputs Uno de los factores más importantes para garantizar un buen entrenamiento del modelo, dado los largos tiempos de computación requeridos, reside en el pre-procesado de la imagen y en la naturaleza del input a la red neuronal. Esto también afectará directamente a las rutinas a desarrollar de cara a la interacción con el entorno. Por lo general, es recomendable que la imagen generada por el entorno de OpenAI Gym sea procesada antes de ser incluida en el modelo, generalmente con la intención de reducir su dimensionalidad, eliminando aquella información de la imagen que no sea de utilidad a la hora de entrenar la red neuronal. Hay que hacer hincapié en que, por lo general, la información relativa al color apilada por OpenaAI Gym en los 3 canales de color que se nos facilitan no contiene información valiosa para el entrenamiento del modelo, por lo que será obviada antes de introducir los estados en el modelo. Las imágenes devueltas por el entorno OpenAI Gym son arrays de 210 x 160 píxeles agrupadas en 3 capas RGB. Esto hace que el uso de memoria sea elevado. Por ello, se hace imprescindible abordar un pre-procesado de las imágenes para disminuir la dimensión de los inputs, eliminando información innecesaria para entrenar el modelo y disminuir el uso de memoria. Las pruebas realizadas en este proyecto se han fundamentado en dos aproximaciones con respecto al procesado de imágenes: Como primera aproximación, se toman imágenes del entorno de juego y se procesan, convirtiéndose a escala de grises haciéndose un resizing, eliminando el fondo y usando un filtrado de imágenes sencillo para poder detectar movimiento. El estado resultante de ese procesado se compone de la última imagen del entorno de juego junto con una traza de movimiento de las trayectorias más recientes de los objetos. En la segunda alternativa de procesado, se ha optado por dar como input al modelo un conjunto de 4 capturas con la intención de que pueda aprender a detectar el movimiento. Esto es necesario, pues un único estado como input no nos aporta apenas información sobre la velocidad, dirección y aceleración de la pelota y la pala. Únicamente nos interesa el área de juego por donde se mueven la pelota y la pala y donde se encuentran los ladrillos; por ello, los bordes de las capturas no aportan información valiosa al modelo, por lo que esta zona se elimina. Además, a cada imagen se le disminuye la resolución a la mitad y se pasa a blanco y negro, pues los canales RGB de la imagen original tampoco aportan información al entrenamiento del modelo.
19 de junio de 2018
AI & Data
Deep Learning con Python: Introducción a TensorFlow (Parte II)
Escrito por Enrique Blanco (Investigador en CDO) y Fran Ramírez (Investigador de seguridad informática en Eleven Paths) Este artículo es el segundo de nuestra serie de introducción al Deep Learning con Python haciendo uso del framework TensorFlow. En el artículo anterior, Deep Learning con Python: Introducción a TensorFlow (Parte I), exploramos los fundamentos de esta librería y nos familiarizamos con los conceptos y el uso de las sesiones, grafos, así como de las variables y placeholders. En este post, y con la intención de ganar soltura en el uso de estos recursos, crearemos nuestras primeras neuronas y una primera red neuronal lo más sencilla posible dirigida a realizar regresiones lineales . Dado que nos vamos a poder despreocupar del aparato matemático, pues las operaciones necesarias para realizar una regresión son muy sencillas, podremos centrarnos en el manejo de los principales instrumentos de TensorFlow . Para empezar, crearemos una neurona que, de manera muy sencilla, ajusta una recta a un conjunto de datos, que en este caso estarán aleatoriamente generados por nosotros. La representación de esa neurona se puede generar haciendo uso de la herramienta de visualización TensorBoard, que abordaremos tras el primer Jupyter Notebook. Como pudimos ver en el anterior post, los pasos previos a realizar con TensorFlow para comenzar el entrenamiento de un modelo son: construir el grafo o definir la secuencia de operaciones a realizar con los datos, inicializar todas las variables, iniciar una sesión y comenzar el entrenamiento. Antes de iniciar la sesión, que ejecutaremos dando como entrada los datos pertinentes, tendremos que definir una función de coste y un optimizador sobre el que entrenaremos el modelo. En el primer notebook que se adjunta a continuación, vamos a crear nuestras primeras neuronas y vamos a aprender cómo ejecutar sesiones haciendo uso de los feed dictionaries. Una vez familiarizados con su uso, seguiremos con un ejemplo sencillo de red neuronal, veremos cómo definir una función de activación y haremos un sencillo ejemplo de regresión lineal donde deberemos definir una función de coste y un optimizador que se encargará de minimizarla. Visualizar el grafo de nuestro modelo puede ayudarnos a entender las operaciones que estamos realizando. Al final de la ejecución del cuaderno anterior, tendremos en /log/neural_network_tensorflow/ el fichero que podremos invocar con TensorBoard para visualizar nuestro grafo . Podemos abrir un terminal y ejecutar (¡sin olvidarnos de situarnos en el entorno Python donde está instalada la librería TensorFlow!) lo mostrado en la captura de abajo. Figura 1. Comando de ejecución de TensorBoard Donde el --logdir es el path definido /log/neural_network_tensorflow/ en el notebook. Tras ejecutar el comando de arriba, podemos clickar en http://$localhost:6006, lo que nos permitirá acceder a la información de nuestro modelo de forma gráfica. Figura 2. Ejemplo de grafo generado por TensorBoard tras la ejecución del anterior .ipynb Para más información sobre las posibilidades de visualización y debugging que ofrece TensorBoard, recomendamos leer la documentación disponible en su página web y en su repositorio de GitHub. En nuestro siguiente paso, abordaremos otro ejemplo de regresión lineal con más datos generados por nosotros mismos, con la diferencia de que el volumen del dataset va a ser mucho más grande. Dado el elevado número de variables que vamos a manejar, nos vemos obligados a dividir nuestro dataset en batches de un cierto tamaño, de tal forma que podamos entrenar nuestro modelo de manera más eficiente. Esta estrategia es necesaria, pues tomar todos los datos de una vez resultaría inmanejable. Para ello, iteraremos nuestro entrenamiento del modelo a lo largo de un número determinado de épocas o episodios sobre batches obtenidos de manera aleatoria, con la misión de ajustar lo mejor posible los parámetros de nuestra regresión. También se proporciona una breve introducción al uso de los estimadores de TensorFlow, los cuales simplifican el código al encapsular tanto el entrenamiento como la evaluación y la predicción, además de encargarse de la construcción del grafo y de la inicialización de variables. En la siguiente captura podéis observar el grafo de nuestro modelo, también generado para la primera mitad del cuaderno anterior. Os animamos a explorar con TensorBoard el grafo de la regresión lineal que acabamos de realizar. Sólo se debe modificar el comando de --logdir , apuntando al directorio /log/regresion_batches_tensorflow/. Figura 3. Grafo obtenido a partir de nuestro último modelo de regresión lineal https://gist.github.com/eblancoh/d39de37939e56903b3f2695c99dd19b7.js'%20defer%20onload='' defer onload=' En este post hemos aprendido a crear con TensorFlow nuestra primera neurona capaz de soportar operaciones básicas de multiplicación y suma. Nos hemos familiarizado con el uso de los feed dictionaries como método de ingestión inputs a una determinada operación una vez iniciada una sesión. Estos dos simples recursos nos han permitido, junto con la definición de una función de activación y un optimizador – en el caso de la regresión, destinado a minimizar el residuo entre los valores esperados y el valor predicho por el modelo – realizar un ajuste lineal a un reducido conjunto de datos aleatorios. Posteriormente, hemos extendido el tamaño de nuestro set de datos para hacer uso de una estrategia de muestreo de batches y se ha introducido el uso de los Estimators, una API de TensorFlow dirigida a simplificar la simplificación en scripts creados para este tipo de análisis. En el siguiente post nos centraremos en la clasificación de datasets extensos muy conocidos. Os animamos a continuar profundizando en el mundo del cálculo numérico con TensorFlow. Deep Learning con Python: Introducción a TensorFlow (Parte I) Deep Learning con Python: Introducción a TensorFlow (Parte II) Deep Learning con Python: Introducción a TensorFlow (Parte III)
24 de mayo de 2018