scieee AI-readable full text Open interactive document viewer

Reconocimiento automático de emociones en la música utilizando aprendizaje máquina

Parra Galindo, Ana

Abstract

La Inteligencia Artificial, una tecnología muy actual, está respondiendo a necesidades y avances, como sucede en el mundo de la medicina y de la automoción. Existen proyectos y estudios para lograr la detección del cáncer a través del procesamiento de imágenes con el Deep Learning o conseguir llegar a la conducción autónoma de un vehículo. Trasladándonos a algo más cotidiano, junto a estas capacidades, la Inteligencia Artificial está siendo usada por plataformas de música para recomendar música o hacer listas de reproducción de forma automática y personalizada. Con estas evidencias como respaldo, en el presente trabajo se quiere demostrar la facultad de un algoritmo de detectar algo tan subjetivo como son las emociones o sentimientos en la música. Requerirá de un entrenamiento de datos procesados y preparados, y un análisis de las distintas posibilidades de modelos para encontrar el más eficaz. Gracias a la forma que tienen de funcionar los algoritmos de Machine Learning, no serán necesarias miles y miles de canciones para que el algoritmo pueda clasificarlas y relacionarlas con el sentimiento que despierta en las personas,si no que basándose en características comunes que él aprende en el proceso de entrenamiento hará esa clasificación como si de cualquiera de nosotros se tratara, y sabremos que emoción está asociada a un tipo de música. Con el amplio abanico de posibilidades que presentan los modelos de Machine Learning y Deep Learning, se tomarán las Redes Neuronales como centro del trabajo. Serán necesarias varias combinaciones de las mismas y pruebas hasta dar con un modelo óptimo.

Full text

1 Equation Chapter 1 Section 1 Trabajo Fin de Grado Ingeniería de Tecnologías de Telecomunicación Reconocimiento automático de emociones en la música utilizando aprendizaje máquina Autor: Ana Parra Galindo Tutor: Francisco José Simois Tirado Dpto. Teoría de la Señal y Comunicaciones Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2021 2 3 Trabajo Fin de Grado Ingeniería de Tecnologías de Telecomunicación Reconocimiento automático de emociones en la música utilizando aprendizaje máquina Autor: Ana Parra Galindo Tutor: Francisco José Simois Tirado Profesor Contratado Doctor Dpto. de Teoría de la Señal y Comunicaciones Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2021 4 5 Trabajo Fin de Grado: Reconocimiento automático de emociones en la música utilizando aprendizaje máquina Autor: Ana Parra Galindo Tutor: Francisco José Simois Tirado El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocal/es: Secretario: Acuerdan otorgarle la calificación de: El Secretario del Tribunal Sevilla, 2021 6 7 A mi familia y amigos A mi tutor 8 9 Resumen La Inteligencia Artificial, una tecnología muy actual, está respondiendo a necesidades y avances, como sucede en el mundo de la medicina y de la automoción. Existen proyectos y estudios para lograr la detección del cáncer a través del procesamiento de imágenes con el Deep Learning o conseguir llegar a la conducción autónoma de un vehículo. Trasladándonos a algo más cotidiano, junto a estas capacidades, la Inteligencia Artificial está siendo usada por plataformas de música para recomendar música o hacer listas de reproducción de forma automática y personalizada. Con estas evidencias como respaldo, en el presente trabajo se quiere demostrar la facultad de un algoritmo de detectar algo tan subjetivo como son las emociones o sentimientos en la música. Requerirá de un entrenamiento de datos procesados y preparados, y un análisis de las distintas posibilidades de modelos para encontrar el más eficaz. Gracias a la forma que tienen de funcionar los algoritmos de Machine Learning, no serán necesarias miles y miles de canciones para que el algoritmo pueda clasificarlas y relacionarlas con el sentimiento que despierta en las personas, si no que basándose en características comunes que él aprende en el proceso de entrenamiento hará esa clasificación como si de cualquiera de nosotros se tratara, y sabremos que emoción está asociada a un tipo de música. Con el amplio abanico de posibilidades que presentan los modelos de Machine Learning y Deep Learning, se tomarán las Redes Neuronales como centro del trabajo. Serán necesarias varias combinaciones de las mismas y pruebas hasta dar con un modelo óptimo. 16 17 ÍNDICE DE FIGURAS Figura 2-1. Cronología del Machine Learning desde su inicio hasta finales del siglo XX 22 Figura 2-2. Cronología del Machine Learning sigo XXI 23 Figura 2-3. Cronología del Machine Learning sigo XXI más actual. 24 Figura 2-4. Similitud entre una neurona biológica y un perceptrón 27 Figura 2-5. Unidad básica de neurona artificial 28 Figura 2-6. Arquitectura de un perceptrón con dos entradas y tres salidas 28 Figura 3-1. “Modelo circumplejo del afecto” con dimensiones de excitación y valencia, adaptado por Russell (1980) 35 Figura 3-2. Sobre un mapa autoorganizado de las etiquetas de estado de ánimo en el espacio semántico se hacen cuatro grupos asociados a cada estado de ánimo 38 Figura 3-3. Dendrograma de las 20 etiquetas de estado de ánimo más utilizadas, destacando la ramificación correspondiente a la excitación y valencia, mostrando racimos muy relacionados con las emociones básicas 39 Figura 4-1. Función de activación Lineal Rectificada 45 Figura 4-2. Función de activación Logística o Sigmoide 45 Figura 4-3. Función de activación Tangente Hiperbólica 45 Figura 4-4. Función de activación Softmax 46 Figura 5-1. Matriz confusión para Sigmoide con 128 neuronas en 1 capa 57 Figura 5-2. Matriz confusión para Sigmoide con 512 neuronas en 1 capa 57 Figura 5-3. Matriz confusión para Relu con 512 neuronas en 2 capas 58 Figura 5-4. Matriz confusión para Tanh con 512 neuronas en 1 capa 59 18 19 1 INTRODUCCIÓN 1.1 Motivación La música y los sentimientos guardan una estrecha relación, solo hay que escuchar una canción que nos gusta mucho para que nos despierte un sentimiento e incluso puede devolvernos un recuerdo. Un ejemplo de esta relación podría verse en la pandemia que ha sacudido el mundo en el año 2020, y que ha sacado altavoces a los balcones para animar y transmitir alegría gracias a la música. Esta relación entre música y sentimiento, sumado a la capacidad de un algoritmo de detectar emociones en un fragmento de canción, permiten a muchas plataformas agrupar música o recomendar la próxima canción relacionada con la última reproducida. Como ejemplo de esto último se pueden poner a Spotify o Youtube, por ser las más usadas. Spotify hace listas de reproducción por género, el cual a su vez tiene relación con los sentimientos, listas por estado de ánimo o para un tipo de tarea, como conducir, leer, trabajar o limpiar. En el ejemplo para Youtube, tras poner a reproducir una canción ya tiene una recomendación relacionada con el estilo o el artista para cuando termine y proponértela. Tanto la música como las emociones son dos imprescindibles en nuestra vida y se abre hueco en ellas la Inteligencia Artificial como en tantos otros campos. La capacidad que tienen los algoritmos de aprender gracias a las características sacadas de audios e interpretar emociones evocadas por una canción como si de un humano se tratara, podrá verse representado en este trabajo. 1.2 Objetivos y enfoque La elaboración de este trabajo tiene el fin de encontrar un modelo de Red Neuronal capaz de clasificar por emociones un conjunto de canciones. El comienzo será la elaboración de una base de datos, de la cual se extraerán las características usadas para entrenar y probar una red. Cada característica es de un tipo, pueden ser de tipo numérico o cadena de texto, por ello llevarán su correspondiente análisis y preparación, no todos los tipos de datos son válidos. Es importante partir de una buena base de datos, bastante completa, con canciones que presenten matices muy concretos de ese estado de ánimo, pero que también haya algunos que sean un poco más parecidos a los de sus vecinos, con el fin de ajustar aún más el algoritmo. Para el entrenamiento esto puede reducir la incertidumbre a la hora de identificar y clasificar. El proceso de modelado puede ser algo más tedioso. Como todo estudio, es imprescindible realizar pruebas y ajustes de todos los parámetros e hiperparámetros de los que consta el modelo. Aquí el modelo estará centrado en las redes neuronales, dónde se hará especial énfasis en el estudio del número de capas y en las neuronas por capa. De entre las opciones de diferentes estructuras de redes neuronales se seleccionará el modelo más óptimo, se Me enseñaron que el camino del progreso no era rápido ni fácil. - Marie Curie - 20 mostrarán los resultados de las diferentes pruebas y se evaluarán los datos arrojados cómo conclusión del proceso. 1.3 Organización de la memoria El presente trabajo contará con la estructura mostrada a continuación. El primer capítulo, en el que nos encontramos, cuenta con una pequeña introducción que refleja el propósito y proceso del trabajo. El segundo capítulo estará dedicado a la Inteligencia Artificial, el Machine Learning y el Deep Learning. Se explicará cada uno de estos términos y cómo se desarrolla un posible modelo de Machine Learning. A continuación, el tercer capítulo, contendrá la exposición de la relación existente entre la música y las emociones desde diferentes perspectivas. En el cuarto capítulo aparecerá la parte práctica, dónde el propósito es reconocer las emociones en la selección de canciones que forman la base de datos del presente trabajo. El quinto capítulo albergará los resultados del anterior y nos llevará a unas conclusiones finales sobre la capacidad de un algoritmo de relacionar música y emociones, que aparecerá en el sexto y último capítulo. Todo ello se verá acompañado de la bibliografía en la que se ha apoyado la documentación, una lista de figuras y otra de tablas, mostradas a lo largo de la memoria, y un Anexo de apoyo. 21 2 TRES CONCEPTOS PARA UNA IDEA DE FUTURO 2.1 Inteligencia Artificial, Aprendizaje Máquina y Aprendizaje Profundo Casi a diario, y de forma indirecta, las personas hacen uso de la Inteligencia Artificial. Esta está presente en las redes sociales, en los buscadores, en los anuncios que nos muestran, en los asistentes de voz e incluso en los correos, filtrando los mensajes de spam. Acciones cotidianas, que han sido posibles o mejoradas gracias a la Inteligencia Artificial [1]. Estos algoritmos están presentes incluso en la sanidad. Actualmente son usados para asistentes virtuales permitiendo el incremento de la interacción médico-paciente, los chatbots como apoyo seguro de información médica o dispositivos de monitorización de asistencia sanitaria [2]. En el mundo de la música también está presente la Inteligencia Artificial. Su practicidad es innegable a la hora de recomendar canciones en plataformas como YouTube, asociándolas por género o artista. También en la creación, dentro de la plataforma de Spotify, de playlist personalizadas para cada usuario según las reproducciones más frecuentes, llegando a agrupar canciones por idiomas y estado de ánimo, además de por géneros. Todos estos avances se han dado gracias a la Inteligencia Artificial, unida al Machine Learning y al Deep Learning. A continuación, se expondrá que son cada uno de estos aprendizajes que nos acompañaran de aquí en adelante en nuestra sociedad, debido a que son el futuro; y qué las hace diferentes entre sí. Se mostrará que tipos existen y cómo se llega a un modelo que pueda actuar por si sólo sin necesidad de intervención humana. Aparecerán también las redes neuronales, las protagonistas del presente trabajo. 2.1.1 ¿Qué es la Inteligencia Artificial o IA? La Inteligencia Artificial es la simulación del comportamiento humano. Los algoritmos usados analizan el entorno, estudian cómo se comporta y generan una respuesta. Su aplicación y uso, como se ha comentado anteriormente, abarca casi todas las áreas dónde está presente la acción humana [3]. El concepto de Inteligencia Artificial se nombró por primera vez en 1956 en la Conferencia de Dartmouth, pero anteriormente ya se habían dado pinceladas sobre la misma. Descartes, en 1637, contempló la posibilidad de robots que pensasen, o Raimundo Lulio, entre los siglos XIII y XIV, escribió una obra dónde diseñaba una máquina lógica teórica para probar la verdad o falsedad de las afirmaciones o de los postulados [4]. A continuación se muestran los hitos más destacados de la historia de la Inteligencia Artificial, incluida su etapa más fría [5]: Algunas personas denominan a esta tecnología inteligencia artificial, cuando en realidad lo que va a permitir es que aumente la nuestra propia. - Gin Rometty, Presidenta y Directora ejecutiva de IBM- 22 Figura 2-1. Cronología del Machine Learning desde su inicio hasta finales del siglo XX [5]. 1637 •Descartes plantea la posibilidad de robots que piensan. 1950 •Edad de oro de la IA. •Turing publica su test en "Computer machine and Intelligence". 1956 •Surge el término "Inteligencia artificial" en la Conferencia de Dartmouth. 1966 •ELIZA, primer chatbot que implementa lenguaje natural. 1970 •El invierno de la IA. Las expectativas de la IA no se habían cumplido. 1973 •Nace el primer lenguaje de programación textual para robots. 1979 •El programa BKG 9.8 gana al campeón mundial de backgammon. 1980 •Primera furgoneta guiada por visión artificial. •La investigación vuelve a avanzar. Los beneficios económicos de la IA avivan su investigación. 1988 •La IA se aplica a la traducción entre inglés y francés. 1994 •Dos vehículos autónomos recorren 1000km de autopista en París. 1996 •Nacen los agentes inteligentes que perciben el entorno. 1997 •La IA Deep Blue gana a Kaspárov al ajedrez 23 Con la entrada del nuevo siglo, el sigo XXI, los avances se daban de forma más consecutiva en el tiempo, reflejo del auge de la tecnología y de los datos. La entrada en el mundo del Big Data contribuyó al crecimiento de la IA, debido a que los datos son su alimento. El Big Data hace referencia a un conjunto de datos que se caracteriza por su volumen, su velocidad y su variedad. Actualmente todo dispositivo conectado a la red genera datos útiles, por lo que hay un gran volumen; su renovación es rápida, todo en la red se desarrolla en un instante; y son variados, desde números hasta imágenes, pasando por vídeos o textos [6]. Figura 2-2. Cronología del Machine Learning sigo XXI [5]. Desde el 2018 hasta nuestros días han seguido sucediéndose acontecimientos gracias al Machine Learning, de hecho son tantos que se pisan unos a otros y cuesta destacarlos. 2008 •Google lanza la primera app que reconoce la voz 2011 •Watson gana a los humanos al concurso Jeopardy! Todo se acelera. 2012 •El machine learning aprende a identificar gatos. 2013 •Boston Dynamics construye a Atlas, robot bípedo de rescate. 2014 •El programa Eugene Goostman pasa el test de Turing. 2015 •Las máquinas 'ven' mejor que los humanos. 2016 •AlphaGo gana al campeón mundial de GO. •El MIT lanza el primer taxi autónomo en Singapur. 2017 •El programa Libratus vence al póker contra cuatro personas. •DeepMind se lleva lo aprendido en un juego a otro. •La ginoide Sophia se convierte en ciudadana Saudí. 2018 •En Arizona se puede llamar a un taxi de Waymo vía app. •Atlas aprende a hacer parkour. •Alpha Zero aprende por si misma a jugar al ajedrez. 24 Figura 2-3. Cronología del Machine Learning sigo XXI más actual. 2.1.2 ¿Qué es el Machine Learning o Aprendizaje Automático? Dentro de la Inteligencia Artificial existe un subconjunto denominado Machine Learning. Esta técnica de análisis de datos implementa métodos de cálculo en los algoritmos para que puedan aprender directamente de las entradas de datos, mejorando el rendimiento de forma adaptativa. No hacen uso de una ecuación predeterminada como modelo, encuentran patrones que les ayuda a tomar decisiones y hacer predicciones [11]. El algoritmo aprende a base de ejemplos, denominados conjunto de entrenamiento. Cada ejemplo es una instancia o muestra, de entrenamiento. Con cada nueva instancia el algoritmo se modifica y se ajusta, para predecir futuros escenarios y tomar decisiones. La medida de rendimiento es la precisión [12]. Tom Mitchell (1997) decía que un programa informático aprende de la experiencia E con respecto a una tarea T y una medida de rendimiento P, si su rendimiento en T, medido por P, mejora con la experiencia E. La eficacia guarda relación con la cantidad de información recibida. Cuantos más datos diferentes reciba durante el entrenamiento, mayor complejidad tendrá el cálculo de la salida y más preciso será el proceso de elección. Para llegar a un algoritmo eficaz, se necesita un mínimo de datos con relevancia, que dependerá de la aplicación [12]. De forma generalizada, el aprendizaje automático es útil para aquellos problemas dónde la solución requerida necesite de muchas reglas o criterios, o aquellos casos que sean muy complejos y resulte costoso dar con la solución. También pueden ser interesantes en los casos con una gran cantidad de datos para trabajar, o dónde además, se actualicen con rapidez. 2.1.3 ¿Qué es el Deep Learning o Aprendizaje Profundo? El Deep Learning es una forma especializada de aprendizaje automático. Es una técnica de Machine Learning que aumenta la precisión, consiguiendo resultados que no se habían visto antes, incluso superando en ocasiones el rendimiento humano. El modelo se entrena con grandes cantidades de datos etiquetados, que pueden ser imágenes, texto o sonido. El propio modelo extrae las características directamente de estos datos, no necesita una selección previa. Esta gran cantidad de datos, junto con una alta potencia de cálculo, son los requisitos básicos para poder hacer uso del Deep Learning. El Deep Learning o Aprendizaje Profundo también es conocido como redes neuronales profundas, debido al alto uso de arquitecturas de redes neuronales en los modelos, de las que se hablará más adelante en este trabajo [13]. 2019 •La compañía OpenAI consiguió una mano robot capaz de resolver el cubo de Rubik [7]. •Desde DeepMind desarrollaron agentes que tomaban decisiones conociendo las consecuencias del futuro [7]. 2020 •Deepfakes: el MIT publicó una falsificación del presidente Richard Nixon. Por los Deepfakes, en este año, se aprobó en el estado de California una ley para criminalizarlos [8]. •Waymo, firma de taxis autónomos, hizo primer ensayo para el transporte de mercancías [9]. 2021 •Digital twins. Predictor de posible fallo en la cadena de suministros internacional con el objetivo de minimizar daños en la crisis actual y proponer soluciones [10]. 25 2.1.4 Diferencias entre Machine Learning y Deep Learning Cómo se ha comentado, el Aprendizaje Profundo es una rama del Aprendizaje Automático y sus modelos son mucho más superiores en los escenarios dónde podría hacerse uso de ambos. Las principales diferencias entre ambos aprendizajes se muestran en la siguiente tabla [14]. Tabla 2-1. Comparativa entre el Machine Learning y el Deep Learning [14] MACHINE LEARNING DEEP LEARNING Tiempo de ejecución (entrenamiento + prueba) Modelos más simples, menos tiempo. Modelos más complejos, más tiempo. Tamaño de datos En función de la aplicación. Gran tamaño. Extracción de características Manual, previo al modelo. Directamente de los datos. Número de parámetros Menor número de parámetros aprendibles e hiperparámetros. Mayor número de parámetros aprendibles e hiperparámetros. Relación entre rendimiento y cantidad de datos Directamente proporcional hasta un punto, dónde empieza a ser inversamente proporcional. Directamente proporcional. A más datos, más robusto es el modelo. Capacidad de procesamiento (GPU) Bajo rendimiento. Alto rendimiento. Capacidad de aprendizaje Menor ajuste y sobreajuste. Mayor ajuste y sobreajuste. Interpretabilidad Alta. Baja. 2.2 Tipos de Sistemas de Aprendizaje Automático Los criterios que se siguen para esta clasificación son la supervisión humana, la capacidad de aprender sobre la marcha de forma incremental, o si presentan la capacidad de detectar patrones en los datos de entrenamiento o solo aprenden comparando con datos conocidos. A continuación, se muestran las diferencias y las características de las tres clasificaciones de aprendizaje que presentan los algoritmos [15]. 2.2.1 Aprendizaje supervisado, no supervisado, semisupervisado o por refuerzo o Aprendizaje supervisado: dentro de sus capacidades se encuentran la de realizar una clasificación o predecir un valor. Esta última también es conocida como regresión. Lo interesante es que los algoritmos de clasificación pueden usarse en regresión y viceversa. Los datos de entrenamiento que utiliza llevan etiquetas o clases identificativas. Además de esto, les acompañan a los ejemplos predictores o características. Algoritmos:  K-vecinos cercanos.  Regresión lineal. 32 33 3 LA MÚSICA Y LAS EMOCIONES 3.1 Visión biológica y fisiológica Las reacciones que consigue la escucha de una melodía se traducen en alteraciones fisiológicas y biológicas. Alteraciones hormonales que actúan sobre el sistema nervioso, alteraciones del ritmo cardiaco… Y tras la escucha entran en juego el pensamiento y las emociones. Para estudiar la relación de la música con la conducta humana existe una rama de la Psicología, conocida como Psicología de la Música, que intenta comprender el efecto que causa la música sobre las personas. El estudio se centra en dos dimensiones, la dimensión psicofisiológica y la dimensión psicobiológica. Desde el punto de vista psicofisiológico, la música estimula tres partes del cerebro, la zona bulbar, el diencéfalo y el nivel cortical. Cada una de las partes da una respuesta diferente. La zona bulbar, centro de las reacciones físicas, guarda relación con el ritmo. El diencéfalo origina las emociones y los sentimientos, contenido básico de la conciencia y de la actividad psíquica, tras la recepción de la afectividad de la música. Por último, el nivel cortical, centro de la actividad intelectual y el pensamiento, responde con estímulos ante la armonía. Desde el punto de vista de la psicobiología, la relación existente entre la música y el pensamiento musical viene determinada por la funcionalidad de las estructuras cerebrales. El cerebro involucra no solo el pensamiento, localizado en la zona cortical, si no también involucra la afectividad, localizada en otra parte diferente del cerebro, en el diencéfalo y en el lóbulo temporal. Esta última, es la característica básica del estado de conciencia [28]. Por ello podemos hablar de dos partes o procesos dentro del cerebro, la parte objetiva y la parte afectiva. La primera parte es llamada “Unidad de valoración objetiva” y es la llevada a cabo por las funciones del pensamiento. La segunda, es conocida por “Unidad de valoración afectiva”, es el resultado de la respuesta emocional del sistema límbico, el tálamo, el hipotálamo y el lóbulo temporal. La fusión de ambos da como resultado la conciencia. Todo este estudio tiene presente que la cultura, el entorno y la inserción en el medio social de cada persona juegan un papel importante en las reacciones de dos individuos ante la misma melodía. Esto tiene un reflejo en lo biológico, no existen dos cerebros iguales, no existen dos redes de neuronas iguales. Cada persona desde que nace y según los estímulos que recibe a lo largo de su vida, va tejiendo las conexiones de sus neuronas de una forma distinta a las de otra persona [28]. 3.2 Relación bidireccional La relación de las emociones o estados de ánimo, y la música, es bidireccional. La música y los sonidos provocan en nosotros una respuesta según lo escuchado. Y según nuestro estado de ánimo o momento en el que nos encontremos, elegimos un tipo de música u otro. Para ejemplificar lo comentado se puede observar el uso de una banda sonora de tensión o suspense para Sin sentimiento, todo lo que hagas equivaldrá a nada. - Billie Holiday - 34 provocar miedo en el espectador de una película de terror, o la necesidad de escuchar música rítmica que te invite a bailar cuando estás en una fiesta o celebración. En Noruega se hizo un estudio para poner de manifiesto la relación bidireccional comentada. Para ello se valieron de la subjetividad de un grupo de jóvenes desconocidos por el investigador, se buscaba la mayor heterogeneidad posible, y se siguieron las siguientes fases [29]. Fase1: Un primer grupo de jóvenes iban a establecer la relación entre estado de ánimo-música. Se les mostraba a cada uno de ellos ocho emociones, las mismas para todos, y a cada emoción le tenían que asignar una canción que le hubiese suscitado esa emoción. De esta primera fase se obtiene una primera matriz de datos subjetivos, dónde aparecen ocho conjuntos de canciones asociado cada conjunto a una emoción. La selección de las 8 emociones se hizo de acuerdo al diferencial semántico, y eran felicidad, relajante, animada, romántica, nostálgica, bailable, triste y tensión. Fase 2: Se analizan los rasgos musicales de las canciones de la fase anterior. Se hace una selección de canciones típicas, ocho en total, una por emoción, y se obtiene una selección, que será la mostrada al grupo de validación. La selección de canciones típicas es la selección de las canciones más repetidas dentro de cada uno de los ocho grupos. Fase 3: Un segundo grupo de jóvenes, diferente al primer grupo, iba a establecer la relación contraria, músicaestado de ánimo. Su función era puntuar del 1 al 10 si esa canción despertaba en ellos la emoción con la que se había relacionado esa canción. De esta fase se obtiene otra matriz de datos subjetivos. A la matriz obtenida en la fase 3, se le suma una tercera matriz de datos objetivos. Estos datos son los rasgos musicales de cada una de las canciones en examen, utilizando los más discriminatorios. Tras el análisis de los datos recogidos durante el estudio desde la Universidad de Noriega llegaron a las siguientes conclusiones: “1) Existe una relación estadísticamente significativa entre la asociación de sentimientos a las canciones propuestas, primero “motu proprio”, y después validada externamente por otros sujetos entrevistados. 2) Existe dimensionalidad en la estructura de valoración de las canciones, que corresponde con las propuestas de dimensionalidad en la orientación psicológica del diferencial semántico. 3) Existe una relación empírica estadísticamente significativa entre las cualidades musicales de las canciones y su efecto psicológico tal y como lo reconocen los entrevistados." [29]. 3.3 Tipos de emociones y representación en la psicología Las emociones que se asocian a la música pueden ser de forma general de dos tipos, emociones inducidas o emociones percibidas, entendidas también como emociones en la música o emociones de la música. La emoción inducida es la emoción buscada por el creador, el sentimiento que llevó a crear o componer esa canción u obra. Es una emoción más objetiva, pero aun así está sujeta a las circunstancias que rodean a la canción, y puede fluctuar con el tiempo. Un ejemplo de ello, un autor que tras muchas escuchas y ensayos, cansado, deja de percibir las emociones iniciales y le cambia la emoción a la canción. La emoción percibida es la emoción experimentada por el oyente, el estado de ánimo que surge de la escucha de la canción o de la obra. Aunque esta emoción sea más subjetiva, las personas coinciden más en la emoción percibida que en la inducida. Estudios psicológicos dieron lugar a dos posibles representaciones de las emociones. Estas serían la representación categórica o la representación dimensional [30]. La representación categórica divide las emociones en grupos o clústeres. Cada uno de ellos será identificado por un grupo de adjetivos. Uno de los modelos más recientes de representación categórica y que pone de manifiesto la teoría básica de la emoción, es el modelo de Juslin y Sloboda (2001) [31]. 35 Tabla 3-1. Evaluaciones clave para emociones básicas adaptadas de Sloboda (2001) [30] Emoción Coyuntura del plan Tema central de las relaciones Felicidad Subobjetivos alcanzados Avanzar razonablemente hacia un objetivo Ira Plan activo frustrado Una ofensa denigrante contra mí y los míos Tristeza Fracaso del plan principal o pérdida del objetivo activo Habiendo sufrido una pérdida irremediable Miedo Objetivo de autoconservación amenazado o conflicto de objetivos Enfrentarse a un peligro físico inmediato, concreto o abrumador Disgusto Golpe de efecto violado Tomar o estar cerca de algo desagradable Todo conjunto de emociones depende de cómo se definan las emociones, pero existe un consenso alrededor del modelo expuesto por Juslin y Sloboda. Las emociones básicas deben ser universales y son el conjunto más simple de emociones que pueden dar lugar a todas las demás, buscándole una similitud con los colores, las emociones básicas vendrían a ser los colores primarios. La representación dimensional implica la distribución de las emociones a lo largo de dos ejes, un eje representa la excitación de la emoción (si la emoción es más activa o menos activa), y el otro eje representa la valencia (si la emoción es más positiva o más negativa) [30]. Figura 3-1. “Modelo circumplejo del afecto” con dimensiones de excitación y valencia, adaptado por Russell (1980) [30]. 3.4 Elección de emociones En el presente trabajo se van a detectar cuatro emociones básicas en la música. Estas cuatro emociones son 36 Alegría, Tristeza, Enfado y Relajado. La elección de solo estas cuatro emociones se apoya en el estudio y las conclusiones alcanzadas por Cyril Laurier en su tesis [30]. Es una referencia más avanzada resumida en este apartado para apoyar la elección de estas emociones. Cyril Laurier ha querido validar si el etiquetado con estas cuatro emociones de canciones de una plataforma, cuadraba con los expertos. Los datos de los que partieron fueron las etiquetas sociales más repetidas. La matriz obtenida tenía una gran dimensionalidad, y para reducirla y mostrarla en un espacio de estado semántico, aplicaron Análisis Semántico Latente (LSA) con Descomposición del Valor Singular (SVD). [El LSA es, en efecto, una técnica habitual para mapear palabras y documentos en un "espacio conceptual", mapeando la matriz de términos del documento (o, en nuestro caso, la matriz de etiquetas de las pistas) en un espacio conceptual reducido, que denominamos "espacio semántico del humor".] Representación categórica. El espacio semántico del estado de ánimo pasó a compararse con las representaciones propuestas por la literatura, con la representación categórica y con la representación de excitación/valencia. Haciendo uso de un método de agrupación no supervisado a través del algoritmo de maximización de expectativas (EM) de Dempster et al. (1977), lograron una representación categórica del espacio semántico del que partió el estudio del departamento de la Universidad. [El algoritmo EM no requiere una fase de entrenamiento. Consiste en un algoritmo iterativo, cuyo objetivo es encontrar los parámetros de la distribución de probabilidad que tiene la máxima verosimilitud de sus atributos. El primer paso es la Inicialización, seguida de la Expectativa y la Maximización, ambas repetidas iterativamente hasta la convergencia.] Dicha representación categórica se denominó representación Folksonómica. Los cuatro clúster que surgieron son muy similares a la teoría básica de la emoción de Juslin y Sloboda (2001), mostrada en la Tabla 3-1 de la sección anterior; y a los cuatro cuadrantes de excitación-valencia de Russell, también mostrado en la Figura 3-1 de la sección anterior. Por tanto parece que no es muy desatinado seleccionar cuatro emociones como base de todas las demás. No les bastaba con la similitud anterior, y calcularon la similitud Intra-clúster e Inter-Clúster de la representación folksonómica, junto con las de Hevner y MIREX, y las compararon. Los clúster de Hevner y de MREX aparecen en las siguientes Tablas: Tabla 3-2. Adjetivos de humor emparejados en el modelo de Hevner [30] Clusters Hevner Mood Adjectives Cluster 1 Spiritual, sacred Cluster 2 Pathetic, sad, mournful, tragic, melanholy, depressing, gloomy, heavy, dark Cluster 3 Dreamy, tender, sentimental, longing, yearning, plaintive Cluster 4 Lyrical, serene, tranquil, quiet, soothing Cluster 5 Humorus, whimsical, playful, delicate, light Cluster 6 Merry, joyous, gay, cheerful, bright Cluster 7 Restless, passionate, exciting Cluster 8 Martial, majestic 37 Tabla 3-3. Medios de similitud intra-clúster para cada taxonomía de estados de ánimo [30] Clusters MIREX Mood Adjectives Cluster 1 Passionate, rousing, confident, boisterous, rowdy Cluster 2 Rollicking, cheerful, fun, sweet, amiable, good natured Cluster 3 Literate, poignant, wistful, bittersweet, autumnal, brooding Cluster 4 Humorous, silly, campy, quirky, whimsical, witty, wry Los resultados de las medidas de similitud entre los valores de un mismo clúster fueron los siguientes para cada una de las representaciones: Tabla 3-4. Medios de similitud intra-clúster para cada taxonomía de estados de ánimo [30]. Mood Taxonomy Intra-cluster similarity Hevner MIREX Folksonomy 0.55 0.73 0.82 Los resultados de las medidas de similitud entre diferentes clústeres fueron los siguientes para cada una de las representaciones: Tabla 3-5. Medias de disimilitud entre inter-clúster para cada taxonomía del estado de ánimo y su línea de base aleatoria para la comparación [30]. Mood Taxonomy Inter-cluster dissimilarity Hevner MIREX Folksonomy 0.70 0.56 0.9 Como puede observarse, la representación de MIREX es mejor en la similitud dentro del mismo clúster, sin embargo, no es tan clara la diferenciación entre unos y otros. En cuanto a la representación de Hevner, tiene mejor separación entre clúster. La representación Folksonómica arroja buenos resultados porque se ha extraído del propio espacio semántico de estudio. Representación dimensional. Para visualizar el espacio semántico del estado de ánimo en dos dimensiones, y poderlo comparar con la representación de Russel, hacen uso del algoritmo del mapa autoorganizado (SOM). [Esta técnica de transformación de datos reduce la dimensión de un espacio de entrada mediante el uso de redes neuronales autoorganizadas. Una red neuronal artificial se entrena mediante aprendizaje no supervisado para construir una representación de baja dimensión de las muestras del espacio de entrada (normalmente entre 1 y 3 dimensiones para permitir una representación visual).] 38 El resultado aparece en la Figura: Figura 3-2. Sobre un mapa autoorganizado de las etiquetas de estado de ánimo en el espacio semántico se hacen cuatro grupos asociados a cada estado de ánimo [30]. En la figura se pueden apreciar cuatro grupos más o menos claros, relacionados con las cuatro emociones básicas. Es similar a la representación de Russell. Para completar la búsqueda de un modelo válido con cuatro emociones básicas, desde la universidad se buscó una representación jerárquica, también relacionada con la valencia y la excitación de las emociones. Experimentaron con clustering jerárquico aglomerativo común con enlace completo para lograr visualizar las emociones en un diagrama de árbol. [En el clustering jerárquico los puntos de datos no se asignan a un clúster en un solo paso. Por el contrario, los datos se dividen agregando o dividiendo conjuntos de muestras. En el método aglomerativo, más comúnmente utilizado, las muestras se agrupan por series de fusiones, obteniendo una representación jerárquica en forma de árbol, también llamada dendrograma. El enlace simple, o vecinos más cercanos, define la distancia entre clústeres como la distancia entre el par de muestras más cercano. La técnica de vinculación completa, también llamada vecino más lejano, es lo contrario de la vinculación simple. Las distancias de los clústeres se definen como la distancia entre el par de objetos más distante de cada grupo.] La solución del proceso de clustering nos lleva hasta el dendrograma mostrado en la Figura: 39 Figura 3-3. Dendrograma de las 20 etiquetas de estado de ánimo más utilizadas, destacando la ramificación correspondiente a la excitación y valencia, mostrando racimos muy relacionados con las emociones básicas [30]. La principal separación de las ramas es gracias a la excitación, separando calma y tristeza, de enfado y felicidad. Tras varias revisiones, puede darse como aceptado el uso de solo cuatro emociones, las más usadas en una red social. 40 41 4 MATERIALES Y MÉTODOS n este capítulo se explicará cada uno de los pasos hasta conseguir la identificación de emociones. Se tomará como referencia el orden marcado para la construcción de un modelo expuesto en el apartado 2.4 de este trabajo. Se mostrará el dataset utilizado, los cambios realizados sobre los datos para el correcto funcionamiento de los modelos y todos los modelos tratados en el trabajo, explicando cada uno de ellos, enmarcados todos ellos dentro de las redes neuronales. Los resultados obtenidos y las conclusiones a las que se puedan llegar, aparecerán en capítulos posteriores, cuyo contenido estará íntimamente relacionado e influenciado por este. Los pasos que aparecerán a continuación son los elegidos para este caso concreto, pero no son exactamente cada uno de los indicados en el apartado 2.4. Es una individualización del proceso de creado de un modelo de Machine Learning, se mantendrá el esquema con matices. El lenguaje de programación empleado para los códigos es Python, en la versión 3.8.3. El entorno de desarrollo es Jupyter 6.0.3 a través de Anaconda Navigator 1.9.12. 4.1 Dataset El objetivo es lograr que un modelo de Machine Learning, en concreto un modelo de red neuronal, identifique emociones en la música. El modelo queda bastante definido ya al inicio del proceso y la base de datos se obtiene de forma personal seleccionando canciones a las que después se le reducirá la duración. El procedimiento de obtención de canciones empieza con una clasificación de las emociones en estilos de música. De una forma muy general y personal, se asocia a la alegría los estilos Disco, Pop Latino o HipHop; al enfado los estilos Hard Rock o Heavy Metal; a la relajación el Blues o el Jazz, y a la tristeza canciones Pop con un ritmo más lento. La línea más fina entre canciones de dos emociones serían las asociadas a la tristeza y a la relajación. A la hora de la selección ambas tienen un ritmo parecido y la diferencia parece residir en que las de tristeza suelen tener letra y el tema de la canción es melancólico. Para reflejar esta relación y ejemplificar un poco mejor la selección del tipo de canción que aparecerá de forma más marcada en cada grupo, se van a citar dos canciones de cada uno:  Alegría: Waka Waka (Shakira) y Hey Ya! (OutKast)  Tristeza: Sober (Demi Lobato) y Aunque tú no lo sepas (Enrique Urquijo)  Enfado: Murder On (Metallica) y Flick of the sitch (AC/DC)  Relajado: Do I love you because you’re beautiful? (John Coltrane) y That old feeling (Chet Baker) E Solo puedes analizar los datos que tienes. Sé estratégico sobre qué reunir y cómo almacenarlo. - Marie Curie - 48 49 5 EXPERIMENTOS Y RESULTADOS continuación se van a indicar cada una de las pruebas que se han realizado en la búsqueda de la red óptima. Junto a cada experimento aparecerán los resultados del mismo en una tabla. Hay un total de 2 pruebas mostradas en los siguientes 3 puntos: función activación y optimizador, relación capas y neuronas, y matriz de confusión para estudiar la clasificación llevada a cabo por la red. 5.1 Experimento 1: función de activación y optimizador En el primer experimento se van a probar diferentes combinaciones de funciones de activación y optimizadores con la finalidad de ir dando forma a la red neuronal más óptima con la elección de hiperparámetros. La primera prueba entrena un perceptrón con el optimizador Adam y las funciones de activación Sigmoide, Relu y Tangente Hiperbólica. Se empieza por el optimizador Adam debido a que es el más usado y el que arroja mejores resultados de forma más general. Se entrenan 50, 100 y 150 épocas cada una. Este primer perceptrón está formado por una capa de entrada con 9 neuronas, son 9 los descriptores que se han obtenido de cada audio de la base de datos, y una capa de salida con 4 neuronas, son 4 las clases a las que se puede asociar cada entrada. Tiene además una capa oculta con 16 neuronas. De la siguiente ejecución se tomarán las funciones con mejores resultados y el número de épocas, y con estas elecciones se procederá al cambio de optimizador para probar descenso de gradiente estocástico (SGD) y RMSprop. El proceso aparece en el código 6_FuncionActivacion_Optimizador y en la siguiente tabla se muestran los resultados de precisión de cada caso: Tabla 5-1. Precisión del perceptrón con optimizador Adam. Épocas 50 100 150 Sigmoide 0.7 0.72 0.77 Relu 0.75 0.78 0.77 Tanh 0.72 0.74 0.78 A Un ser humano debe convertir la información en inteligencia o conocimiento. Hemos tendido a olvidar que ninguna computadora nos hará jamás una nueva pregunta. - Grace Murray Hopper - 50 Los mejores resultados respecto a cada función de activación son: Relu con 100 épocas, Sigmoide y Tangente Hiperbólica con 150. Estas 3 combinaciones son las que se probarán a continuación con los otros dos optimizadores y se comparan con Adam. Sigue manteniéndose el mismo modelo de perceptrón que con el optimizador anterior. Tabla 5-2. Precisión del perceptrón con optimizadores SGD y RMSprop. Optimizador Adam SGD RMSprop Sigmoide con 150 épocas 0.77 0.72 0.74 Relu con 100 épocas 0.78 0.76 0.73 Tanh con 150 épocas 0.78 0.69 0.73 Tras los resultados seguimos manteniendo las tres funciones de activación para poder estudiar su respuesta con más capas y neuronas, y el optimizador de Adam, debido a que es el mejor optimizador para las tres funciones. El número de épocas no queda fijado. 5.2 Experimento 2: relación capas y neuronas En este experimento se sigue haciendo uso de las tres funciones de activación, Sigmoide, Relu y Tanh; se probará variedad de épocas, junto al optimizador Adam, se barajarán el número de capas y el número de neuronas por capa, y se irán aumentando a medida que se vea una mejora en la precisión, o disminuyendo. Para hacer más cómodo el estudio, se fija una función de activación en cada subapartado, se marca el optimizador Adam, la función de salida es la Softmax, y se van variando las capas, las neuronas y las épocas. Cada prueba con una función de activación va a comenzar con una capa oculta y cuatro posibles valores de neuronas por capa. Estos valores de neuronas por capa se han elegido tomando las primeras cuatro potencias impares de 2, elección aleatoria, descartando el 1. Si los resultados de las pruebas requieren probar otro número de capas o de neuronas, se irán ajustando con cada función. En cada una de las tablas que se mostrarán a continuación aparecerá el valor x, esta x hará referencia a una estructura de red neuronal no ejecutada con las épocas indicadas debido a que se ha encontrado con esa estructura el valor óptimo. Este valor óptimo aparecerá resaltado en negrita en la tabla. 5.2.1 Función de activación Sigmoide Para esta primera prueba el código es 8_Red_Neuronal_Multicapas_Sig. Comienza con una sola capa oculta para cuatro modelos, cada uno de ellos con un número de neuronas por capa diferente. La capa de entrada mantiene sus 9 neuronas y la de salida sus 4 en todos los casos. Se realizaron en total 5 ejecuciones variando el número de épocas, aumentando o disminuyendo según los resultados. 51 Tabla 5-3. Precisión y pérdida de red neuronal con 1 capa oculta con función Sigmoide. Número de neuronas en cada capa 8 32 128 512 25 épocas x loss: 0.5136 - accuracy: 0.7879 x x 50 épocas loss: 0.5392 - accuracy: 0.7475 loss: 0.5356 - accuracy: 0.7677 x loss: 0.5458 - accuracy: 0.7475 100 épocas loss: 0.5287 - accuracy: 0.7576 loss: 0.5460 - accuracy: 0.7475 loss: 0.6249 - accuracy: 0.7071 loss: 0.4758 - accuracy: 0.7879 150 épocas loss: 0.5447 - accuracy: 0.7273 loss: 0.5533 - accuracy: 0.7273 loss: 0.4953 - accuracy: 0.7980 loss: 0.5011 - accuracy: 0.6970 200 épocas x x loss: 0.6011 - accuracy: 0.7374 x En los resultados de la primera prueba se aprecia que las cuatro opciones barajadas dan buenos resultados, con diferencia en todos los casos en el número de épocas, y destacar que en dos de los casos las pérdidas están por debajo de 0.5. Para comprobar si un aumento en el número de capas ocultas supone una mejora en la precisión, se repitió el mismo proceso con los mismos modelos a los que se les añadió una capa oculta, teniendo como resultado una estructura con dos capas ocultas. Tabla 5-4. Precisión y pérdida en red neuronal con 2 capas ocultas con función Sigmoide. Número de neuronas en cada capa 8 32 128 512 50 épocas loss: 0.8909 - accuracy: 0.5051 x x loss: 0.5927 - accuracy: 0.6970 100 épocas loss: 0.7563 - accuracy: 0.6263 loss: 0.6147 - accuracy: 0.6869 loss: 0.4965 - accuracy: 0.7475 loss: 0.4912 - accuracy: 0.7273 150 épocas loss: 0.6965 - accuracy: 0.6162 loss: 0.5275 - accuracy: 0.7273 loss: 0.5088 - accuracy: 0.7677 loss: 0.5305 - accuracy: 0.7273 200 épocas x loss: 0.5531 - accuracy: 0.6869 loss: 0.5077 - accuracy: 0.7576 x Tras la revisión de los resultados de esta segunda prueba se comprobó que en ningún caso se consigue mejorar los valores que se obtuvieron con una sola capa oculta. Tras confirmar que lo más óptimo es tener un modelo con una capa, se estudió la posibilidad de mejorarlo añadiendo más neuronas. El número de neuronas por capa elegido es la potencia 7 de 2. 52 Tabla 5-5. Precisión y pérdida en red neuronal con 1 capa oculta con 512 y 1024 neuronas por capa con función Sigmoide. Número de neuronas en cada capa 512 1024 50 épocas loss: 0.5458 - accuracy: 0.7475 loss: 0.5826 - accuracy: 0.7172 100 épocas loss: 0.4758 - accuracy: 0.7879 loss: 0.6865 - accuracy: 0.7273 150 épocas loss: 0.5011 - accuracy: 0.6970 loss: 0.5809 - accuracy: 0.7273 El aumento de neuronas tampoco ha dado buenos resultados comparándolos con los que teníamos. 5.2.2 Función de activación Relu En este segundo subapartado se trabajó con la función de activación Relu en el código 8_Red_Neuronal_Multicapas_Relu. La primera estructura de la red vuelve a ser una capa oculta en la cual se irán cambiando el número de neuronas. La capa de entrada mantiene sus 9 neuronas y la de salida sus 4 en todos los casos. El optimizador, cómo ya se avanzó al inicio del capítulo, va a ser siempre Adam. Tabla 5-6. Precisión y pérdida de red neuronal con 1 capa oculta con función Relu. Número de neuronas en cada capa 8 32 128 512 20 épocas x x x loss: 0.8926 - accuracy: 0.7576 25 épocas x x x loss: 0.9392 - accuracy: 0.7879 50 épocas loss: 0.5711 - accuracy: 0.7071 loss: 0.5307 - accuracy: 0.7475 loss: 0.5500 - accuracy: 0.7576 loss: 0.6825 - accuracy: 0.7576 100 épocas loss: 0.5551 - accuracy: 0.7071 loss: 0.4994 - accuracy: 0.7475 loss: 0.5200 - accuracy: 0.7879 loss: 0.7181 - accuracy: 0.7576 150 épocas loss: 0.5615 - accuracy: 0.7172 loss: 0.5557 - accuracy: 0.7879 loss: 0.6526 - accuracy: 0.7475 loss: 0.8924 - accuracy: 0.7475 200 épocas loss: 0.5650 - accuracy: 0.727 loss: 0.6232 - accuracy: 0.7879 x x 750 épocas loss: 0.5685 - accuracy: 0.7677 x x x 53 800 épocas loss: 0.6152 - accuracy: 0.7273 x x x Con una sola capa oculta, la red que mejor responde es la que presenta 128 neuronas por capa tras una ejecución de 100 épocas. Muy de cerca, aunque con unas pérdidas un poco más altas, la seguiría la red con 32 neuronas. Al igual que con la función Sigmoide se comprobó que ocurría con el aumento de capas ocultas, se hará lo mismo usando la función Relu. Se creó un modelo de red con 2 capas ocultas, a las que se les asignó por capa 8, 32, 128 y 512 neuronas. Se ejecutaron dichas redes y los resultados de la precisión se muestran en la siguiente tabla. Tabla 5-7. Precisión y pérdida en red neuronal con 2 capas ocultas con función Relu. Número de neuronas en cada capa 8 32 128 512 50 épocas loss: 0.5329 - accuracy: 0.7576 loss: 0.5314 - accuracy: 0.7374 loss: 0.5699 - accuracy: 0.7677 100 épocas loss: 0.4189 - accuracy: 0.8055 loss: 0.5051 - accuracy: 0.7778 loss: 0.6090 - accuracy: 0.7778 loss: 0.5332 - accuracy: 0.8283 150 épocas loss: 0.3642 - accuracy: 0.8383 loss: 0.5247 - accuracy: 0.7677 loss: 0.7005 - accuracy: 0.7778 loss: 0.7173 - accuracy: 0.7677 200 épocas loss: 0.4296 - accuracy: 0.8095 x x x Tras la ejecución con 2 capas ocultas se observa que todas las estructuras mejoran salvo la que tiene 128 neuronas por capa. Como la mayoría presenta una mejora se van a poner a prueba con una capa más. Tabla 5-4. Precisión y pérdida en red neuronal con 3 capas ocultas con función Relu. Número de neuronas en cada capa 8 32 128 512 25 épocas loss: 0.6643 - accuracy: 0.6667 loss: 0.7762 - accuracy: 0.6869 loss: 0.6568 - accuracy: 0.7475 loss: 0.6879 - accuracy: 0.8081 50 épocas loss: 0.6239 - accuracy: 0.6667 loss: 0.4948 - accuracy: 0.7778 loss: 0.5650 - accuracy: 0.7778 loss: 0.6500 - accuracy: 0.7778 100 épocas loss: 0.5617 - accuracy: 0.7172 loss: 0.5344 - accuracy: 0.7778 loss: 0.8984 - accuracy: 0.7576 loss: 1.2715 - accuracy: 0.7778 150 épocas loss: 0.5836 - accuracy: 0.7071 loss: 0.5264 - accuracy: 0.7879 x x 54 Con esta última prueba en la que la estructura tiene tres capas ocultas se concluye que el aumento de capas no marca una gran mejoría, y como pasó con la función Sigmoide no se mejora la precisión. El mejor resultado lo ha dado la red neuronal cuya estructura contaba con 2 capas y 8 neuronas, por ello no se va a buscar mejoría en el aumento de neuronas por capa. 5.2.3 Función de activación Tanh El código de este subapartado está en 8_Red_Neuronal_Multicapas_Tanh. Al igual que en los subapartados anteriores la estructura de red cuenta con una capa oculta y optimizador de Adam como estructura inicial. Contará con 9 neuronas en capa de entrada y 4 neuronas en capa de salida. Aquí la función de activación de la capa oculta es Tangente Hiperbólica. Se probará con 8, 32, 128 y 512 neuronas en la capa oculta, y variedad de épocas según resultados. Tabla 5-9. Precisión y pérdida de red neuronal con 1 capa oculta con función Tangente Hiperbólica. Número de neuronas en cada capa 8 32 128 512 25 épocas x x x loss: 0.5531 - accuracy: 0.7273 50 épocas loss: 0.4939 - accuracy: 0.7576 loss: 0.5172 - accuracy: 0.7576 loss: 0.6151 - accuracy: 0.7071 loss: 0.4690 - accuracy: 0.7980 100 épocas loss: 0.4968 - accuracy: 0.7677 loss: 0.4720 - accuracy: 0.7879 loss: 0.5333 - accuracy: 0.7273 loss: 0.6456 - accuracy: 0.7273 150 épocas loss: 0.4997 - accuracy: 0.7677 loss: 0.5341 - accuracy: 0.7677 loss: 0.5812 - accuracy: 0.7677 x 200 épocas loss: 0.5279 - accuracy: 0.7576 x loss: 0.5340 - accuracy: 0.7778 x 300 épocas x x loss: 0.6989 - accuracy: 0.7879 x 450 épocas x x loss: 0.8363 - accuracy: 0.7778 x Tras los resultados con una sola capa oculta se prueba el comportamiento con 2, no se aumenta más debido a que con las anteriores funciones los mejores resultados han sido con 1 o 2. Si fuera necesario se aumentará posteriormente. Todos los demás hiperparámetros serán iguales. 55 Tabla 5-10. Precisión y pérdida de red neuronal con 2 capas ocultas con función Tangente Hiperbólica. Número de neuronas en cada capa 8 32 128 512 25 épocas x x loss: 0.4965 - accuracy: 0.7374 x 50 épocas loss: 0.5033 - accuracy: 0.7273 loss: 0.4915 - accuracy: 0.7374 loss: 0.5177 - accuracy: 0.7980 loss: 0.7232 - accuracy: 0.7273 100 épocas loss: 0.4778 - accuracy: 0.7475 loss: 0.4691 - accuracy: 0.7778 loss: 0.4953 - accuracy: 0.7677 loss: 0.5243 - accuracy: 0.7879 150 épocas loss: 0.5053 - accuracy: 0.7374 loss: 0.4517 - accuracy: 0.7475 x loss: 0.6271 - accuracy: 0.7677 De los resultados se deduce que las estructuras con 8 y 512 neuronas por capa no mejoran con el aumento de capas ocultas, sin embargo, de las otras hay una que se mantiene en número, la de 32 neuronas, y la de 128 mejora. Por tanto, se toman estas dos últimas y se analizan con 3 capas ocultas. Tabla 5-11. Precisión y pérdida de red neuronal con 3 capas ocultas con función Tangente Hiperbólica. Número de neuronas en cada capa 32 128 50 épocas loss: 0.5891 - accuracy: 0.7374 loss: 0.5978 - accuracy: 0.7475 100 épocas loss: 0.5415 - accuracy: 0.7374 loss: 0.5693 - accuracy: 0.7576 150 épocas loss: 0.5611 - accuracy: 0.7576 loss: 0.7340 - accuracy: 0.7576 250 épocas loss: 0.9643 - accuracy: 0.7677 x El aumento de capas no ha dado resultados. Se prueba si es posible con un aumento de neuronas por capa obtener mejores resultados que los de hasta ahora. Salvo el número de capas y de neuronas, lo demás es común al resto de estructuras empleadas en el subapartado. 56 Tabla 5-12. Precisión y pérdida de red neuronal con 1024 neuronas por capa oculta con función Tangente Hiperbólica. Número de capas con 1024 neuronas 1 2 3 100 épocas loss: 0.5579 - accuracy: 0.7576 loss: 0.6097 - accuracy: 0.7172 loss: 0.8434 - accuracy: 0.7071 150 épocas loss: 0.5092 - accuracy: 0.7778 loss: 0.7403 - accuracy: 0.7475 loss: 0.8417 - accuracy: 0.7374 250 épocas loss: 0.5427 - accuracy: 0.7576 loss: 1.1782 - accuracy: 0.7879 loss: 1.1162 - accuracy: 0.7374 El aumento de neuronas por capa tampoco ha dado muy buen resultado, como se venía apreciando con las funciones de activación anteriores. 5.3 Experimento 3: matriz de confusión De los mejores resultados obtenidos en cada uno de los subapartados anteriores se va a generar una matriz de confusión para observar lo bien o lo mal que clasifica la red cada una de las emociones y localizar el lugar de una posible mejora. 5.3.1 Matriz de confusión con Sigmoide Con la función de activación Sigmoide en la capa oculta se obtuvieron los mejores resultados con dos estructuras de redes, ambas con 1 sola capa oculta. La diferencia entre ellas estaba en el número de neuronas de esa capa, 128 y 512, y número de épocas. 150 y 100. Generamos la matriz para el primer caso: 57 Figura 5-1. Matriz confusión para Sigmoide con 128 neuronas en 1 capa. Y para el segundo: Figura 5-2. Matriz confusión para Sigmoide con 512 neuronas en 1 capa. 64 https://es.mathworks.com/discovery/deep-learning.html#howitworks. [14] LIU, Hongyu; LANG, Bo. Machine learning and deep learning methods for intrusion detection systems: A survey. applied sciences, 2019, vol. 9, no 20, p. 4396. [15] GÉRON, A., 2019. Hands-on machine learning with scikit-learn, keras, and tensorflow. Sebastopol (CA): O’Reilly. ISBN 9781492032649. [16] Mathworks, “¿Qué es una red neuronal? Tres cosas que es necesario saber”. Mathworks. https://es.mathworks.com/discovery/deep-learning.html#howitworks. [17] A. Requena, R. Quintanilla, J.M. Bolarín, A. Vázquez, A. Bastida, J. Zúñiga y L.M. Tomá, "Nuevas Tecnologías y Contaminación de Atmósferas, para PYMEs", Universidad de Murcia. https://www.um.es/LEQ/Atmosferas/Ch-VI-3/F63s4p3.htm [18] F. Arribas Jara, “Aprendizaje no supervisado con modelos generativos profundos,” Universidad Autónoma de Madrid, 2018. [19] “Ejemplo Web Scraping en Python: IBEX35® la Bolsa de Madrid” Aprende Machine Learning, 2019. https://www.aprendemachinelearning.com/ejemplo-web-scraping-python-ibex35-bolsa-valores/. [20] “Comprende Principal Component Analysis” Aprende Machine Learning, 2018. https://www.aprendemachinelearning.com/comprende-principal-component-analysis/. [21] “Clasificación con datos desbalanceados” Aprende Machine Learning, 2019. https://www.aprendemachinelearning.com/clasificacion-con-datos-desbalanceados/. [22] TRAPERO ESTEPA, M.D., MURILLO FUENTES, J.J. y PAYÁN SOMET, F.J., 2021. Clasificación de ataques a una red de telecomunicación con Deep Learning Trabajo Fin de Máster . Sevilla: El autor. [23] “Escalado de datos” Interactive Chaos, 2019. https://interactivechaos.com/es/manual/tutorial-de-machine- learning/escalado-de-datos. [24] Boyan Angelov, “El impacto de la Inteligencia Artificial en la asistencia sanitaria”. Medium, 2017. https://towardsdatascience.com/working-with-missing-data-in-machine-learning-9c0a430df4ce. [25] “7 pasos del Machine Learning para construir tu máquina.,” Aprende Machine Learning, 2017. https://www.aprendemachinelearning.com/7 pasos machine learning construir maquina/. [26] Martínez del Amor, Miguel Ángel [IEEE Universidad de Sevilla]. "[Webinar] Deep Learning". Youtube <https://www.youtube.com/watch?v=yXuTu1GfHos> [27] Colaboradores de Wikipedia. Validación cruzada [en línea]. Wikipedia, La enciclopedia libre, 2020 [fecha de consulta: 24 de agosto del 2021]. Disponible en <https://es.wikipedia.org/w/index.php?title=Validaci%C3%B3n_cruzada&oldid=124047241>. [28] Lacárcel Moreno, J. Psicología de la música y emoción musical. En: Educatio Siglo XXI, 20, 213-226. Recuperado a partir de https://revistas.um.es/educatio/article/view/138 [29] Alaminos Fernández, Antonio F. En: Revista de Ciencias Sociales Vol. 9, n.º 1, 2014; pp. 15-42 ISSN: 1989-1385 DOI: 10.14198/OBETS2014.9.1.01. Recuperado a partir de https://doaj.org/article/fdda8fb7cbc94ef3aa119c10cb90102e 65 [30] Laurier, Cyril François. Automatic Classification of musical mood by content-based analysis. 2011 Disponible en: https://repositori.upf.edu/handle/10230/13091?locale-attribute=es [31] Juslin, P. N. & Sloboda, J. A. (2001). Music and Emotion: Theory and Research. Oxford: Oxford University Press. [32] Youtube, https://www.youtube.com/ [33] Transformador de enlace de Youtube a mp3, https://youtubetomp3music.com/es26/ [34] Essentia. music extractor features, https:// essentia.upf.edu/ documentation/ streaming_extractor_music. html. [35] Krumhansl, C. L. (1997). An exploratory study of musical emotions and psychophysiology. Canadian journal of experimental psychology, 51 (4), 336–353. [36] Tim Bock, “What are Dummy Variables?”. DisplayR, 2018. https://www.displayr.com/what-are-dummy- variables/ [37] Red Neuronal Multicapa en Keras. Mariano Rivera, ©2018-2020 [consulta: septiembre 2021]. Disponible en: http://personal.cimat.mx:8181/~mrivera/cursos/aprendizaje_profundo/nn_multicapa/nn_multicapa.html [38] Luis Velasco, “Optimizadores en redes neuronales profundas: un enfoque práctico”. Medium, 2020. https://velascoluis.medium.com/optimizadores-en-redes-neuronales-profundas-un-enfoque- pr%C3%A1ctico-819b39a3eb5 [39] MOOLAYIL, J., 2019. Learn Keras for Deep Neural Networks A Fast-Track Approach to Modern Deep Learning with Python . 1st ed. 2019. Berkeley, CA: Apress. ISBN 1-4842-4240-8. [40] Ignacio G.R. Gavilán, “Catálogo de componentes de redes neuronales (III): funciones de pérdida”. Blog Ignacio G.R. Gavilán, 2020. https://ignaciogavilan.com/catalogo-de-componentes-de-redes-neuronales- iii-funciones-de-perdida/ 66 67 ANEXO A: CÓDIGOS 23_Ordenar_salida_essentia #!/usr/bin/env python # coding: utf-8 # ### 23_Ordenar_salida_essentia # El código "23_Ordenar_salida_essentia" es el encargado primero de ordenar la salida de la libreria essentia. Ordena las características del archivo json de salida, y lo mantiene en el mismo formato. La segunda parte del código transforma de formato json a csv los cuatro archivos con los que se trabaja. import json import pandas as pd # Se accede a la carpeta dónde se encuentran los archivos json extraidos con essentia. Y se selecciona la nueva carpeta dónde se desean guardar los archivos en formato csv, que contienen las caracterísiticas ordenadas. mainpatch = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA" archivos = ['alegria','enfado','relajado','tristeza'] filepatch = 'C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/2_Archivos_salida_essentia/' ordenpatch = 'C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/3_Archivos_ordenados/' # El primer bucle ordena el archivo json y lo mantiene en el mismo formato en la nueva carpeta. for i in archivos: with open(filepatch + i + '.json', "r") as in_data: data = json.load(in_data) with open(ordenpatch + i + 'ord.json', "w") as out_data: json.dump(data ,out_data , sort_keys=True, indent=4, separators=(',', ': ')) # El segundo bucle convierte el archivo json a formato csv. for j in archivos: df = pd.read_json (ordenpatch + j + 'ord.json') df.to_csv (ordenpatch + j + 'ord.csv', index = None) 34_Extraer_caracteristicas #!/usr/bin/env python # coding: utf-8 # ### 34_Extraer_caracteristicas 68 # Este codigo implementa el proceso de extración de un conjunto de características (tomadas del capítulo 4 de la memoria de referencia de este trabajo), las mismas para todas las canciones y para cada una de las cuatro emociones. Tendremos por tanto 9 características de cada canción por cada emoción en cuatro archivos diferentes. import json import csv import pandas as pd # Se accede a la carpeta dónde se encuentran los cuatro archivos csv con las caracteristicas de las 120 canciones de cada emoción. Se selecciona la nueva carpeta dónde se desean guardar los archivos en formato csv, que contienen la selección de caracterísitcas. mainpatch = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA" sentimientos = ['alegria','enfado','relajado','tristeza'] filepatch = mainpatch + '/3_Archivos_ordenados/' featurespatch = mainpatch + '/4_Caracteristicas_por_separado/' # Se crea un array con las caracterísitcas que se van a extraer. features = ['Dissonance','Spectral_Centroid','Spectral_Complexity','Spectral_Rolloff','S pectral_Kurtosis','Zero_Crossing_Rate','Spectral_Skewness','Onset_Rate','Chor ds_Scale'] features_copy = [] # Abrir cada uno de los cuatro ficheros csv que contienen el conjunto completo de características. # Se extraen las caracteristicas y almacenamos en una variable auxiliar. # Abrir un nuevo fichero csv, donde guardar una copia de esas caracteristicas seleccionadas extraidas. # # Al final del bucle, al final de cada línea, asociada a una canción dentro del array, se le agrega como nuevo atributo, el sentimiento al que van asociados todos los atributos. for i in sentimientos: with open(filepatch + i + 'ord.json',"r") as data_file: data = json.load(data_file) with open (featurespatch + i + '_feature.csv',"w") as f: writer = csv.writer(f) for cancion in data.keys(): array_aux = [] caracteristicas_patch = data[cancion]['stats']['lowlevel'] array_aux.append(caracteristicas_patch['dissonance']['mean']) array_aux.append(caracteristicas_patch['spectral_centroid']['mean']) array_aux.append(caracteristicas_patch['spectral_complexity']['mean']) array_aux.append(caracteristicas_patch['spectral_rolloff']['mean']) array_aux.append(caracteristicas_patch['spectral_kurtosis']['mean']) array_aux.append(caracteristicas_patch['zerocrossingrate']['mean']) array_aux.append(caracteristicas_patch['spectral_skewness']['mean']) 69 caracteristicas_patch1 = data[cancion]['stats']['rhythm'] array_aux.append(caracteristicas_patch1['onset_rate']) caracteristicas_patch2 = data[cancion]['stats']['tonal'] array_aux.append(caracteristicas_patch2['chords_scale']) array_aux.append(i) features_copy.append(array_aux) writer.writerows(features_copy) features_copy = [] 45_Train_Test_Sentimientos #!/usr/bin/env python # coding: utf-8 # ### 45_Train_Test_Sentimientos # Separar en train y test los cuatro dataset de las caracteristicas de forma aleatoria, obteniendo de nuevo 8 archivos en formato csv. # Una vez separados, se juntarán los ocho en dos, uno que englobe a todos los datos de etrenamiento y otro a todos los datos de testeo. import csv import json import random import pandas as pd import numpy as np import matplotlib.pyplot as plt # Accedemos a la carpeta de los archivos y a la carpeta dónde irán tras la separación. mainpatch = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA" sentimientos = ['alegria','enfado','relajado','tristeza'] featurespatch = mainpatch + '/4_Caracteristicas_por_separado/' train_test_patch = mainpatch + '/5_Dataset_train_test_separados/' features = ['Dissonance','Spectral_Centroid','Spectral_Complexity','Spectral_Rolloff','S pectral_Kurtosis','Zero_Crossing_Rate','Spectral_Skewness','Onset_Rate','Chor ds_Scale', 'Mood'] # #### Separar en train y test. # Generar una semilla para mantener el resultado aleatorio de la separación. np.random.seed(2020) # Bucle para realizar el proceso de separación de una sola vez para las cuatro emociones. for i in sentimientos: # Se abre el dataset. data = pd.read_csv(featurespatch + i + '_feature.csv', header = None, names = features) # Generar una variable aleatoria que siga una distribución normal, y con ella hacemos la separación de 80% de datos # para entrenamiento, y 20% de datos para testeo. var = np.random.randn(len(data)) 70 # Tomar los valores del vector var (variable aleatoria) menores que 0.8. check = (var<0.8) # Se genera el grupo de train y el grupo de test. training = data[check] testing = data[~check] # Se pasa a csv. training.to_csv(train_test_patch + i + '_train.csv') testing.to_csv(train_test_patch + i + '_test.csv') # #### Concatenar los dataset de cada sentimiento en uno solo, uno para train y otro para test # Abrir los cuatro archivos de train, y guardarlos en df1, df2, df3, df4. df1 = pd.read_csv(train_test_patch + sentimientos[0] + '_train.csv') df2 = pd.read_csv(train_test_patch + sentimientos[1] + '_train.csv') df3 = pd.read_csv(train_test_patch + sentimientos[2] + '_train.csv') df4 = pd.read_csv(train_test_patch + sentimientos[3] + '_train.csv') # Una vez abiertos, se concatenan de forma ordenada, es decir, df2, detrás de df1; df3, detrás de df2, y sucesuvamente. data_training = pd.concat([df1, df2, df3, df4]) # Una vez obtenido el dataframe de train con las caracteristicas de las cuatro emociones juntas, se puede aleatorizar el orden # del archivo csv con la función sample data_training_random = data_training.sample(frac=1) # Se transforma el archivo a csv. data_training_random.to_csv(train_test_patch + 'train.csv') # Reeptir el proceso para los datos de testeo. df5 = pd.read_csv(train_test_patch + sentimientos[0] + '_test.csv') df6 = pd.read_csv(train_test_patch + sentimientos[1] + '_test.csv') df7 = pd.read_csv(train_test_patch + sentimientos[2] + '_test.csv') df8 = pd.read_csv(train_test_patch + sentimientos[3] + '_test.csv') data_testing = pd.concat([df5, df6, df7, df8]) data_testing_random = data_testing.sample(frac=1) data_testing_random.to_csv(train_test_patch + 'test.csv') 56_Transformación #!/usr/bin/env python # coding: utf-8 # ### 56_Transformación # En el código siguiente se va a llevar a cabo las transformaciones de escalado y pasar a binario los atributos que son caracteres. Ambas transformaciones se hacen sobre el dataset de entrenamiento y el dataset de testeo. import seaborn as sns import numpy as np import tensorflow as tf import json import csv import pandas as pd from tensorflow import keras from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegressionCV 71 from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.utils import to_categorical # Cargar dataset de train. mainpatch = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/5_Dataset_train_test_separados/" data_train = pd.read_csv(mainpatch + 'train.csv') # Al tener ahora en un mismos dataset todas las emociones, se puede ver cómo son los datos de nuestro dataset. # seaborn proporciona algunas funciones para facilitar esta representación # El primer paso elimina las dos primeras columnas de indices para la representación data_train_pairplot = data_train.iloc[:, 2:12] sns.pairplot(data_train_pairplot,hue='Mood') # Histograma data_train_pairplot.hist() # #### Escalado prueba = data_train.iloc[:,2:10] # Importamos e instanciamos la clase con las opciones por defecto, escalado entre (0, 1); pero también con la opción del # escalado entre (-1, 1), necesario para la función de activación tanh que se usará más adelante. from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaler_tanh = MinMaxScaler(feature_range = (-1 , 1)) # Se escalan las características predictivas (no es necesario escalar la variable objetivo o etiqueta, irá en formato binario). # De las predictivas, la varibale chord scale no se normaliza, también va en binario. # Se entrena el escalador y se transforman las primeras 10 columnas, no entran en la cuenta as primeras columnas de índices: transformed_data_train = scaler.fit_transform(data_train.iloc[:,2:10]) transformed_data_train_tanh = scaler_tanh.fit_transform(data_train.iloc[:,2:10]) # Considerando que el resultado devuelto por el escalador es un array bidimiensional, # a continuación podemos reconstruir el dataframe, añadiendo al array en cuestión la columna "species" con la variable objetivo # y dando nombre a todas las columnas: transformed_data_train = pd.DataFrame(transformed_data_train) transformed_data_train.columns = prueba.columns transformed_data_train_tanh = pd.DataFrame(transformed_data_train_tanh) transformed_data_train_tanh.columns = prueba.columns # Agregar las dos columnas finales del dataframe original. columnas_finales = data_train.iloc[:,10:] transformed_data_train = pd.concat([transformed_data_train,columnas_finales], axis=1) 72 transformed_data_train_tanh = pd.concat([transformed_data_train_tanh,columnas_finales], axis=1) # #### Etiquetas en binario (variable dummy) # Keras necesita que todas las etiquetas sean codificadas de forma numérica, lo que significa, por ejemplo, que hemos de añadir una columna numérica a cada muestra para representar el estado de ánimo al que pertenece la muestra de forma binaria (es lo que se llama one-hot-encoding) def createDummies (df, var_name): dummy = pd.get_dummies(df[var_name], prefix = var_name) df = df.drop(var_name, axis=1) df = pd.concat([df, dummy], axis=1) return df # Con este paso se transforma la columna Mood a binario, para no tener etiquetas con caracateres data_train_transformed_dummies = createDummies(transformed_data_train, "Mood") data_train_transformed_dummies_tanh = createDummies(transformed_data_train_tanh, "Mood") # ### Transformar la variable Chords_Scale a binario # En lugar de emplear una variable dummies también para esta caracteristica creando dos nuevas columnas, se puede aplicar una condición que convierta el valor 'mayor' en 1 y el valor 'minor' en 0, y se matiene una sola columna. for i in data_train_transformed_dummies.index: if data_train_transformed_dummies.loc[i,"Chords_Scale"] == 'major': data_train_transformed_dummies.loc[i,"Chords_Scale"] = 1 else: data_train_transformed_dummies.loc[i,"Chords_Scale"] = 0 for i in data_train_transformed_dummies_tanh.index: if data_train_transformed_dummies_tanh.loc[i,"Chords_Scale"] == 'major': data_train_transformed_dummies_tanh.loc[i,"Chords_Scale"] = 1 else: data_train_transformed_dummies_tanh.loc[i,"Chords_Scale"] = 0 # #### Pasar a csv # Tras las modificaciones se pasa a csv para poder trabajar con la red neuronal. # Vamos a transformarlo, pero para ello no vamos a sobreescribir los que existen, sino que crearemos nuevos. mainpatch_red = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/6_Datos_preparados/" data_train_transformed_dummies.to_csv(mainpatch_red + 'train_transformado.csv') data_train_transformed_dummies_tanh.to_csv(mainpatch_red + 'train_transformado_tanh.csv') # Repetimos los cambios del dataset Train al dataset Test para probar la red neuronal. 73 # Leemos el csv data_test = pd.read_csv(mainpatch + 'test.csv') # Escalamos los valores. scaler = MinMaxScaler() transformed_data_test = scaler.fit_transform(data_test.iloc[:,2:10]) transformed_data_test = pd.DataFrame(transformed_data_test) prueba = data_test.iloc[:,2:10] transformed_data_test.columns = prueba.columns columnas_finales = data_test.iloc[:,10:] transformed_data_test = pd.concat([transformed_data_test,columnas_finales], axis=1) # Creamos la variable dummies para pasar las etiquetas a binario. data_test_transformed_dummies = createDummies(transformed_data_test, "Mood") # Cambiamos el valor 'major' por 1 y 'minor' por 0. for i in data_test_transformed_dummies.index: if data_test_transformed_dummies.loc[i,"Chords_Scale"] == 'major': data_test_transformed_dummies.loc[i,"Chords_Scale"] = 1 else: data_test_transformed_dummies.loc[i,"Chords_Scale"] = 0 # Tras todas estas modificaciones se pasa a csv. data_test_transformed_dummies.to_csv(mainpatch_red + 'test_transformado.csv') # Repetimos los cambios del dataset Train al dataset Test para probar la red neuronal con función de activación Tanh. # Escalamos los valores. scaler_tanh = MinMaxScaler(feature_range = (-1 , 1)) transformed_data_test_tanh = scaler_tanh.fit_transform(data_test.iloc[:,2:10]) transformed_data_test_tanh = pd.DataFrame(transformed_data_test_tanh) prueba = data_test.iloc[:,2:10] transformed_data_test_tanh.columns = prueba.columns columnas_finales = data_test.iloc[:,10:] transformed_data_test_tanh = pd.concat([transformed_data_test_tanh,columnas_finales], axis=1) # Creamos la variable dummies para pasar las etiquetas a binario. data_test_transformed_dummies_tanh = createDummies(transformed_data_test_tanh, "Mood") # Cambiamos el valor 'major' por 1 y 'minor' por 0. for i in data_test_transformed_dummies_tanh.index: if data_test_transformed_dummies_tanh.loc[i,"Chords_Scale"] == 'major': data_test_transformed_dummies_tanh.loc[i,"Chords_Scale"] = 1 else: data_test_transformed_dummies_tanh.loc[i,"Chords_Scale"] = 0 # Tras todas estas modificaciones se pasa a csv data_test_transformed_dummies_tanh.to_csv(mainpatch_red + 'test_transformado_tanh.csv') 6_FuncionActivacion_Optimizador #!/usr/bin/env python # coding: utf-8 80 from keras.models import Sequential from keras.layers.core import Dense, Activation from keras import optimizers from keras.utils import to_categorical from keras.utils import np_utils # Se toman los dataset con el procesado de los datos, tanto el de train como el de test. mainpatch_red = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/6_Datos_preparados/" data_train_red = pd.read_csv(mainpatch_red + 'train_transformado.csv') data_test_red = pd.read_csv(mainpatch_red + 'test_transformado.csv') # Separación del dataset train en atributos y etiquetas. X_train = data_train_red.values[:,1:10] Y_train = data_train_red.values[:,10:] # Separación del dataset test en atributos y etiquetas. X_test = data_test_red.values[:,1:10] Y_test = data_test_red.values[:,10:] # ### Definición del modelo from keras import models from keras import layers from keras.utils.vis_utils import plot_model # La capa de entrada con 9 neuronas, para 9 características. # Las capas ocultas van aumentando al igual que las neuronas por capa. # La capa de salida tendrá 4, por ser 4 emociones. # 1 capas ocultas con 8, 32, 128 y 512 neuronas -> sigmoide model_1_8_sig = models.Sequential() model_1_8_sig.add(layers.Dense(8, activation='sigmoid', input_shape=(9,))) model_1_8_sig.add(layers.Dense(4, activation='softmax')) model_1_32_sig = models.Sequential() model_1_32_sig.add(layers.Dense(32, activation='sigmoid', input_shape=(9,))) model_1_32_sig.add(layers.Dense(4, activation='softmax')) model_1_128_sig = models.Sequential() model_1_128_sig.add(layers.Dense(128, activation='sigmoid', input_shape=(9,))) model_1_128_sig.add(layers.Dense(4, activation='softmax')) model_1_512_sig = models.Sequential() model_1_512_sig.add(layers.Dense(512, activation='sigmoid', input_shape=(9,))) model_1_512_sig.add(layers.Dense(4, activation='softmax')) #model_2_5.summary() model_1_8_sig.compile(optimizer='adam',loss='categorical_crossentropy',metric s=['accuracy']) model_1_32_sig.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_1_128_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_1_512_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) 81 # ### Proceso de Entrenamiento # Preparados los datos y definida la red (estructura y funcionalidad), podemos hacer uso de la instrucción fit para comenzar el proceso de entrenamiento sobre los datos que tenemos. model_1_8_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=1) model_1_32_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=1) model_1_128_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=1) model_1_512_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=1) # ### Proceso de testeo # Debemos tener en cuenta que los valores mostrados son el error y métricas calculados sobre los propios datos de entrenamiento. Sin embargo, como el objetivo de un modelo de aprendizaje es generalizar bien sobre datos que el proceso de entrenamiento no ha visto anteriormente, necesitamos el conjunto de test para evaluar cómo se comporta la red sobre ejemplos que no ha usado para ajustarse. test_loss_1_8_sig, test_acc_1_8_sig = model_1_8_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_32_sig, test_acc_1_32_sig = model_1_32_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_128_sig, test_acc_1_128_sig = model_1_128_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_512_sig, test_acc_1_512_sig = model_1_512_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # ### Repeticion del proceso aumentando las capas # 5 capas: model_5_8_sig = models.Sequential() model_5_8_sig.add(layers.Dense(8, activation='sigmoid', input_shape=(9,))) model_5_8_sig.add(layers.Dense(8, activation='sigmoid')) model_5_8_sig.add(layers.Dense(8, activation='sigmoid')) model_5_8_sig.add(layers.Dense(8, activation='sigmoid')) model_5_8_sig.add(layers.Dense(8, activation='sigmoid')) model_5_8_sig.add(layers.Dense(4, activation='softmax')) model_5_8_sig.compile(optimizer='adam',loss='categorical_crossentropy',metric s=['accuracy']) model_5_32_sig = models.Sequential() model_5_32_sig.add(layers.Dense(32, activation='sigmoid', input_shape=(9,))) model_5_32_sig.add(layers.Dense(32, activation='sigmoid')) model_5_32_sig.add(layers.Dense(32, activation='sigmoid')) model_5_32_sig.add(layers.Dense(32, activation='sigmoid')) model_5_32_sig.add(layers.Dense(32, activation='sigmoid')) model_5_32_sig.add(layers.Dense(4, activation='softmax')) model_5_32_sig.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) 82 model_5_128_sig = models.Sequential() model_5_128_sig.add(layers.Dense(128, activation='sigmoid', input_shape=(9,))) model_5_128_sig.add(layers.Dense(128, activation='sigmoid')) model_5_128_sig.add(layers.Dense(128, activation='sigmoid')) model_5_128_sig.add(layers.Dense(128, activation='sigmoid')) model_5_128_sig.add(layers.Dense(128, activation='sigmoid')) model_5_128_sig.add(layers.Dense(4, activation='softmax')) model_5_128_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_5_512_sig = models.Sequential() model_5_512_sig.add(layers.Dense(512, activation='sigmoid', input_shape=(9,))) model_5_512_sig.add(layers.Dense(512, activation='sigmoid')) model_5_512_sig.add(layers.Dense(512, activation='sigmoid')) model_5_512_sig.add(layers.Dense(512, activation='sigmoid')) model_5_512_sig.add(layers.Dense(512, activation='sigmoid')) model_5_512_sig.add(layers.Dense(4, activation='softmax')) model_5_512_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_5_8_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=10) model_5_32_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_5_128_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_5_512_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=10) loss_5_8_sig, acc_5_8_sig = model_5_8_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_5_32_sig, acc_5_32_sig = model_5_32_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_5_128_sig, acc_5_128_sig = model_5_128_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_5_512_sig, acc_5_512_sig = model_5_512_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # Lo normal es que la red se comporte peor en los datos de test que en los datos de entrenamiento, ya que el proceso de entrenamiento consiste precisamente en ajustar los pesos para que el error cometido en estos últimos se minimice. Esta diferencia de comportamiento entre entrenamiento y test se denomina overfitting (o sobreajuste). # ### Aumento o disminición de capas según resultados # 2 capas: model_2_8_sig = models.Sequential() model_2_8_sig.add(layers.Dense(8, activation='sigmoid', input_shape=(9,))) model_2_8_sig.add(layers.Dense(8, activation='sigmoid')) model_2_8_sig.add(layers.Dense(4, activation='softmax')) model_2_8_sig.compile(optimizer='adam',loss='categorical_crossentropy',metric s=['accuracy']) model_2_32_sig = models.Sequential() 83 model_2_32_sig.add(layers.Dense(32, activation='sigmoid', input_shape=(9,))) model_2_32_sig.add(layers.Dense(32, activation='sigmoid')) model_2_32_sig.add(layers.Dense(4, activation='softmax')) model_2_32_sig.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_2_128_sig = models.Sequential() model_2_128_sig.add(layers.Dense(128, activation='sigmoid', input_shape=(9,))) model_2_128_sig.add(layers.Dense(128, activation='sigmoid')) model_2_128_sig.add(layers.Dense(4, activation='softmax')) model_2_128_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_2_512_sig = models.Sequential() model_2_512_sig.add(layers.Dense(512, activation='sigmoid', input_shape=(9,))) model_2_512_sig.add(layers.Dense(512, activation='sigmoid')) model_2_512_sig.add(layers.Dense(4, activation='softmax')) model_2_512_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_2_8_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=10) model_2_32_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_2_128_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_2_512_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=50, batch_size=10) loss_2_8_sig, acc_2_8_sig = model_2_8_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_32_sig, acc_2_32_sig = model_2_32_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_128_sig, acc_2_128_sig = model_2_128_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_512_sig, acc_2_512_sig = model_2_512_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # ### Elegimos aumentar neuronas para una sola capa model_1_1024_sig = models.Sequential() model_1_1024_sig.add(layers.Dense(1024, activation='sigmoid', input_shape=(9,))) model_1_1024_sig.add(layers.Dense(4, activation='softmax')) model_1_1024_sig.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_1_1024_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=100, batch_size=10) loss_1_1024_sig, acc_1_1024_sig = model_1_1024_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # ### Matriz de confusión 1 84 model_1_128_sig = models.Sequential() model_1_128_sig.add(layers.Dense(128, activation='sigmoid', input_shape=(9,))) model_1_128_sig.add(layers.Dense(4, activation='softmax')) model_1_128_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_1_128_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) test_loss_1_128_sig, test_acc_1_128_sig = model_1_128_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) y_predict=model_1_128_sig.predict(X_test) cm = confusion_matrix(Y_test.argmax(axis=1), y_predict.argmax(axis=1)) print (cm) # Realizacion de la matriz de confusion: cm_df = pd.DataFrame(cm,index = ['alegria','enfado','relajado','tristeza'], columns = ['alegria','enfado','relajado','tristeza']) plt.figure(figsize=(9,7)) sns.heatmap(cm_df, annot=True) plt.title(u'Matriz de confusión de los sentimientos:') plt.ylabel(u'Valor real') plt.xlabel(u'Valor predicho') print ('Accuracy Score :',accuracy_score(Y_test.argmax(axis=1), y_predict.argmax(axis=1))) print ('Report : ') print (classification_report(Y_test.argmax(axis=1), y_predict.argmax(axis=1), target_names=['alegria','enfado','relajado','tristeza'])) plt.show() # ### Matriz de confusión 2 model_1_512_sig = models.Sequential() model_1_512_sig.add(layers.Dense(128, activation='sigmoid', input_shape=(9,))) model_1_512_sig.add(layers.Dense(4, activation='softmax')) model_1_512_sig.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_1_512_sig.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=100, batch_size=10) test_loss_1_512_sig, test_acc_1_512_sig = model_1_512_sig.evaluate(X_test.astype("float32"), Y_test.astype("float32")) y_predict=model_1_512_sig.predict(X_test) cm = confusion_matrix(Y_test.argmax(axis=1), y_predict.argmax(axis=1)) print (cm) # Realizacion de la matriz de confusion: cm_df = pd.DataFrame(cm,index = ['alegria','enfado','relajado','tristeza'], 85 columns = ['alegria','enfado','relajado','tristeza']) plt.figure(figsize=(9,7)) sns.heatmap(cm_df, annot=True) plt.title(u'Matriz de confusión de los sentimientos:') plt.ylabel(u'Valor real') plt.xlabel(u'Valor predicho') print ('Accuracy Score :',accuracy_score(Y_test.argmax(axis=1), y_predict.argmax(axis=1))) print ('Report : ') print (classification_report(Y_test.argmax(axis=1), y_predict.argmax(axis=1), target_names=['alegria','enfado','relajado','tristeza'])) plt.show() 8_Red_Neuronal_Multicapas_Relu #!/usr/bin/env python # coding: utf-8 # ## 8_Red_Neuronal_Multicapas_Relu # En este código se va a buscar la combinación idónea de capas ocultas y neuronas. # #### Importación de librerías y carga de dataset. import seaborn as sns import numpy as np import tensorflow as tf from tensorflow import keras from matplotlib import pyplot as plt from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegressionCV from sklearn.decomposition import PCA from sklearn.metrics import confusion_matrix from sklearn.preprocessing import LabelEncoder from sklearn.metrics import accuracy_score from sklearn.metrics import classification_report from keras import models from keras import layers from keras.utils.vis_utils import plot_model from keras.models import Sequential from keras.layers.core import Dense, Activation from keras import optimizers from keras.utils import to_categorical from keras.utils import np_utils import json import csv import pandas as pd # Se toman los dataset con el procesado de los datos, tanto el de train como el de test. 86 mainpatch_red = "C:/Users/Ana Parra/Documents/Trabajo/ANACONDA/6_Datos_preparados/" data_train_red = pd.read_csv(mainpatch_red + 'train_transformado.csv') data_test_red = pd.read_csv(mainpatch_red + 'test_transformado.csv') # Separación del dataset train en atributos y etiquetas. X_train = data_train_red.values[:,1:10] Y_train = data_train_red.values[:,10:] # Separación del dataset test en atributos y etiquetas. X_test = data_test_red.values[:,1:10] Y_test = data_test_red.values[:,10:] # ### Definición del modelo # La capa de entrada con 9 neuronas, para 9 características. # Las capas ocultas van aumentando al igual que las neuronas por capa. # La capa de salida tendrá 4, por ser 4 emociones. # 1 capas ocultas con 8, 32, 128 y 512 neuronas -> relu model_1_8_relu = models.Sequential() model_1_8_relu.add(layers.Dense(8, activation='relu', input_shape=(9,))) model_1_8_relu.add(layers.Dense(4, activation='softmax')) model_1_32_relu = models.Sequential() model_1_32_relu.add(layers.Dense(32, activation='relu', input_shape=(9,))) model_1_32_relu.add(layers.Dense(4, activation='softmax')) model_1_128_relu = models.Sequential() model_1_128_relu.add(layers.Dense(128, activation='relu', input_shape=(9,))) model_1_128_relu.add(layers.Dense(4, activation='softmax')) model_1_512_relu = models.Sequential() model_1_512_relu.add(layers.Dense(512, activation='relu', input_shape=(9,))) model_1_512_relu.add(layers.Dense(4, activation='softmax')) model_1_8_relu.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_1_32_relu.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_1_128_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_1_512_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) # ### Proceso de Entrenamiento # Preparados los datos y definida la red (estructura y funcionalidad), podemos hacer uso de la instrucción fit para comenzar el proceso de entrenamiento sobre los datos que tenemos. model_1_8_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) model_1_32_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) model_1_128_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) model_1_512_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) 87 # ### Proceso de testeo # Debemos tener en cuenta que los valores mostrados son el error y métricas calculados sobre los propios datos de entrenamiento. Sin embargo, como el objetivo de un modelo de aprendizaje es generalizar bien sobre datos que el proceso de entrenamiento no ha visto anteriormente, necesitamos el conjunto de test para evaluar cómo se comporta la red sobre ejemplos que no ha usado para ajustarse. test_loss_1_8_relu, test_acc_1_8_relu = model_1_8_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_32_relu, test_acc_1_32_relu = model_1_32_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_128_relu, test_acc_1_128_relu = model_1_128_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) test_loss_1_512_relu, test_acc_1_512_relu = model_1_512_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # ### Aumento o disminición de capas según resultados # 2 capas: model_2_8_relu = models.Sequential() model_2_8_relu.add(layers.Dense(8, activation='relu', input_shape=(9,))) model_2_8_relu.add(layers.Dense(8, activation='relu')) model_2_8_relu.add(layers.Dense(4, activation='softmax')) model_2_8_relu.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_2_32_relu = models.Sequential() model_2_32_relu.add(layers.Dense(32, activation='relu', input_shape=(9,))) model_2_32_relu.add(layers.Dense(32, activation='relu')) model_2_32_relu.add(layers.Dense(4, activation='softmax')) model_2_32_relu.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_2_128_relu = models.Sequential() model_2_128_relu.add(layers.Dense(128, activation='relu', input_shape=(9,))) model_2_128_relu.add(layers.Dense(128, activation='relu')) model_2_128_relu.add(layers.Dense(4, activation='softmax')) model_2_128_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_2_512_relu = models.Sequential() model_2_512_relu.add(layers.Dense(128, activation='relu', input_shape=(9,))) model_2_512_relu.add(layers.Dense(128, activation='relu')) model_2_512_relu.add(layers.Dense(4, activation='softmax')) model_2_512_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_2_8_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) model_2_32_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) model_2_128_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) 88 model_2_512_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) loss_2_8_relu, acc_2_8_relu = model_2_8_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_32_relu, acc_2_32_relu = model_2_32_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_128_relu, acc_2_128_relu = model_2_128_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_2_512_relu, acc_2_512_relu = model_2_512_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # ### Repeticion del proceso aumentando las capas # 3 capas: model_3_8_relu = models.Sequential() model_3_8_relu.add(layers.Dense(8, activation='relu', input_shape=(9,))) model_3_8_relu.add(layers.Dense(8, activation='relu')) model_3_8_relu.add(layers.Dense(8, activation='relu')) model_3_8_relu.add(layers.Dense(4, activation='softmax')) model_3_8_relu.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_3_32_relu = models.Sequential() model_3_32_relu.add(layers.Dense(32, activation='relu', input_shape=(9,))) model_3_32_relu.add(layers.Dense(32, activation='relu')) model_3_32_relu.add(layers.Dense(32, activation='relu')) model_3_32_relu.add(layers.Dense(4, activation='softmax')) model_3_32_relu.compile(optimizer='adam',loss='categorical_crossentropy',metr ics=['accuracy']) model_3_128_relu = models.Sequential() model_3_128_relu.add(layers.Dense(128, activation='relu', input_shape=(9,))) model_3_128_relu.add(layers.Dense(128, activation='relu')) model_3_128_relu.add(layers.Dense(128, activation='relu')) model_3_128_relu.add(layers.Dense(4, activation='softmax')) model_3_128_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_3_512_relu = models.Sequential() model_3_512_relu.add(layers.Dense(512, activation='relu', input_shape=(9,))) model_3_512_relu.add(layers.Dense(512, activation='relu')) model_3_512_relu.add(layers.Dense(512, activation='relu')) model_3_512_relu.add(layers.Dense(4, activation='softmax')) model_3_512_relu.compile(optimizer='adam',loss='categorical_crossentropy',met rics=['accuracy']) model_3_8_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_3_32_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_3_128_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) model_3_512_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=200, batch_size=10) 89 loss_3_8_relu, acc_3_8_relu = model_3_8_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_3_32_relu, acc_3_32_relu = model_3_32_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_3_128_relu, acc_3_128_relu = model_3_128_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) loss_3_512_relu, acc_3_512_relu = model_3_512_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) # Lo normal es que la red se comporte peor en los datos de test que en los datos de entrenamiento, ya que el proceso de entrenamiento consiste precisamente en ajustar los pesos para que el error cometido en estos últimos se minimice. Esta diferencia de comportamiento entre entrenamiento y test se denomina overfitting (o sobreajuste). # ### Matriz de confusión 1 # 2 capas con 8 neuronas model_2_8_relu = models.Sequential() model_2_8_relu.add(layers.Dense(8, activation='relu', input_shape=(9,))) model_2_8_relu.add(layers.Dense(8, activation='relu')) model_2_8_relu.add(layers.Dense(4, activation='softmax')) model_2_8_relu.compile(optimizer='adam',loss='categorical_crossentropy',metri cs=['accuracy']) model_2_8_relu.fit(X_train.astype("float32"), Y_train.astype("float32"), epochs=150, batch_size=10) loss_2_8_relu, acc_2_8_relu = model_2_8_relu.evaluate(X_test.astype("float32"), Y_test.astype("float32")) y_predict = model_2_8_relu.predict(X_test) cm = confusion_matrix(Y_test.argmax(axis=1), y_predict.argmax(axis=1)) print (cm) # Realizacion de la matriz de confusion: cm_df = pd.DataFrame(cm,index = ['alegria','enfado','relajado','tristeza'], columns = ['alegria','enfado','relajado','tristeza']) plt.figure(figsize=(9,7)) sns.heatmap(cm_df, annot=True) plt.title(u'Matriz de confusión de los sentimientos:') plt.ylabel(u'Valor real') plt.xlabel(u'Valor predicho') print ('Accuracy Score :',accuracy_score(Y_test.argmax(axis=1), y_predict.argmax(axis=1))) print ('Report : ') print (classification_report(Y_test.argmax(axis=1), y_predict.argmax(axis=1), target_names=['alegria','enfado','relajado','tristeza'])) plt.show() 8_Red_Neuronal_Multicapas_Tanh #!/usr/bin/env python # coding: utf-8 96