scieee AI-readable full text Open interactive document viewer

Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural

Quintana Sánchez, Diego

Abstract

Desde hace algunos años, se ha podido observar una tendencia en alza de hacer uso de modelos de IA y machine learning para la resolución de numerosas tareas en campos tan complejos y difusos como podría ser el procesamiento de imágenes o lenguaje natural. En el caso del procesamiento del lenguaje natural, el machine learning, y concretamente el uso de las redes neuronales ha provocado una absoluta revolución en el campo, obteniendo resultados tan increíbles que en algunos casos llegan a superar la pericia de un ser humano real. En este trabajo se ha buscado implementar un modelo capaz de detectar, para una premisa y una hipótesis dada, la relación semántica que existe entre ellas (relacionada, neutral o contradictoria). El dataset utilizado para entrenar nuestro modelo es ofrecido por Kaggle en su competición “Contradictoy My Dear Watson” y está formado por numerosos ejemplos de hipótesis y premisas en 15 lenguajes diferentes, aunque nosotros nos centramos en el inglés. Durante el trabajo hemos desarrollado de cero un modelo imitando la arquitectura y el proceso de entrenamiento de BERT. El rendimiento de nuestro modelo solo alcanzo el 46% de exactitud, por ello se hizo uso de un modelo ya pre-entrenado mucho más potente, RoBERTa, para poder terminar de comprender la increíble capacidad que poseen este tipo de redes neuronales, consiguiendo un 84% de exactitud.

Full text

Equation Chapter 1 Section 1 Proyecto Fin de Carrera Ingeniería de Telecomunicación Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Autor: Diego Quintana Sánchez 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, 2023 iii Proyecto Fin de Carrera Ingeniería de Telecomunicación Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Autor: Diego Quintana Sánchez 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, 2023 v Proyecto Fin de Carrera: Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Autor: Diego Quintana Sánchez Tutor: Francisco José Simois Tirado El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2023 El Secretario del Tribunal vii A mi familia A mis maestros ix AGRADECIMIENTOS Primero que todo, a mis queridos padres, Avelino y Sonia. Les quiero agradecer su apoyo, tanto emocional como financiero, que ha sido el pilar que me ha permitido llegar hasta el punto en el que me encuentro ahora. Vuestra confianza en mí y vuestro amor incondicional han sido mi mayor motivación y fuente de fortaleza. No puedo agradecerles lo suficiente todo lo que han hecho por mí y principalmente, agradecerles haberme enseñado que las cosas no llueven del cielo, que todo hay que ganárselo con el esfuerzo de uno mismo, a quedarme con lo bueno y a aprender de lo malo. Gracias por todo. Agradecer también a mi tutor Francisco José Simois por abrirme las puertas de un campo tan pionero y apasionante como son las redes neuronales y el machine learning, así como agradecerle la ayuda y guía a la hora de realizar el trabajo, sobre todo con la redacción de este documento. También agradecerle su apoyo durante todos estos años a mi pareja Marina, por haber estado siempre a mi lado, por haberme acompañado durante los buenos momentos y sobre todo, por apoyarme en las dificultades. Finalmente agradecerle a mi amigo Martine el haberme acompañado durante todos estos años de carrera y de vida, por esos descansos entre clase de risas bajo el puente de los laboratorios y por esas tardes de estudio intensivo donde pensábamos que no había final, por estar siempre. Muchísimas gracias por todo. Diego Quintana Sánchez Sevilla, 2023 xvii ÍNDICE DE TABLAS Tabla 4-1. Etiquetas de clases dataset fine-tuning 27 Tabla 5-1. Parámetros del pre-entrenamiento 38 Tabla 5-2. Resumen parámetros generales fine-tuning 45 Tabla 5-3. Parámetros fine-tuning modelo clasificador RoBERTa 51 xix ÍNDICE DE FIGURAS Figura 2-1. Comparativa Programación Clásica vs Machine Learning 4 Figura 2-2. Comparativa Shallow vs Deep Learning 5 Figura 2-3. Esquema de la arquitectura de una red neuronal 5 Figura 2-4. Funcionamiento de la neurona artificial 6 Figura 2-5. Funciones de activación más comunes 7 Figura 2-6. Posibles comportamientos de una red neuronal 11 Figura 2-7. Funcionamiento del dropout 11 Figura 2-8. Matriz de confusión clasificador binario 12 Figura 3-1. Ejemplo de pre-procesamiento de una frase 12 Figura 3-2. Tokenizado de una frase 12 Figura 3-3. Ejemplo de postprocesamiento de una frase 13 Figura 3-4. Vectorización de los tokens que conforman una frase 13 Figura 3-5. Comparativa dense vs sparse vector 14 Figura 3-6. Celda LSTM 15 Figura 3-7. Operación de convolución 17 Figura 3-8. Operación de pooling 17 Figura 3-9. Esquema Transformer [29] 18 Figura 3-10. Scaled Dot-Product Attention y Multi-Head Attention [29] 19 Figura 3-11. Masking de una frase 21 Figura 3-12. Creación de pares para NSP 22 Figura 3-13. Predicción de siguiente token 23 Figura 4-1. Lenguajes de programación más utilizados para ML. Kaggle 2022. 25 Figura 4-2. Frameworks más utilizados para ML. Kaggle 2022. 25 Figura 4-3. Comparativa de idiomas en el dataset para el fine-tuning 27 Figura 4-4. Clasificación de los distintos ejemplos en ingles en el dataset para el fine-tuning 28 Figura 4-5. Esquema de nuestro modelo 32 Figura 4-6. Resumen de capas y parámetros del modelo 33 Figura 5-1. Proceso de pre-entrenamiento 38 Figura 5-2. Matriz de confusión NSP 39 Figura 5-3. Predicción de tokens enmascarados del modelo pre-entrenado. 39 Figura 5-4. Modelo clasificador 44 Figura 5-5. Resumen de capas y parámetros del modelo clasificador 44 Figura 5-6. Proceso de fine-tuning 46 Figura 5-7. Grafica comparativa de la exactitud 46 Figura 5-8. Grafica comparativa de la pérdida 47 Figura 5-9. Matriz de confusión fine-tuning 48 Figura 5-10. Estructura del modelo clasificador con RoBERTa 50 Figura 5-11. Resumen parámetros del modelo clasificador con RoBERTa 50 Figura 5-12. Proceso de entrenamiento para el fine-tuning de RoBERTa 52 Figura 5-13. Grafica comparativa exactitud en validación frente a entrenamiento de RoBERTa 53 Figura 5-14. Grafica comparativa perdida en validación frente a entrenamiento de RoBERTa 53 Figura 5-15. Matriz de confusión fine-tuning RoBERTa 54 xxi ÍNDICE DE ECUACIONES Ecuación 2-1. Salida de una neurona artificial 6 Ecuación 2-2. Salida de una capa de una red neuronal 7 Ecuación 2-3. Función de una red neuronal 7 Ecuación 2-4. Optimización por descenso de gradiente 8 Ecuación 2-5. Mapeado de la función de coste a sus parámetros 8 Ecuación 2-6. Derivada parcial de la función de coste respecto a la salida de la red. 8 Ecuación 2-7. Derivada parcial de la salida de la red respecto a la salida de la capa 2 9 Ecuación 2-8. Derivada parcial de la salida de la red respecto a la salida de la capa 1 9 Ecuación 2-9. Gradiente de la función de coste 9 Ecuación 2-10. Derivada parcial de la salida de una capa respecto de sus parámetros 9 Ecuación 2-11. Regularización L1 11 Ecuación 2-12. Regularización L2 11 Ecuación 2-13. Precisión en clasificador binario 12 Ecuación 2-14. Recall en clasificador binario 12 Ecuación 2-15. Exactitud en clasificador binario 13 Ecuación 2-16. F1 13 Ecuación 3-1. Ecuaciones de celda LSTM 16 Ecuación 3-2. Cálculo de attention weights 18 Ecuación 3-3. Cálculo de la matriz de atención 19 Ecuación 3-4. Vector de posición 19 Ecuación 5-1. Función de entropía cruzada para C clases 36 xxiii ÍNDICE DE CÓDIGOS Código 4-1. Creación y entrenamiento del tokenizer 30 Código 4-2. Creación de nuestro modelo 31 Código 5-1. Creamos y compilamos el modelo en la TPU 35 Código 5-2. Pre-entrenamiento del modelo 37 Código 5-3. Pre-procesamiento del dataset para el fine-tuning 41 Código 5-4. Función para crear modelo clasificador 42 Código 5-5. Creamos y compilamos el modelo clasificador en la TPU 43 Código 5-6. Fine-tuning del modelo 45 Código 5-7. Descargamos RoBerta, cargamos y compilamos en la TPU 49 Código 5-8. Fine-tuning de modelo clasificador RoBERTa 52 Código 0-1. Descargamos e importamos librerías 61 Código 0-2. Montamos Drive en nuestro entorno Colab 61 Código 0-3. Obtenemos el dataset para el pre-entreno 61 Código 0-4. Cargamos dataset fine-tuning 62 Código 0-5. Filtrado dataset para entrenar tokenizer 62 Código 0-6. Clase CustomDataset 64 Código 0-7. Función para generar vector de posición 64 Código 0-8. Función para crear encoder del transformer 65 Código 0-9. Clase BertLikeModel 65 Código 0-10. Callback evaluación predicción de tokens pre-entreno 66 Código 0-11. Función para crear matriz de confusión tarea NSP 67 Código 0-12. Función para evaluar predicciones tokens enmascarados 68 Código 0-13. Función para mostrar graficas comparativas 68 Código 0-14. Función para crear matriz confusión fine-tuning 69 Código 0-15. Función para crear matriz de confusión fine-tuning RoBERTa 70 1 1 INTRODUCCIÓN 1.1 Estructura de la Memoria El documento va a estar dividido en los siguientes apartados: • Apartado 1. Introducción: se corresponde con el actual apartado, se mostrará un resumen del contenido de cada apartado y se dará una breve descripción de la motivación y el objetivo de este trabajo. • Apartado 2. Inteligencia Artificial: el objetivo es proporcionar un contexto acerca de la IA y el aprendizaje máquina, así como una breve introducción a las redes neuronales que nos permitan comprender como funcionan las mismas. • Apartado 3. Procesamiento del Lenguaje Natural: se ofrecerá una breve descripción del campo del NLP y se introducirán las topologías de redes neuronales, así como las diferentes técnicas que se utilizan en esta disciplina. Adicionalmente se hará un breve repaso de algunos de los modelos de redes neuronales del estado del arte en NLP. • Apartado 4. Método Propuesto: se propondrá un entorno de trabajo y una arquitectura de red neuronal que sea capaz de extraer relaciones semánticas del lenguaje y posteriormente hacer uso de dichas relaciones para clasificar dos pares de frases. • Apartado 5. Pre-entrenamiento y Fine-tuning: se relatará como ha sido todo el proceso de preentrenamiento de nuestro modelo y se hará un análisis de los resultados de este. Adicionalmente se realizará un traspaso de conocimientos para el fine-tuning de nuestro modelo en la tarea propuesta por el desafío “Contradictory My Dear Watson” de Kaggle y se analizarán los resultados en dicha tarea. Finalmente realizaremos este mismo fine-tuning pero con el modelo pre-entrenado RoBERTa para comparar los resultados. • Apartado 6. Conclusiones y Futuros Pasos: se extraerán conclusiones de todo el trabajo realizado y se propondrán futuras metas que conseguir y los posibles pasos que se necesitarán para conseguirlas. 1.2 Motivación El humano es un ser social, lo que quiere decir que tenemos una necesidad inherente de interactuar y relacionarnos con otros individuos, además de depender unos de otros para satisfacer nuestras necesidades básicas y alcanzar metas comunes. En esta interrelación entre individuos tiene un papel fundamental la comunicación y es donde entra el juego el concepto de lenguaje natural. El lenguaje natural se refiere al sistema de comunicación utilizado por los seres humanos para expresar y transmitir información de manera verbal. Es el medio principal a través del cual nos comunicamos en nuestro día a día, tanto de forma oral como escrita. Además, el lenguaje natural es la base de muchas tecnologías de procesamiento del lenguaje natural (NLP, por sus siglas en inglés), que buscan desarrollar sistemas informáticos capaces de comprender, interpretar y generar lenguaje humano. Esto tiene un gran número de aplicaciones, como la creación de asistentes virtuales, sistemas de traducción automática, análisis de sentimientos, procesamiento de texto y muchas otras. Sin embargo, el NLP es un campo de investigación extremadamente extenso y complejo, que se puede incluso subdividir en otros subcampos, como podría ser el análisis, la traducción e incluso la generación de textos. Dado la increíble complejidad que abarca la comprensión del lenguaje natural para una máquina, surgen diversas ramas que aplicaran diferentes algoritmos y métodos para lograr estos objetivos e incluso cooperarán entre ellas, como podría ser la estadística y el modelado probabilístico, la ingeniería de características o el machine learning. Teniendo esto en cuenta, es interesante profundizar en la forma que usan las personas para comunicarse con las Inteligencia Artificial 8 función es fiable entorno al punto en el que lo calculamos) que nos dará como resultado un punto en el que el valor de la función es ligeramente menor que el anterior, así sucesivamente hasta lograr encontrar ese punto en el que la función tiene el valor mínimo. 𝑊𝑡+1=𝑊𝑡−𝛼∗∇𝐶(𝑊𝑡) Ecuación 2-4. Optimización por descenso de gradiente Siendo 𝑾𝒕 el valor de los pesos del modelo en el instante t, 𝜶 es el learning rate y 𝛁𝑪(𝑾𝒕) el gradiente de la función en 𝑾𝒕 . 𝑾𝒕+𝟏 es el nuevo valor de los pesos calculados para el que la función es menor. La función utilizada para optimizar el valor de estos parámetros se conoce como función de pérdida. La función de pérdida es una función que calcula la diferencia entre el resultado deseado y el resultado obtenido por el modelo para unos datos determinados. Dado que el resultado del modelo depende únicamente del valor de sus pesos, ya que tanto los datos como el resultado de ejemplo que se quiere obtener son constantes, es posible mapear esta función a otra que dependa únicamente de los pesos del modelo. 𝐶(𝑦,𝑖𝑛𝑝𝑢𝑡,𝑊)=𝑙𝑜𝑠𝑠(𝑓𝑟𝑒𝑑𝑛𝑒𝑢𝑟𝑜𝑛𝑎𝑙(𝑖𝑛𝑝𝑢𝑡,𝑊),𝑦)≡𝐶(𝑊) Ecuación 2-5. Mapeado de la función de coste a sus parámetros Siendo x la salida de la red neuronal (resultado real) e y el resultado esperado (etiqueta), loss hace referencia a la función de pérdida utilizada para optimizar los parámetros de la red y C la función de coste final. Como ya hemos dicho, un modelo lo podemos ver como una función anidada compuesta de otras funciones diferenciables, y no solo eso, sino que son funciones diferenciables cuyas derivadas son conocidas. Por lo que gracias a la regla de la cadena podemos encontrar el gradiente de la función de toda la red neuronal. Aquí es donde entra en juego el algoritmo de backpropagation. El algoritmo de backpropagation, (Rumelhart et al. [11] (1986)), calcula los gradientes de la red neuronal haciendo uso de la regla de la cadena, calculando las derivadas parciales de las capas inferiores de la red y va ascendiendo a las capas superiores utilizando las derivadas parciales calculadas con anterioridad. Posteriormente se hace uso de este gradiente de la red neuronal para optimizar todos sus parámetros de manera conjunta. A la hora de calcular este gradiente el algoritmo tiene en cuenta la importancia de cada uno de los parámetros sobre la función de pérdida y se actualizarán cada uno de manera correspondiente. Así es como toda la red se optimiza para realizar la tarea para la que ha sido entrenada, es decir, así es como aprende la red neuronal. Existen y se utilizan diversas versiones mejoradas del algoritmo de optimización por descenso de gradiente que reciben el nombre de optimizers, es decir, el algoritmo que optimiza los pesos del modelo (Ruder [12] (2016)). Para una red FF de 3 capas el algoritmo de backpropagation calcularía las derivadas parciales de la red neuronal haciendo uso de la regla de la cadena de la siguiente forma. (Mazur [13] (2015)). 1º. Derivada parcial de la función de pérdida respecto de la salida de la red. Donde 𝑨𝒙 hace referencia a la función de activación en la capa correspondiente. 𝜕𝐶 𝜕𝑂𝑢𝑡𝑝𝑢𝑡=𝜕𝐿𝑜𝑠𝑠 𝜕𝐴𝑜𝑢𝑡𝑝𝑢𝑡∗𝜕𝐴𝑜𝑢𝑡𝑝𝑢𝑡 𝜕𝑂𝑢𝑡𝑝𝑢𝑡 Ecuación 2-6. Derivada parcial de la función de coste respecto a la salida de la red. 2º. Derivada parcial de la función de pérdida respecto de la salida de la segunda capa de la red. 9 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural 𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟2=𝜕𝐶 𝜕𝑂𝑢𝑡𝑝𝑢𝑡∗𝜕𝑂𝑢𝑡𝑝𝑢𝑡 𝜕𝐴𝐿𝑎𝑦𝑒𝑟2∗𝜕𝐴𝐿𝑎𝑦𝑒𝑟2 𝜕𝐿𝑎𝑦𝑒𝑟2 Ecuación 2-7. Derivada parcial de la salida de la red respecto a la salida de la capa 2 3º. Derivada parcial de la función de pérdida respecto de la salida de la primera capa de la red. 𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟1=𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟2∗𝜕𝐿𝑎𝑦𝑒𝑟2 𝜕𝐴𝐿𝑎𝑦𝑒𝑟1∗𝜕𝐴𝐿𝑎𝑦𝑒𝑟1 𝜕𝐿𝑎𝑦𝑒𝑟1 Ecuación 2-8. Derivada parcial de la salida de la red respecto a la salida de la capa 1 4º. Finalmente ya podemos calcular el gradiente de la función de pérdida respecto de W, siendo W el conjunto total de los parámetros o pesos que conforman la red. ∇𝐶(𝑊)=( 𝜕𝐶 𝜕𝑂𝑢𝑡𝑝𝑢𝑡,𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟2,𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟1) Ecuación 2-9. Gradiente de la función de coste Para calcular el valor de los parámetros de cada capa haríamos lo siguiente: 𝜕𝐶 𝜕𝑊𝑖= 𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟𝑖∗𝜕𝐿𝑎𝑦𝑒𝑟𝑖 𝜕𝑊𝑖 y 𝜕𝐶 𝜕𝐵𝑖= 𝜕𝐶 𝜕𝐿𝑎𝑦𝑒𝑟𝑖∗𝜕𝐿𝑎𝑦𝑒𝑟𝑖 𝜕𝐵𝑖 Ecuación 2-10. Derivada parcial de la salida de una capa respecto de sus parámetros Donde 𝑾𝒊 y 𝑩𝒊 hacen referencia a los pesos y al bias. Sin embargo, por la forma de funcionamiento del algoritmo de backpropagation encontramos dos problemas de las redes neuronales (cuanto más grande es la red más tiende a sufrir estos problemas) que es necesario solucionar, el desvanecimiento y la explosión de gradiente. De hecho, son 2 problemas que provocan que el modelo aprenda de manera incorrecta o no aprenda, pero su origen es el contrario. El desvanecimiento de gradiente ocurre cuando el gradiente que calculamos es tan pequeño que no es capaz de modificar lo suficiente los parámetros del modelo para que aprenda de manera efectiva, o siquiera que aprenda. Esto ocurre como consecuencia de la forma en el que el algoritmo de backpropagation calcula los gradientes (con la regla de la cadena empezando por las capas inferiores), por lo tanto, si los gradientes de las capas previas tienen valores pequeños, los valores calculados a partir de estos valores van decreciendo de manera exponencial según subimos por la topología de la red neuronal. Es decir, provoca que las capas más superiores no sean capaces o que aprendan muy lento. La explosión de gradiente ocurre cuando el algoritmo de backpropagation calcula los gradientes del modelo, y estos gradientes alcanzan valores muy elevados, lo que da lugar a que los pesos del modelo se actualicen de manera muy brusca, lo que provoca un aprendizaje inestable. El origen de estos valores tan elevados es el mismo que en el desvanecimiento de gradiente. Si los gradientes calculados previamente tienen valores elevados estos valores se van acumulando hasta dar lugar a valores tan elevados que causen overflow e imposibiliten o que inestabilizan el aprendizaje de la red. Ambos problemas se solucionan o mitigan utilizando funciones de activación apropiadas en el caso del desvanecimiento de gradiente, y de la normalización L1 y L2 o el gradient clipping en el caso de la explosión de gradiente. (Géron [14] (2019)). Inteligencia Artificial 10 Función de Pérdida La función de pérdida es la encargada de proporcionar al modelo una referencia de su desempeño al realizar la tarea para la que está siendo entrenado. Esta función es escogida por el ser humano y debe ser precisa a la hora de indicar al modelo el rendimiento de este sobre la tarea realizada. Una mala función de pérdida provocaría que nuestro modelo sea incapaz de aprender a realizar dicha tarea o que el modelo realice esta tarea, pero con un efecto secundario no deseado por falta de especificidad en la misma. El ser humano es el que debe de definir una función de pérdida lo más precisa posible para enseñar al modelo de forma óptima, por lo que para cada tarea sería necesario una función de pérdida concreta, que sería inservible para enseñar al modelo a realizar cualquier otra tarea de diferente naturaleza. Por ejemplo, para clasificación se utiliza una función de pérdida y para regresión otra distinta, incluso dependiendo de la naturaleza del problema de clasificación puede ser necesario utilizar diferentes funciones de pérdida. (Brownlee [15] (2021)) Comportamiento Durante el proceso de entrenamiento, nuestro modelo o red neuronal lo que hará es adaptarse a los ejemplos optimizando sus parámetros al efecto. Existen múltiples elementos que influyen en el resultado del entrenamiento, como son la función de pérdida elegida, la topología de la red o los ejemplos con los que enseñamos a nuestro modelo. Mientras entrenamos a nuestro modelo y una vez este ha sido entrenado, será necesario evaluar el resultado de su aprendizaje. Cuando entrenamos a nuestro modelo podemos encontrar varios tipos de comportamiento dependiendo del rendimiento del modelo sobre los datos de entrenamiento y sobre nuevos datos nunca vistos. Puede darse el caso que nuestro modelo sea incapaz de predecir correctamente los resultados deseados con los datos de entrenamiento, esto es debido a que el modelo es incapaz de encontrar las relaciones de estos datos de entrada con los resultados deseados. Este fenómeno se conoce como underfitting y puede deberse a que nuestra red es muy simple para la tarea, la función de pérdida no es adecuada o los datos no son lo suficientemente complejos o informativos respecto a la tarea en cuestión. También puede ocurrir que se aprenda demasiado de estos datos de entrenamiento, de tal manera que su rendimiento a la hora de trabajar con datos que ya ha visto antes sería excepcional, pero a la hora de procesar nuevos datos el modelo rinde pobremente. Esto ocurre porque el modelo solo puede optimizarse/aprender en base a los datos de ejemplo o training set, puede darse el caso que el modelo encuentre el estado óptimo para tratar estos ejemplos y sea muy preciso con dichos ejemplos, pero incapaz de procesar correctamente nueva información, pues se ha especializado demasiado o en otras palabras no tiene generalización. Este fenómeno se conoce como overfitting y puede ocurrir con un número de ejemplos reducidos pero muy caracterizados o por que el modelo es muy complejo para la tarea. Por último, y este es el objetivo de entrenar a nuestro modelo, puede darse el caso que nuestro modelo sea capaz de aprender perfectamente de los datos de entrenamiento y que también logre realizar la tarea para la que fue entrenado con nuevos datos nunca antes vistos. En la Figura 2-6 tenemos un ejemplo de los distintos comportamientos posibles. 11 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Figura 2-6. Posibles comportamientos de una red neuronal Evitar el underfitting es relativamente sencillo y lo podemos lograr aumentando la complejidad de nuestro modelo o realizando un mejor feature engineering sobre los datos de entrada. Para evitar el overfitting también podemos reducir la complejidad del modelo, obtener más datos de ejemplo o reducir la dimensión de sus representaciones, pero también surgen técnicas de regularización, como la L1 y L2 regularization (modificar la función de pérdida añadiendo un nuevo parámetro que penaliza la complejidad del modelo, Friedman et al. [16] (2010)) o el dropout (establecer a 0 de manera aleatoria algunos valores del vector resultado de un layer, Srivastava et al. [17] (2014)). Figura 2-7. Funcionamiento del dropout 𝑳𝟏 𝑹𝒆𝒈.≡ 𝒍𝒐𝒔𝒔(𝒙,𝒚)+ 𝜶∗∑|𝑾| Ecuación 2-11. Regularización L1 𝑳𝟐 𝑹𝒆𝒈.≡ 𝒍𝒐𝒔𝒔(𝒙,𝒚)+ 𝜶∗∑|𝑾|𝟐 Ecuación 2-12. Regularización L2 Siendo x el resultado, y el resultado deseado, loss la función de pérdida, 𝜶 un factor de reducción y W todos los pesos de la red neuronal. Evaluación del Modelo El modelo optimiza su rendimiento atendiendo a la función de pérdida y el ser humano evalúa el rendimiento de un modelo basándose en 2 elementos fundamentales, un conjunto de datos nunca visto por el modelo, también llamado testset y un valor o función que nos permita evaluar su rendimiento sobre estos nuevos datos, también Inteligencia Artificial 12 llamado metric o métrica. Es decir, conocer si ha alcanzado un buen nivel de generalización. Existen un gran número de métricas que podemos usar y que se adaptan a la tarea que queremos que nuestro modelo realice. Al igual que con la función de pérdida, la métrica va a depender de la naturaleza de la tarea, para la regresión por ejemplo nos basta con medir la diferencia entre el valor obtenido y el valor esperado para evaluar el rendimiento, con la tarea de clasificación la cosa es más complicada, y es donde entran en juego el concepto de la matriz de confusión, (Narkhede [18] (2021)), que permite calcular y obtener métricas muy importantes para evaluar la capacidad de nuestro modelo para clasificar ejemplos. En la Figura 2-8 podemos observar la matriz de confusión de un clasificador binario. Donde TP y TN hacen referencia a los verdaderos positivos y verdaderos negativos respectivamente (el modelo ha predicho correctamente la etiqueta) y FP y FN hacen referencia a los falsos positivos y falsos negativos (el modelo ha predicho la etiqueta opuesta). Figura 2-8. Matriz de confusión clasificador binario Algunas de las métricas más utilizadas y extraídas de la matriz de confusión son: • Precisión: mide la proporción de positivos reales acertados entre el total de positivos, útil en tareas en las que un falso positivo es un problema grande, como en los sistemas de detección de intrusión en redes o IDS. 𝑷𝒓𝒆𝒄𝒊𝒔𝒊ó𝒏= 𝑇𝑃 𝑇𝑃+𝐹𝑃 Ecuación 2-13. Precisión en clasificador binario • Recall: mide la proporción de positivos reales que son correctamente identificados, se utiliza en tareas en las que un falso negativo puede acarrear consecuencias graves como en la detección de enfermedades. 𝑹𝒆𝒄𝒂𝒍𝒍= 𝑇𝑃 𝑇𝑃+𝐹𝑁 Ecuación 2-14. Recall en clasificador binario • Exactitud: como su propio nombre indica mide la exactitud del modelo, es decir el número de veces que acierta. Se ha de destacar que es una métrica útil en el caso en el que las clases estén balanceadas, 13 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural es decir que el número de ejemplo sea similar entre las clases. En el caso de que no sea así puede dar lugar a una falsa sensación de éxito. 𝑬𝒙𝒂𝒄𝒕𝒊𝒕𝒖𝒅= 𝑇𝑃+𝑇𝑁 𝑇𝑃+𝐹𝑃+𝑇𝑁+𝐹𝑁 Ecuación 2-15. Exactitud en clasificador binario • F1: es una métrica que combina la precisión y el recall. 𝑭𝟏= 2∗𝑃𝑟𝑒𝑐𝑖𝑠𝑖𝑜𝑛∗𝑅𝑒𝑐𝑎𝑙𝑙 𝑃𝑟𝑒𝑐𝑖𝑠𝑖𝑜𝑛+𝑅𝑒𝑐𝑎𝑙𝑙 Ecuación 2-16. F1 Se debe tener en cuenta que utilizar una sola de estas métricas para medir el rendimiento del modelo en una tarea con cierto nivel de complejidad puede dar lugar a una falsa sensación de éxito en los resultados, por ello generalmente se utilizan varias de estas métricas simultáneamente y en algunos casos incluso combinaciones de estas para obtener unos resultados menos sesgados. 11 3 PROCESAMIENTO DEL LENGUAJE NATURAL entro del deep learning conviven un gran número de campos de investigación como el análisis de audio o el procesado de imágenes. Uno de los que más está dando que hablar hoy en día debido a los increíbles avances que ha sufrido en los últimos años es el procesamiento del lenguaje natural o NLP (por sus siglas en inglés Natural Language Processing). El procesamiento del lenguaje natural abarca el desarrollo de algoritmos y modelos capaces de dar capacidad de entender, interpretar y generar lenguaje humano a las máquinas como si de un verdadero ser humano se tratase. Dentro del NLP participan y convergen diferentes disciplinas además del machine learning y las redes neuronales, como serían la estadística y el modelado probabilístico, la ingeniería de características o la teoría de la información. El NLP tiene un gran número de aplicaciones como podría ser la traducción entre idiomas, clasificación de textos, chatbots (máquinas especializadas en conversar) o incluso motores de búsqueda. El NLP ha revolucionado la forma en la que nos comunicamos con las máquinas haciendo su uso mucho más cómodo y accesible. 3.1 Herramientas para NLP Como podemos llegar a imaginar es una tarea extremadamente compleja que necesita hacer uso de herramientas y técnicas adicionales al deep learning para conseguir lograr estos objetivos. Dado que las redes neuronales trabajan con vectores numéricos y no con secuencias de palabras, en el procesamiento del lenguaje natural es fundamental tratar los textos para que sea más cómodo procesarlos a las redes neuronales. Para realizar esta tarea se hace uso del tokenizer, el elemento encargado de transformar estas secuencias de palabras para que el modelo pueda trabajar con ellas Tokenizer El tokenizer, (Manning et al. [19] (1999)), es la herramienta encargada de fragmentar el lenguaje natural en unidades más pequeñas que reciben el nombre de tokens. Estos tokens son generalmente palabras o fragmentos de palabras que se utilizan como entrada para las tareas de NLP. La tokenización del lenguaje natural es un paso fundamental ya que estandariza y normaliza el texto y hace más fácil al modelo trabajar con este tipo de información. Al igual que una red neuronal, estos tokenizers tienen su propia forma de aprender a partir de textos de ejemplo, de los que se encargan de extraer estos tokens atendiendo a un algoritmo concreto o unas reglas predefinidas y que dependen del tipo de tokenizer y de la tarea en la que vayamos a entrenar al modelo. Generalmente estos D Natural language processing is about understanding the meaning of human language, not just the form. - Dan Jurafsky - Procesamiento del Lenguaje Natural 12 12 textos de los que se extraen los tokens son los mismos que usaremos para entrenar nuestro modelo de lenguaje. Una vez entrenamos un tokenizer y entrenamos un modelo con los tokens extraídos, es necesario utilizar siempre este tokenizer para tokenizar los textos que usemos para entrenar a nuestro modelo. El tokenizer asocia a cada palabra o fragmento de palabra un identificador numérico, atendiendo a diversos criterios como la frecuencia en la que aparece la palabra en los textos con lo que lo entrenamos. Este número va a representar unívocamente una palabra, es lo que conocemos como token. Si cambiamos el tokenizer con el que tokenizamos los textos de entrenamiento a mitad del proceso, puede ocurrir que dos palabras diferentes tengan el mismo token o que la misma palabra tenga asignada un token diferente, lo que confundiría al modelo. Existen un gran número de diferentes algoritmos de tokenizado cada uno con sus propios procesos, aunque la mayoría tienen en común algunas fases. (Huggingface [20] (2021)). La primera fase es el pre-procesamiento o normalización, el objetivo de esta frase es homogeneizar y normalizar el texto para facilitar su conversión en tokens, algunas transformaciones usadas frecuentemente es el lower casing (todas las letras en minúsculas), la eliminación de caracteres especiales y la eliminación de acentos. Tenemos un ejemplo en la Figura 3-1. Figura 3-1. Ejemplo de pre-procesamiento de una frase La segunda fase es el tokenizado, en esta fase es en la que se fragmenta el lenguaje natural en tokens, esta fragmentación se puede realizar atendiendo a un gran número de criterios que dependen del tipo de tokenizado que queramos y las exigencias de la tarea para la que entrenaremos a nuestro modelo. Algunos criterios podrían ser separar y tokenizar el texto por espacios y signos de puntuación y otros por patrones de letras o hasta incluso por caracteres. En la Figura 3-2 podemos observar un ejemplo. Figura 3-2. Tokenizado de una frase Finalmente, el postprocesado, una vez el texto ha sido tokenizado, aún podemos realizar alguna transformación más para refinar aún más los ejemplos antes de entrenar a nuestro modelo. Algunas herramientas muy utilizadas en esta fase son el padding o el truncado, que consiste en añadir relleno (tokens especiales sin valor informativo) o eliminar valores de la secuencia de tokens para alargarlas o recortarlas, respectivamente, y normalizar la longitud de las mismas. También es común incluir tokens especiales que ayuden al modelo a diferenciar cada frase, también llamado sentence segmentation, como el token de inicio de frase o el de fin de frase. En la Figura 13 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural 3-3 encontramos un ejemplo. Figura 3-3. Ejemplo de postprocesamiento de una frase En resumen, el tokenizado es fundamental en el procesamiento del lenguaje natural ya que permite a las redes neuronales procesar y extraer información de los datos de ejemplo que le ayuden a identificar patrones y relaciones en el lenguaje natural relevantes para la tarea en la que va a ser entrenado. A pesar de que el tokenizer ayuda enormemente a el modelo a procesar el lenguaje natural, aún tiene que enfrentarse a problemas derivados de la necesidad de tratar este tipo de información, algunos de los más comunes serían la ambigüedad (palabras con diferente significado, pero misma morfología), palabras fuera del vocabulario o la contextualización. Encoding Esta secuencia de tokens, aunque ya son valores numéricos que una red neuronal puede procesar, son muy poco informativos. Es necesario darle una representación más refinada a estos tokens que le permita al modelo extraer relaciones complejas, es decir necesitamos caracterizar estos tokens para darles un conjunto de atributos que en cierto modo los describan. (Jurafsky et al. [21] (2019)). Esta caracterización puede hacerse a mano, es decir, es el ser humano el que se encarga de extraer características representativas de las palabras, por ejemplo, si es negativa o positiva, femenina o masculina, singular o plural… de tal forma que el modelo pueda utilizar estas representaciones más complejas para darle un “significado” a los tokens que le ayude a procesar mejor la información. Sin embargo, esta tarea de feature engineering es bastante compleja, por lo que se prefiere y se intenta hacer uso del deep learning para que sea el propio modelo el que convierta estos tokens en representaciones mucho más complejas y que extraiga las características óptimas que le permitan describir y dar significado a cada token. Para construir estas representaciones más complejas de los tokens los convertimos en vectores, como se observa en la Figura 3-4, de tal manera que cada palabra o token es un punto representado en un espacio vectorial. Esta forma de representar las palabras para darles un significado se conoce como vector semantics. Figura 3-4. Vectorización de los tokens que conforman una frase Existen 2 tipos de vector semantics, los sparse vectors o los dense vectors. Los sparse vector son aquellos cuya dimensión es igual o mayor que el tamaño del vocabulario, como el one-hot encoding o las term-term matrix. Procesamiento del Lenguaje Natural 20 20 número pos de la secuencia. Este vector será la entrada de la capa multi-head attention, va a ser el mismo vector para los 3 elementos de entrada, es decir el vector query, value y key. Este tipo de attention mechanism se conoce como self-attention y se utiliza para extraer las relaciones e importancia que tienen el resto de las palabras del texto o frase sobre cada palabra, de tal manera que el modelo conozca qué tokens tienen mayor o menor relación con el resto de los tokens de la secuencia. La ventaja de este método es que conseguimos relaciones de alcance muy elevado de tal forma que es posible computar la relación entre cada una de las palabras sin verse especialmente afectada por la separación entre ellas dentro de la secuencia. Este vector va a ser procesado por una capa FF que transformará lineal e independientemente cada una de las posiciones con el mismo tipo de transformación. Se realizan dos transformaciones lineales con una función de activación RELU entre medias. Finalmente vamos a obtener unas representaciones complejas con un alto nivel informativo acerca del contexto y el significado de cada palabra. 3.4 Estado Del Arte Una vez tenemos una visión general, vamos a destacar algunos de los modelos que representan el Estado del Arte en el procesamiento del lenguaje natural hoy día, y vamos a profundizar en los diferentes layers y técnicas de procesamiento del lenguaje natural del que hacen uso para alcanzar un rendimiento excepcional en dichas tareas. Tareas NLP Existen diferentes tareas comúnmente utilizadas para evaluar el rendimiento de un modelo NLP. La tarea específica usada dependerá del tipo de modelo NLP y la aplicación que le queramos dar, sin embargo, estas son algunas de las tareas NLP más utilizadas: • Modelado de Lenguaje: consiste en predecir la similitud de una secuencia de palabras con otra dada. Se utiliza normalmente para el pre-entreno del modelo para otras tareas de NLP como clasificación de textos, análisis de sentimiento o traducción. • Clasificación de textos: consiste en asignar una categoría o etiqueta a un texto o fragmento de texto. Los ejemplos más comunes son análisis de sentimiento, clasificación por temas o detección de spam. • NER (por sus siglas en inglés Named Entity Recognition): consiste en la identificación de entidades como personas, organizaciones o sitios y lugares dentro del texto. • Etiquetado POS (por sus siglas en inglés Part-Of-Speech): consiste en asignar una categoría gramatical (adjetivo, verbo, sustantivo, pronombre…) a cada elemento del texto. • Traducción Máquina: como su propio nombre indica consiste en traducir textos de un idioma a otro. • Respuesta a Preguntas: consiste en responder a preguntas formuladas en lenguaje natural basándose normalmente en un contexto o temática. • Resumen de textos: consiste en resumir un texto de mayor tamaño manteniendo la intencionalidad y mensaje original de la forma más compacta posible. • Generación de lenguaje: consiste en generar textos en lenguaje natural. Es el motor de sistemas como los chatbots y se usa también para completar textos e incluso para generar textos completos según una instrucción o promt. Adicionalmente a estas tareas existen numerosas métricas de evaluación usadas frecuentemente para medir el rendimiento de los modelos NLP. Además de las métricas más clásicas como precisión, exactitud o F1, algunos ejemplos serían la BLEU score, ROUGE score y métricas basadas en la perplejidad. (Kumar et al. [31] (2019)). Junto con estas métricas y tareas surgen un conjunto de pruebas diseñadas para probar la eficacia de los modelos en las diferentes tareas mencionadas y proporcionar un resultado que permite medir el rendimiento general del 21 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural modelo, esto es lo que se conoce como los benchmarks. El objetivo es la posibilidad de comparar el rendimiento de los diferentes modelos en las distintas tareas y proporcionar un indicador del estado actual del campo del NLP. Algunos de los benchmarks más utilizados y lo que se encargan de medir: • GLUE (General Language Understanding Evaluation): como su nombre indica es un benchmark muy general en el que se mide el rendimiento en tareas como el análisis de sentimientos, la clasificación de textos o las respuestas a preguntas (Wang et al. [32] (2018)). Existe la versión extendida conocida como superGLUE (Wang et al. [33] (2019)). • SQuAD (Stanford Question Answering Dataset): evalúa el rendimiento de los modelos en tareas de comprensión lectora. Es un conjunto de preguntas basadas en artículos de Wikipedia (Rajpurkar et al. [34] (2016)). • CoNLL: mide el rendimiento de los modelos en tareas de NER. • MNLI (Multi-Genre Natural Language Inference): evalúa el rendimiento del modelo en tareas de inferencia en el lenguaje natural, como por ejemplo determinar la relación entre dos frases (Williams et al. [35] (2018)). Modelos State of the Art 3.4.2.1 BERT BERT o Bidirectional Encoder Representations from Transformers, (Devlin et al. [36] (2019)), es un modelo de lenguaje pre-entrenado desarrollado por Google en 2018 capaz de crear complejas representaciones para diversas tareas del lenguaje natural como las introducidas en el apartado anterior y que hace uso de la estructura del transformer, en este caso solo hace uso del encoder, ya que no busca la generación de lenguaje sino el procesamiento y la extracción de características. Ha sido entrenado en una amplísima cantidad de información textual, como libros, artículos… haciendo uso de un tipo de aprendizaje no supervisado conocido como language modeling o modelado de lenguaje. Durante el entrenamiento, una determinada cantidad de los tokens que forman los textos van a ser sustituidos por un token especial conocido como mask, el objetivo será que el modelo prediga que token había originalmente en dicha posición haciendo uso del contexto otorgado por el resto de los tokens del texto o secuencia, esta técnica se conoce como masked language modeling (MLM) o modelado de lenguaje enmascarado. Tenemos un ejemplo gráfico en la Figura 3-11. Figura 3-11. Masking de una frase Adicionalmente es entrenado con otro tipo de aprendizaje semi-supervisado conocido como next sentence prediction (NSP) o predicción de siguiente frase, que consiste básicamente en predecir en un par de frases si la segunda es continuación o no de la primera. El objetivo es conseguir proporcionar al modelo un conocimiento general de las relaciones y significados de las palabras y estructuras que conforman el lenguaje natural. Como se puede observar en la Figura 3-12. Procesamiento del Lenguaje Natural 22 22 Figura 3-12. Creación de pares para NSP Una de las características más destacadas de BERT es que es un modelo de lenguaje bidireccional, lo que significa que a la hora de predecir los tokens tiene en cuenta tantos los tokens a la izquierda como a la derecha del token enmascarado, es decir, que hace uso de la secuencia completa. Esto ayuda al modelo a capturar el contexto y significado del texto o secuencia más eficientemente. BERT ha conseguido resultados de state of the art en numerosos campos del NLP y ha sido ampliamente adoptado tanto en la industria comercial como en el campo de la investigación. El objetivo fundamental de BERT es el procesamiento de textos para la extracción de características y posteriormente usar esta información para las diferentes tareas que existen en el campo del NLP. Actualmente existen un gran número de variaciones y modelos fine-tuned de BERT en la mayoría de las tareas, como podrían ser RoBERTa (Liu et al. [37] (2019)) o DeBERTa (He et al. [38] (2020)). 3.4.2.2 GPT GTP o Generative Pre-trained Transformer, (Radford et al. [39] (2018)), es un modelo de lenguaje natural desarrollado por OPEN AI capaz de generar información textual de alta calidad en un gran número de contextos y campos dentro del NLP. También hace uso de la estructura del transformer, en este caso tanto del encoder como del decoder, ya que, si es un modelo generativo, siendo uno de los más grandes que existen actualmente con un inmenso número de parámetros, lo que lo convierte en uno de los modelos NLP más potentes de la actualidad. Ha sido también entrenado en una inmensa cantidad de textos en este caso haciendo uso de otra técnica de aprendizaje no supervisado que consiste en predecir la siguiente palabra para una secuencia dada, lo que es útil para ayudar al modelo a comprender la estructura y funcionamiento del lenguaje natural. Hay que destacar que GTP es unidireccional y que solo tiene en cuenta los elementos previos de la secuencia a la hora de calcular la probabilidad del siguiente token. Como se muestra en la Figura 3-13. 23 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Figura 3-13. Predicción de siguiente token Una de las características más destacadas de GPT es su capacidad de llevar a cabo lo que se conoce como zeroshot o few-show learning, (Brown et al. [40] (2020)), esto consiste en la capacidad de generar información textual precisa en tareas o contextos en los que no ha sido o ha sido muy poco entrenado, convirtiéndolo en uno de los modelos NLP generativos más versátiles y siendo además capaz de lograr rendimientos excepcionales en la mayoría de las tareas de NLP. El objetivo fundamental de GPT es la generación de lenguaje natural coherente y lo más similar a un humano que sea posible para una petición o prompt dado o un contexto determinado. Actualmente está en su versión mejorada GPT 4.0 que además es multimodal, es decir que aceptara otros tipos de información de entrada diferente al texto, como podrían ser imágenes o videos. 3.4.2.3 ERNIE ERNIE o Enhanced Representation through Knowledge Integration, (Sun et al. [41] (2019)), es un conjunto de modelos de lenguaje pre-entrenados desarrollados por Baidu Research diseñados para integrar conocimientos de diferentes dominios y fuentes para mejorar su capacidad de entender y generar lenguaje natural. Al igual que GPT o BERT han sido entrenados en una inmensa cantidad de textos usando técnicas de aprendizaje no supervisados para posteriormente hacer fine-tuning en tareas más específicas del NLP. Lo que marca la diferencia con el resto de los modelos es su capacidad de aprender de diferentes fuentes de información como grafos o textos no estructurados. Esto permite que ERNIE sea capaz de capturar más eficientemente el contexto y significado del lenguaje y generar respuestas más precisas y relevantes. Método Propuesto 24 24 4 MÉTODO PROPUESTO ras esta introducción teórica acerca de la IA, el machine learning, las redes neuronales y la aplicación de estas en el campo del procesamiento del lenguaje natural, así como un breve vistazo a los modelos del estado del arte durante los dos anteriores capítulos, vamos a proponer un modelo de red neuronal que sea capaz de extraer las relaciones semánticas entre dos frases (una premisa y su consiguiente hipótesis) y determinar si la hipótesis es correcta, contradictoria o neutral. 4.1 Recursos Utilizados A continuación, se hará una breve descripción del material hardware y software utilizado para diseñar y entrenar a nuestro modelo. Hardware Como ya hemos visto, entrenar un modelo de machine learning es una tarea que dependiendo del tamaño y la complejidad del modelo puede requerir una gran capacidad de cálculo computacional. En nuestro caso, vamos a necesitar un modelo bastante complejo para la tarea en la que lo vamos a entrenar, la extracción de relaciones semánticas entre una hipótesis y una premisa, que no solo es una tarea complicada de por sí para una máquina, sino que puede llegar a ser complejo incluso para un ser humano real. A pesar de que un modelo de machine learning puede ser entrenado con una CPU común, esta no es especialmente eficiente pues no requerimos de cálculos complejos si no de un enorme número de operaciones sencillas, tarea en la que estas no rinden bien. Aquí es donde entran en juego las GPUs, hardware específicamente diseñado para resolver de manera simultánea un número muy elevado de operaciones, que, aunque no fueron diseñadas exactamente para entrenar redes neuronales si no más enfocadas a ejecución de gráficos en videojuego, diseño gráfico o animación 3D, se adaptan especialmente bien a la naturaleza del deep learning y que hasta los últimos años ha sido la herramienta más usada a la hora de entrenar los modelos. Dado que no disponemos de ningún equipo con una GPU lo suficientemente potente como para entrenar en un tiempo razonable, vamos a optar por la solución del hacer uso de un servicio alojado, en este caso de Google Colab. Google Colab es el servicio alojado de Google que permite la ejecución de código Python en el navegador sobre una máquina virtual dedicada, que da acceso a recursos como CPUs o GPUs y está basado en Jupyter. Cabe destacar que dado el reciente auge del machine learning y las redes neuronales, Google ha diseñado hardware específicamente optimizado para el entrenamiento de redes neuronales al que ha llamado TPUs (Tensor Procesor Units), que superan en rendimiento a las GPUs incluso con una menor cantidad de recursos. Dado que nos ofrecen tanto GPUs como TPUs para entrenar a nuestro modelo, nosotros lo entrenaremos con una TPU. Una ventaja adicional de entrenar a nuestro modelo sobre un servicio alojado es la disponibilidad de equipos con altas cantidades de memoria RAM, que también es muy útil a la hora de trabajar con mucha información de manera rápida. Puesto que el entrenamiento no se va a realizar sobre un equipo local y que las máquinas virtuales alojadas de Google Colab no tienen disponibilidad ilimitada, para almacenar nuestro modelo durante el proceso de entrenamiento vamos a utilizar Google Drive que es fácilmente integrable con Google Colab, también almacenaremos en Google Drive nuestro propio tokenizer. En resumen, el entrenamiento de nuestro modelo se va a realizar sobre una maquina alojada en los servidores de Google haciendo uso de su servicio Google Colab. Lenguaje de Programación Existe un gran número de lenguajes de programación que pueden ser utilizados para el deep learning, como C, Java, C++, JS, Matlab… pero los que más destacan tanto en el machine learning como en el data science, son Python y R. A continuación, un gráfico con los lenguajes más utilizados según la encuesta realizada en 2022 por T 25 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural la famosa plataforma de deep learning Kaggle en la Figura 4-1. Figura 4-1. Lenguajes de programación más utilizados para ML. Kaggle 2022. Como podemos ver Python se posiciona como el lenguaje preferido para el machine learning, compitiendo con otros como SQL o R. Dado que el entorno sobre el que vamos a entrenar a nuestro modelo está diseñado para trabajar con Python, no tenemos mucha capacidad de elección en ese sentido por lo que toda la programación se hará en un cuaderno de Google Colab que utiliza Python como lenguaje de programación. Framework Hay diversos frameworks disponibles para diseñar y entrenar modelos de redes neuronales, vamos a ver una comparativa de los frameworks más utilizados para machine learning y data science. A continuación, un gráfico en la Figura 4-2. Figura 4-2. Frameworks más utilizados para ML. Kaggle 2022. Como podemos ver, existen un gran número de alternativas entre las que podemos elegir, nosotros vamos a escoger Keras, que es un framework de código libre que hace uso de la librería y framework de bajo nivel TensorFlow. Fue creada por el ingeniero de Google François Chollet y está escrita en Python. La principal ventaja de Keras es la facilidad que ofrece a la hora de trabajar con vectores y operaciones matriciales, así como Método Propuesto 26 26 para diseñar y entrenar los modelos de machine learning gracias a su API de alto nivel, también he de destacar que la TPU que vamos a usar para entrenar a nuestro modelo esta específicamente optimizada para utilizar Keras, por lo que es la opción más óptima para diseñar y entrenar nuestro modelo. Librerías Adicionalmente a Keras como framework (que hace uso de la librería Tensorflow) vamos a hacer uso de algunas librerías adicionales más: • Pandas: librería para la manipulación y tratamiento de datos. Vamos a utilizarla únicamente para cargar uno de los datasets de los que haremos uso a la hora de entrenar a nuestro modelo. • Numpy: librería para el manejo de vectores y matrices. La vamos a utilizar múltiples veces para el manejo de matrices a lo largo del pre-procesamiento de los datos. • Tokenizers: librería específica para la creación y entrenamiento de los tokenizers. La utilizaremos para configurar y entrenar nuestro propio tokenizer desde 0. • Datasets: librería que facilita el acceso y la manipulación de los datasets con los que se entrenan a los modelos de machine learning. La utilizaremos para descargar otro dataset que necesitamos. Haciendo uso de estas herramientas junto con Keras, vamos a procesar la información de los datasets y a prepararla para que nuestro modelo puede trabajar con ella y aprender, así como a diseñar y a entrenar a nuestro modelo. 4.2 Datasets Para entrenar a nuestro modelo vamos a hacer uso de 2 datasets. El primer dataset lo vamos a utilizar para realizar el pre-entreno de nuestro modelo, es decir, va a ser un dataset no etiquetado para el aprendizaje no supervisado. El dataset que vamos a utilizar es Wikipedia-20220301 que consiste en textos en claro de todos los artículos de Wikipedia, en nuestro caso haremos uso únicamente de los escritos en inglés. El objetivo de esto es proporcionar al modelo un conocimiento general del lenguaje que posteriormente trasladaremos a una tarea más específica. Cada uno de los ejemplos contara con los siguientes campos: • ID: el identificador único del ejemplo • URL: dirección URL del artículo en cuestión • Title: título del articulo • Text: texto que compone el artículo. Nosotros vamos a hacer uso fundamentalmente de los textos que componen los artículos ya que no necesitamos darle gran importancia al título de este para la tarea en la que lo vamos a entrenar. En total van a ser 6.458.670 ejemplos o artículos, de los cuales algunos serán más útiles que otros que quizá sean demasiado cortos o carecen de información relevante para que nuestro modelo extraiga relaciones del lenguaje, que es el objetivo del preentreno con este dataset. Dado que es un dataset no etiquetado vamos a tener que hacer un pre-procesamiento de la información para adaptarla al método de entrenamiento que utilizaremos para pre-entrenar a nuestro modelo, pero esto lo detallaremos más adelante. Hemos elegido este dataset en inglés para el pre-entreno ya que es extremadamente extenso y contiene una gran cantidad de información que es mucho mayor al de resto de lenguajes disponibles, y que tras un poco de preprocesamiento podremos usar para que nuestro modelo comprenda mejor las características y relaciones del lenguaje natural en inglés. El segundo dataset, que utilizaremos para el fine-tuning de nuestro modelo en establecer la relación semántica 27 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural entre 2 frases, será el ofrecido por la plataforma Kaggle en su desafío “Contradictory, My Dear Watson”. Este desafío ofrece un dataset con un conjunto de 12.120 ejemplos clasificados de premisas e hipótesis en 15 idiomas y 3 clases diferentes: relacionadas, contradictorias o neutrales. Los ejemplos están formados por los siguientes campos: • ID: el identificador único del ejemplo • Premise: texto que compone la premisa • Hypothesis: texto que compone la hipótesis • Language: idioma de la premisa y de la hipótesis • Lang_abv: la abreviación del idioma • Label: clase en la que se incluye el ejemplo Vamos a profundizar un poco en el contenido del dataset. Comencemos por el número de ejemplos de cada idioma. A continuación, una gráfica comparativa en la figura 4-3. Figura 4-3. Comparativa de idiomas en el dataset para el fine-tuning Como podemos observar, el número de ejemplos en inglés es la mayor parte del dataset, siendo 6870 ejemplos en total. Es por ello por lo que nosotros nos vamos a enfocar solo en los ejemplos en inglés, ya que el pre-entreno de nuestro modelo se ha realizado en textos en inglés y puesto que componen la mayor parte del dataset vamos a descartar el resto de los idiomas para entrenar a nuestro modelo. Las clases en las que podemos clasificar cada ejemplo son las siguientes: Identificador Clase 0 Relacionada 1 Neutral 2 Contradictoria Tabla 4-1. Etiquetas de clases dataset fine-tuning Método Propuesto 28 28 Ahora, observemos el número de ejemplos de cada clase, para determinar si nos encontramos ante un dataset cuyas clases están balanceadas o no. Veamos cómo se han clasificado cada par de hipótesis y premisas de entre todos los ejemplos en inglés que componen el dataset. Ejemplo grafico en la Figura 4-4. Figura 4-4. Clasificación de los distintos ejemplos en ingles en el dataset para el fine-tuning Como podemos observar, si es un problema balanceado ya que aproximadamente tenemos el mismo número de ejemplos de cada clase. Ya tenemos una visión general de la información que vamos a usar en ambas fases del entrenamiento de nuestro modelo de lenguaje natural. 4.3 Diseño del Modelo A continuación, vamos a detallar el diseño que propondremos para la resolución de nuestra tarea objetivo y la forma que tendremos de implementarlo. Adicionalmente vamos a configurar e implementar nuestro propio tokenizer, que usaremos posteriormente para extraer los tokens con los que entrenaremos a nuestro modelo. El modelo que vamos a proponer va a seguir la arquitectura propuesta por Devlin et al. [36], aunque vamos a implementar un modelo bastante simplificado, ya que la complejidad de BERT es excesiva, y entrenar un modelo de esas características con los recursos de los que disponemos sería totalmente ineficiente ya que necesitaríamos demasiado tiempo. Es por ello por lo que nosotros vamos a simplificar su arquitectura haciendo uso de un único encoder (en vez de apilar 12 o 24 como en el modelo BERT original). El procedimiento que se ha seguido en la implementación del modelo es el siguiente: 1. Configuración y entrenamiento del tokenizer para la extracción de tokens con los que procesaremos los datasets para entrenar posteriormente a nuestro modelo. 2. Diseño de un modelo simplificado de la arquitectura propuesta por Devlin et al. [36]. 3. Pre-entrenamiento del modelo para obtener representaciones contextuales de los tokens, este preentreno consistirá en dos tareas: para la primera el modelo tendrá que adivinar que palabra ocupaba originalmente en la frase el lugar del token de mask y para la segunda el modelo tendrá que predecir, para un par de frases, si las frases son o no continuación una de la otra. 4. Fine-tuning del modelo, a partir de estas representaciones contextuales extraídas durante el pre-entreno, en la tarea objetivo propuesta por la competición “Contradictory My Dear Watson” de Kaggle. 29 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Instalación de Librerías y Obtención de los Datasets El primer paso que tomaremos será la instalación de las librerías que necesitaremos para procesar los datos, diseñar, entrenar y evaluar a nuestro modelo (Código 0-1). Adicionalmente, creamos una función para importar nuestro tokenizer, datasets y modelos entrenados o en proceso de entrenamiento desde Drive. Cargamos 3 carpetas, donde almacenaremos nuestros modelos, nuestros tokenizers y nuestro dataset. (Código 0-2). Descargamos el dataset para el pre-entreno haciendo uso de la librería Datasets. Después obtenemos los valores del dataset y comprobamos el número de ejemplos que lo forman. Que como se ha mencionado anteriormente son 6.458.670 artículos de Wikipedia en inglés (Código 0-3). Para el dataset del fine-tuning lo que haremos es descargarlo de la página de Kaggle, y cargarlo en nuestro Drive, para posteriormente subirlo en nuestro entorno virtual de Google Colab. Lo cargamos en memoria con el Código 0-4. Configuración y Entrenamiento del Tokenizer Ahora es momento de configurar y entrenar nuestro propio tokenizer que nos ayude a procesar la información textual para que sea más manejable por nuestro modelo. Lo primero que haremos es definir una función que procese y filtre los textos para entrenar a nuestro tokenizer con ellos. (Código 0-5). Lo que hacemos con esta función es dividir el texto en párrafos y comprobar que al menos cada párrafo tiene 30 palabras. Finalmente generamos una lista de párrafos, que será con los que entrenaremos nuestro tokenizer. Este filtrado del dataset se utilizará exclusivamente a la hora de entrenar el tokenizer para la extracción de tokens, el tokenizer posteriormente se encargará de tokenizar las frases con la que entrenaremos el modelo, no párrafos completos. Ahora vamos a configurar y entrenar nuestro tokenizer desde cero. Primero importamos el tipo de tokenizer que utilizaremos, en este caso va a ser un WordPiece tokenizer (Huggingface [42] (2021)). Después definimos los tokens especiales de los que haremos uso, en este caso será un token desconocido (el tokenizer lo usará si aparece una palabra que no se encuentra en el vocabulario), también definimos el token de mask para el pre-entreno, el token de padding y por último los tokens de sentence segmentation, el de inicio de frase o BOS y el de fin de frase o EOS, finalmente obtenemos el índice asociado a dichos tokens para usarlos más adelante. La manera de extraer tokens del WordPiece tokenizer consiste en dividir el texto en unidades más pequeñas basándose en la identificación de los patrones de caracteres más comunes. Comienza con caracteres individuales y poco a poco los unifica en secuencias de caracteres según los patrones que detecta más a menudo, que dan lugar finalmente a fragmentos de palabras y palabras completas. Definimos un trainer para entrenar nuestro tokenizer, vamos a utilizar un vocabulario de 25.000, es decir, el tokenizer identificara como máximo 25.000 tokens y extraemos una parte de nuestro dataset para el pre-entreno (no utilizamos todo el dataset porque tomaría demasiado tiempo y a partir de un determinado número de artículos tampoco va a detectar nuevo vocabulario). Antes de comenzar el entrenamiento, definimos el preprocesamiento, es decir, de que forma el tokenizer limpiara los textos antes de procesarlos (en este caso todo a minúscula, y eliminara los acentos y caracteres especiales) y finalmente entrenamos a nuestro tokenizer. Una vez finalizado el entrenamiento del tokenizer, definimos el postprocesado de cara al entrenamiento del modelo, cuando el tokenizer tenga que tokenizar los pares de frases (la primera frase comenzara con el token BOS y ambas finalizaran con el token EOS, adicionalmente, a los tokens correspondientes a la primera frase se les asociara el valor 1 y a los de la segunda el valor 2 para la creación del vector de frase). Establecemos el tamaño para el conjunto de las dos frases a 256 tokens, tanto para añadir padding como para truncar el par de frases. Finalmente guardamos nuestro tokenizer (Código 4-1). Pre-entreno y Fine-Tuning 36 36 Posteriormente con dichas predicciones calculamos el valor de la función de pérdida para cada tipo de aprendizaje, el lenguaje enmascarado y la predicción de continuación de frase, calculamos la pérdida total que en nuestro caso será la suma de ambas pérdidas y finalmente calculamos los gradientes de todas las variables entrenables del modelo, aplicamos los gradientes y actualizamos e imprimimos por pantalla las métricas (Código 0-9). Vamos a detallar las métricas y funciones de pérdidas elegidas para ambos tipos de aprendizaje. Para el aprendizaje por lenguaje enmascarado elegimos como función de pérdida la Sparse Categorical Crossentropy, esta función calcula la entropía cruzada entre la predicción y el resultado esperado para ejemplos en el que existen más de dos clases posibles y cada entidad solo puede tener una clase asignada (como es el caso del lenguaje enmascarado en el que hay tantas clases como palabras en el vocabulario) y la Binary Crossentropy, para la predicción de continuación de frase, que es igual pero cuando solamente existen dos clases posibles (en este caso, continuación o no de la primera frase). (Gómez [44] 2018). 𝐶𝑟𝑜𝑠𝑠 𝐸𝑛𝑡𝑟𝑜𝑝𝑦= −∑𝑙𝑖∗log (𝑝𝑖) 𝐶𝑖 Ecuación 5-1. Función de entropía cruzada para C clases Donde 𝑙𝑖 hace referencia a la etiqueta y 𝑝𝑖 hace referencia a la predicción para cada clase i dentro de C. La clasificación binaria es un caso concreto en el que C=2. Con respecto a las métricas para la monitorización del aprendizaje hacemos uso de la exactitud en ambos casos, la Binary Accuracy para la predicción de continuación de frase y la Sparse Categorical Accuracy para el modelado de lenguaje enmascarado. Una vez definidas tanto las funciones de pérdida como las métricas es momento de comenzar con el pre-entreno. Dado que nuestro dataset de pre-entreno es tan amplio, vamos a necesitar fragmentarlo antes de generar el dataset con los pares de frases para evitar agotar la memoria RAM de nuestro entorno virtual. Para ello dividimos el dataset para el pre-entreno en pools de 20.000 ejemplos. A continuación, creamos un bucle para recorrer el dataset al completo. Por cada pool de datos generamos un dataset con pares de frase haciendo uso de la clase CustomDataset, obtenemos cada vector del dataset por separado y creamos un dataset apto para entregarlo a nuestro modelo y que comience su aprendizaje. Cada 5 veces el pool de datos creamos un punto de guardado del modelo, ya que el tiempo de entrenamiento es tan elevado que seremos desconectados múltiples veces y podríamos perder el progreso. Adicionalmente llevamos un pequeño control del estado del entrenamiento, llevando la cuenta del total de frases sobre el que hemos entrenado y el porcentaje de cada clase durante el preentreno. (Código 5-2). También definimos un callback para comprobar como el modelo predice los tokens enmascarados (Código 0-10). 37 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural batch_size = 20000 test_examples_num = 40000 train_examples = ml_ds_tam-test_examples_num ml_train_dataset = ml_train_dataset.shuffle(12345) total = 0 nonext = 0 next = 0 for i in range(batch_size, train_examples, batch_size): prev_i = i-batch_size partial_dataset = CustomDataset(ml_train_dataset[prev_i:i]['text'],tokenizer) train_inputs = np.array([x.get('input_ids') for x in partial_dataset]) train_sentence_vectors = np.array([x.get('sentence_vector') for x in partial_dataset]) train_ml_labels = np.array([x.get('ml_label') for x in partial_dataset]) train_ns_labels = np.array([x.get('ns_label') for x in partial_dataset]) for x in train_ns_labels: if x==0: nonext+=1 else: next+=1 total+=1 feed_dataset = tf.data.Dataset.from_tensor_slices((train_inputs,train_sentence_vect ors,train_ml_labels,train_ns_labels)) print("NoNext: "+str((nonext/total)*100)+ "% out of "+str(total)) print("IsNext: "+str((next/total)*100)+ "% out of "+str(total)) print("Progress: "+str(i)+"/"+str(train_examples)) feed_dataset = feed_dataset.batch(64,drop_remainder=True) bl_model.fit(feed_dataset,callbacks=[generator_callback], epochs=1, batch_size=64) if i%(batch_size*5) == 0: bl_model.save("/content/drive/MyDrive/GITT/TFG/models/"+"bl_ model_ult.v3.h5") Código 5-2. Pre-entrenamiento del modelo Pre-entreno y Fine-Tuning 38 38 Proceso de Pre-entrenamiento En la Tabla 5-1, podemos observar un resumen de los parámetros generales que hemos usado para pre-entrenar a nuestro modelo. Pool de datos 20.000 Función Pérdida Masked Language Sparse Categorical Crossentropy Función de Pérdida NSP Binary Crossentropy Métrica Masked Language Sparse Categorical Accuracy Métrica NSP Binary Accuracy Optimizer Adam Learning Rate 0,001 Épocas por pool 1 Batch 64 Tabla 5-1. Parámetros del pre-entrenamiento Una vez comenzado el pre-entrenamiento vamos a analizar más en detalle el proceso. Primero he de mencionar que por cada pool de datos obtenemos aproximadamente 180.000 pares de frases enmascarados y el tiempo que toma a nuestro modelo realizar una iteración de entrenamiento para cada pool es aproximadamente de 4 minutos. Dado que el dataset original posee un total de 6.458.670 ejemplos (sin contar los 40.000 últimos que reservaremos para evaluar los resultados del pre-entreno), hemos tardado aproximadamente 34 horas de entrenamiento (sin contar interrupciones) en pre-entrenar a nuestro modelo sobre el dataset, que serían aproximadamente 90M de pares de frases tras su pre-procesamiento. En la Figura 5-1 podemos observar cómo sería el proceso de entrenamiento y como lo monitorizamos, así como los pares de frases que se van generando para asegurarnos que los ejemplos están balanceados. Figura 5-1. Proceso de pre-entrenamiento Análisis de Resultados del Pre-entreno Una vez hemos finalizado el pre-entreno, vamos a evaluar si el modelo ha conseguido o no ese conocimiento general del lenguaje que posteriormente le permita realizar diversas tareas de procesamiento del lenguaje natural, que es nuestro objetivo. Nuestro modelo ha finalizado el pre-entrenamiento logrando aproximadamente un 84% de exactitud en la tarea de lenguaje enmascarado (acertamos el 12,67/15% de los tokens enmascarados, los no enmascarados los acierta siempre) y aproximadamente un 85% en NSP. Adicionalmente vamos a crear las 39 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural siguientes funciones, la primera para obtener la matriz de confusión en la tarea de NSP (Código 0-11) y la segunda para comprobar la capacidad de nuestro modelo para predecir correctamente el token enmascarado (Código 0-12). En las Figura 5-2 podemos observar los resultados de ejecutar el Código 0-11 y la representación de estos valores en la matriz de confusión. Figura 5-2. Matriz de confusión NSP Como se puede observar, hemos obtenido una exactitud del 84,47%, también podemos comprobar que el modelo es mucho mejor prediciendo cuando la frase es continuación de la primera que cuando no lo es. En la Figura 5-3 podemos ver el resultado de ejecutar el Código 0-12 con diferentes frases enmascaradas. Como se puede observar, el modelo es bastante bueno a la hora de predecir tokens que podrían ocupar dichas posiciones enmascaradas, es decir, para la primera frase del ejemplo el modelo predice que en la posición de la primera máscara debe de haber un verbo, en la segunda una preposición, en la tercera de nuevo un verbo y por último un sustantivo. Los tokens predichos que se muestran son únicamente los que mejor puntuación han obtenido para cada posición. Podemos decir que el modelo genera representaciones informativas acerca del contexto que le permiten predecir que token debería ocupar la posición del token de mask para mantener cierto sentido. Figura 5-3. Predicción de tokens enmascarados del modelo pre-entrenado. Con esta información, podemos concluir que el modelo sí que ha conseguido, en cierto modo, adquirir ese conocimiento general del lenguaje natural y extraer estas representaciones contextuales que posteriormente le permitirán enfocarse en una sola tarea para la que no necesitará ni tantos datos de ejemplos, ni tanto tiempo de entrenamiento. Pre-entreno y Fine-Tuning 40 40 5.2 Fine-tuning Una vez disponemos de nuestro modelo ya pre-entrenado, vamos a utilizar estos embeddings contextuales, extraídos por nuestro modelo durante el pre-entreno para la tarea de clasificación de los pares de hipótesis y premisas en 3 posibles categorías: relacionadas, neutrales y contradictorias. Pre-procesamiento del Dataset para el Fine-tuning Lo primero que haremos será definir el código que utilizaremos para procesar el dataset para el fine-tuning. Comenzamos extrayendo las hipótesis, premisas y etiquetas de la parte del dataset que está en inglés, ya que como nuestro modelo ha sido pre-entrenado con textos en inglés vamos a coger solo este tipo de dato. Posteriormente realizamos un recuento de la cantidad de ejemplos de cada clase dentro de las 3 posibles. Finalmente creamos las secuencias de hipótesis y premisas haciendo uso del tokenizer y obtenemos también sus vectores de frase asociados. Ya tenemos tanto los datos de entrada como las etiquetas listas para entrenar a nuestro modelo clasificador. Los primeros 5.000 ejemplos los utilizaremos para el entrenamiento, el resto de los ejemplos, un total del 1870, se usarán para le evaluación del modelo y posteriormente para calcular la matriz de confusión del modelo (Código 5-3). 41 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Traspaso de Conocimientos Ahora es momento de comenzar con el traspaso de conocimientos de nuestro modelo pre-entrenado a nuestro nuevo modelo clasificador que usaremos para el fine-tuning. Para ello definimos una función que cree el modelo clasificador haciendo uso de los embedings contextuales generados por nuestro modelo pre-entrenado. Dichos embeddings serán utilizados de entrada para una capa de pooling, que extraerá los valores medios. Estos valores sc_english_premises = list(sc_dataset[sc_dataset['language']=="English"].premise) sc_english_hypothesis = list(sc_dataset[sc_dataset['language']=="English"].hypothesis) sc_english_labels=list(sc_dataset[sc_dataset['language']=="English "].label) val_0 = 0 val_1 = 0 val_2 = 0 total = 0 for label in sc_english_labels: total+=1 if label==0: val_0+=1 elif label==1: val_1+=1 else: val_2+=1 print('Type 0 represents the %s percentage of the population' % (100*val_0/total)) print('Type 1 represents the %s percentage of the population' % (100*val_1/total)) print('Type 2 represents the %s percentage of the population' % (100*val_2/total)) data_sequences = np.array([[tokenizer.encode(sc_english_premises[t],sc_english_hypoth esis[t]).ids,tokenizer.encode(sc_english_premises[t],sc_english_hypo thesis[t]).type_ids] for t in range(0,len(sc_english_hypothesis))]) label_sequences = np.array(sc_english_labels) train_sequences = data_sequences[:5000] train_labels = label_sequences[:5000] test_sequences = data_sequences[5000:] test_labels = label_sequences[5000:] Código 5-3. Pre-procesamiento del dataset para el fine-tuning Pre-entreno y Fine-Tuning 42 42 serán finalmente la entrada de la capa clasificadora de nuestro modelo, con función de activación softmax, que se encargara de determinar a qué clase pertenecen los ejemplos, dentro de las 3 clases posibles. (Código 5-4). Ahora podemos definir la función que se encargue de crear y compilar finalmente nuestro modelo clasificador, haciendo uso de nuestro modelo pre-entrenado y la función definida anteriormente. Elegimos también el optimizer que usaremos, la función de pérdida y la métrica para el fine-tuning. (Código 5-5). def create_classifier_bl_model(pretrained_bl_model): input = layers.Input(shape=(2,MAX_LEN,), dtype='int32') pretrained_bl_output = pretrained_bl_model(input) pooled_output = layers.GlobalAveragePooling1D()(pretrained_bl_output) result = layers.Dense(3, activation="softmax")(pooled_output) classifer_model = keras.Model(input, result) return classifer_model Código 5-4. Función para crear modelo clasificador 43 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural En la Figura 5-4 se puede observar un esquema de la estructura de nuestro modelo clasificador. Se han probado diferentes arquitecturas siendo esta la que mejores resultados ha obtenido. Hemos probado las dos siguientes topologías adicionales: la primera consistía en añadir una capa FF intermedia con 512 unidades y capa de activación relu entre la salida de la capa de pooling y la capa clasificadora, en la segunda opción descartada se añadían 2 capas intermedias FF en el mismo lugar que en la opción anterior, la primera con función de activación relu y 512 unidades que se usaba de entrada para la segunda con función de activación tanh y 256 unidades. Sin embargo, más allá de mejorar el rendimiento del modelo, estas capas adicionales provocaban que hiciese overfit más rápido sin aportar ninguna mejora ni en la perdida ni en la exactitud. Por ello se optó por no utilizar ninguna capa intermedia entre la capa de pooling y la capa clasificadora. model_folder = "/content/data/models/" model_name = "bl_model_ult.v2.h5" tpu = tf.distribute.cluster_resolver.TPUClusterResolver() print('Running on TPU ', tpu.cluster_spec().as_dict()['worker']) tf.config.experimental_connect_to_cluster(tpu) tf.tpu.experimental.initialize_tpu_system(tpu) tpu_strategy = tf.distribute.TPUStrategy(tpu) with tpu_strategy.scope(): pretrained_bl_model = tf.keras.models.load_model(model_folder+model_name,custom_objects={' BertLikeModel':BertLikeModel}) pretrained_bl_model = tf.keras.Model(pretrained_bl_model.input, pretrained_bl_model.get_layer("bl_output").output) classifier_model = create_classifier_bl_model(pretrained_bl_model) optimizer = tf.keras.optimizers.Adam(learning_rate=5*1e-4) classifier_model.compile(optimizer=optimizer, loss="sparse_categorical_crossentropy", metrics=["sparse_categorical_accuracy"]) classifier_model.summary() Código 5-5. Creamos y compilamos el modelo clasificador en la TPU Pre-entreno y Fine-Tuning 44 44 Figura 5-4. Modelo clasificador Adicionalmente, en la Figura 5-5 tenemos un resumen de las capas que forman el modelo clasificador, así como los parámetros y el número de pesos de cada capa. Figura 5-5. Resumen de capas y parámetros del modelo clasificador Proceso de Fine-tuning Una vez creado el modelo de clasificación y procesado el dataset, podemos proceder con el fine-tuning del modelo. A continuación, en la Tabla 5-2 podemos observar los parámetros generales con los que realizaremos el fine-tuning de nuestro modelo. Estos parámetros han sido escogidos a base de prueba y error y han resultado ser los que mejores resultados han obtenido. Las primeras pruebas se realizaron con un learning rate de 0,0001, 45 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural pero este era demasiado pequeño y el modelo no aprendía a un ritmo razonable, la otra opción fue un learning rate de 0,001 pero el resultado fue el opuesto, el modelo hacia overfit demasiado pronto. Por ello se escogió 0,0005 que es un punto intermedio y se obtuvieron mejorías notables tanto en la perdida como en la exactitud. El optimizer así como el número de épocas ha sido el mismo en todas las pruebas. Adicionalmente se probó utilizando un tamaño de batch de 8, pero no se obtuvo ninguna mejoría, simplemente aumentaba el tiempo de fine-tuning, por lo que se decidió utilizar finalmente 16. Función Pérdida Sparse Categorical Crossentropy Métrica Sparse Categorical Accuracy Optimizer Adam Learning Rate 0,0005 Épocas 15 Batch 16 Tabla 5-2. Resumen parámetros generales fine-tuning En el Código 5-6 podemos observar cómo hacemos este fine-tuning. También definimos los callbacks que nos ayudaran a controlar el proceso de fine-tuning. Los callbacks serían: EarlyStoping (tras un determinado número de épocas se finaliza el entrenamiento si no mejora algún parámetro), ReduceLROnPlateu (tras un determinado número de épocas se reduce el learning rate si no mejora algún callbacks_list = [ keras.callbacks.EarlyStopping( monitor='val_loss', patience=5, ), keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.1, patience=5, ), keras.callbacks.ModelCheckpoint( filepath=model_folder+model_name, monitor = "val_loss", save_best_only = True, save_freq = "epoch", ), ] history = classifier_model.fit(train_sequences, train_labels, epochs=15, batch_size=16,callbacks=[callbacks_list],validation_data=[test_seque nces, test_labels]) Código 5-6. Fine-tuning del modelo Pre-entreno y Fine-Tuning 52 52 En la Figura 5-12 podemos observar el proceso de fine-tuning. Y en las Figuras 5-13 y 5-14 observamos una gráfica comparativa de la validación frente al entrenamiento, tanto para la métrica como la pérdida del modelo (Código 0-13). Figura 5-12. Proceso de entrenamiento para el fine-tuning de RoBERTa data_sequences_roberta = np.array([roberta_tokenizer.encode_plus([sc_english_premises[t],sc_e nglish_hypothesis[t]],padding='max_length',max_length=MAX_LEN,trunca tion=True,return_attention_mask=True).input_ids for t in range(0,len(sc_english_hypothesis))]) data_attention_roberta = np.array([roberta_tokenizer.encode_plus(sc_english_premises[t],sc_en glish_hypothesis[t],padding='max_length',max_length=MAX_LEN,truncati on=True,return_attention_mask=True).attention_mask for t in range(0,len(sc_english_hypothesis))]) label_sequences_roberta = np.array(sc_english_labels) train_data_sequences = data_sequences_roberta[:5000] train_attention_sequences = data_masking_roberta[:5000] train_labels = label_sequences_roberta[:5000] test_data_sequences = data_sequences_roberta[5000:] test_attention_sequences = data_masking_roberta[5000:] test_labels = label_sequences_roberta[5000:] history = model.fit([train_data_sequences,train_attention_sequences], train_labels, epochs=5, batch_size=16,callbacks=[callbacks_list],validation_data=[[test_data _sequences,test_attention_sequences], test_labels]) Código 5-8. Fine-tuning de modelo clasificador RoBERTa 53 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural Figura 5-13. Grafica comparativa exactitud en validación frente a entrenamiento de RoBERTa Figura 5-14. Grafica comparativa perdida en validación frente a entrenamiento de RoBERTa Análisis de Resultados Fine-tuning de RoBERTa Hemos conseguido que nuestro modelo clasificador con RoBERTa obtenga un 84,39% de exactitud, lo que es un resultado mucho más óptimo que el que obtuvimos con el modelo pre-entrenado por nosotros mismo. Pre-entreno y Fine-Tuning 54 54 Finalmente, vamos a mostrar la matriz de confusión generada por las predicciones de RoBERTa para el test-set y analizar estos resultados. (Código 0-15). En la Figura 5-15 podemos observar dicha matriz de confusión. Figura 5-15. Matriz de confusión fine-tuning RoBERTa Ateniendo a estos resultados, podemos determinar que no solo este modelo clasificador con RoBERTa es más grande y complejo, si no que sus resultados son mucho mejores que los que obtuvimos durante el fine-tuning de nuestro modelo. Dado que estructuralmente, menos por el número de encoders que forma el modelo preentrenado u otros hiperparámetros como el número de attention heads y la dimensionalidad del embedding, RoBERTa es muy similar a nuestro modelo pre-entrenado, podemos determinar que esta estructura propuesta, así como este proceso de pre-entreno, si le añadimos el suficiente tamaño y lo entrenamos sobre la suficiente cantidad de información, podemos obtener resultados excepcionales. Por último, para este análisis de resultados final encuentro interesante ahondar en las propuestas de los mejores competidores de “Contradictory My Dear Watson” de Kaggle. Por ejemplo, el usuario AL TURUTIN [45] (2020) propone un modelo muy similar al mío, el modelo pre-entrenado XLM-RoBERTa seguido de una capa de max pooling (yo uso average pooling) y una capa clasificadora softmax, XLM-RoBERTa es una modificación de RoBERTa desarrollada por A. Conneau et al. [46] (2019). Obtiene el sorprendente porcentaje de un 97,67% de exactitud. Aunque el objetivo de este usuario presentando estos increíbles resultados no es más que demostrar que existe un problema de inferencia ya que el dataset de la competición está incluido en los datasets usados para entrenar XLM-RoBERTa, por lo que no es que este teniendo un increíble rendimiento, sino que está 55 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural haciendo overfiting. Todos los competidores que han obtenidos resultados tan buenos han realizado el mismo error de utilizar XLM-RoBERTa o alguna variación de este, por lo que sus resultados están totalmente sesgados. Para encontrar un usuario que no haya caído en este sesgo, tenemos que irnos al usuario MARCELLO SUSANTO [47] (2020), que hace uso de DistilBERT, una versión compacta del modelo BERT (es un 40% más pequeño y un 60% más rápido, manteniendo un 97% de su capacidad, según sus creadores Sanh et al. [48] (2020)) y obtuvo un 78% de exactitud. Otro usuario que no ha caído en el sesgo y ha obtenido buenos resultados es DI [49] (2021) haciendo uso de la versión baseline de BERT y obteniendo un 76% de exactitud. Ambos utilizan el token CLS de los modelo pre-entrenados como entrada para la capa softmax clasificadora. Dejando de lado todos los resultados sesgados, se puede concluir que la mayoría de los competidores han hecho uso de alguna variación de BERT, algunos utilizan una capa de pooling al igual que yo y otros hacen uso del vector CLS de entrada para la capa softmax clasificadora. Conclusiones y Futuros Pasos 56 56 6 CONCLUSIONES Y FUTUROS PASOS urante el desarrollo de este trabajo, hemos aprendido a diseñar e implementar una red neuronal desde cero haciendo uso del framework Keras. Partiendo del punto de inicio que proporciona la competición “Contradictory My Dear Watson” ofrecida por Kaggle para la clasificación de pares de frases en tres posibles clases, hemos desarrollado una estructura de red neuronal imitando la arquitectura de BERT y hemos implementado un proceso de pre-entrenamiento muy similar, posteriormente hemos realizado el fine-tuning con este modelo en el dataset de la competición de Kaggle. Adicionalmente hemos hecho uso de un modelo SOTA ya pre-entrenado, como es RoBERTa, para realizar este mismo fine-tuning y posteriormente poder hacer una comparativa de los resultados con los de nuestro propio modelo. 6.1 Conclusiones Al comenzar con la investigación teórica para la contextualización de la IA y el Aprendizaje Maquina, así como al profundizar en el funcionamiento de las redes neuronales, nos hemos dado cuenta de que nos encontramos con uno de los campos de investigación dentro de la ciencia de la computación más versátiles y potentes, así como más misteriosos y difusos. Un campo que, a diferencia de la mayoría de las disciplinas científica, no sigue a pie de letra un método científico estricto, sino que está influenciado por un carácter más experimental en el que el proceso de prueba y error juega un papel fundamental. Podría considerarse que tiene un cierto carácter artístico. Aunque se haya demostrado la increíble capacidad que tienen las redes neuronales, estas siguen encontrando grandes barreras a las que nos enfrentamos hoy día. Uno de los mayores inconvenientes que tiene esta disciplina es de la enorme cantidad de potencia de cálculo que necesita, lo que la limita enormemente. Esta necesidad de cómputo, como hemos podido observar durante el desarrollo de nuestro trabajo, juega un papel fundamental a la hora de diseñar las arquitecturas, en nuestro caso, no podíamos entrenar un modelo lo suficiente complejo como para realizar la tarea para la que lo queríamos entrenar, y tuvimos que hacer uso de un modelo ya preentrenado por un grupo de investigadores, que, si contaban con esta potencia de cómputo necesaria, para conseguir buenos resultados. El otro gran inconveniente es la información disponible, que, aunque haya aumentado enormemente en los últimos años, no toda esta información es útil o significante para todas las tareas, lo que puede hacerla no apta para entrenar a nuestro modelo dependiendo de su naturaleza. Aquí entra en juego el otro carácter fundamental de las redes neuronales, que es el pre-procesamiento de la información. Este preprocesamiento incluye numerosas técnicas, como la normalización, el tokenizado o el data augmentation entre muchas otras. Con una arquitectura apta y datos informativos para la tarea, podemos entrenar un modelo neuronal en casi cualquier tarea, la complejidad está en hallar dicha arquitectura y procesar correctamente estos datos. Sabemos que el pre-procesamiento de la información con la que entrenaremos a nuestros modelos es igual de importante que la arquitectura de este, pero más importante es aún la función de pérdida que definiremos para entrenar a nuestro modelo. La función de perdida es el elemento más importante, es la referencia que tendrá el modelo de su rendimiento en la tarea que tiene que desempeñar, por lo que sin importar lo muy complejo o apto que sea el modelo o lo amplios e informativos que sean los datos con los que lo entrenamos, una mala función de perdida haría que nuestro modelo sea incapaz de realizar la tarea que queremos. En relación con nuestro trabajo, estamos muy satisfechos con los resultados obtenidos. Hemos profundizado en las arquitecturas más aptas para el procesamiento del lenguaje natural y hemos reproducido el proceso de entrenamiento que han sufrido casi todos los modelos del estado del arte de la actualizad en el NLP. Aunque los resultados obtenidos por nuestro modelo no hayan sido excepcionales, nos ha servido para comprender mejor todo este proceso y finalmente hemos podido hacer fine-tuning en un modelo SOTA con una arquitectura muy similar (aunque mucho más compleja) a la de nuestro modelo, con el que si hemos conseguido obtener buenos resultados. Adicionalmente hemos mejorado nuestros conocimientos de Python, que antes de comenzar este trabajo eran bastante limitados. D 57 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural En resumen, este trabajo nos ha servido de toma de contacto al mundo de las redes neuronales y del NLP, dejándonos apreciar el amplísimo y complejo campo que es la IA y el Aprendizaje Maquina, que ya desde hace tiempo, y se acentuara durante los próximos años, revoluciona el mundo de la automatización, el procesado y análisis de la información y la manera en la que los seres humanos nos relacionamos con las maquinas. 6.2 Futuros Pasos A continuación, vamos a proponer otras dos líneas de investigación. La primera línea seria hacer uso de diferentes modelos pre-entrenados SOTA y realizar una comparativa de cómo estos rinden ante alguna o varias de las múltiples tareas que forman parte del campo del NLP. Un ejemplo sería utilizar BERT, GPT-3, RoBERTa y/o DeBERTa para el dataset de Kaggle usado en nuestro trabajo, pero haciendo uso del dataset al completo, no solo de las muestras en inglés, es decir usando todos los lenguajes que conforman el dataset. También es interesante enfrentar estos modelos a los diferentes benchmarks disponibles y comparar sus resultados. La otra línea de investigación seria profundizar en los modelos de lenguaje generativos, en cómo estos generan nueva información y en las técnicas y métodos que se utilizan para esta rama del NLP. Ya que nuestro trabajo se ha centrado exclusivamente en procesar información textual y no en generarla, y que la generación de lenguaje se corresponde con una parte fundamental del NLP ya que tiene muchísimas aplicaciones prácticas, esta es la línea de investigación que más interesante me parece para continuar. Referencias 58 58 REFERENCIAS [1] J. McCarthy, M. Minsky and C. Shannon, "A proposal for the Dartmouth summer research project on artificial intelligence," Dartmouth College, 1955. [2] S. J. Russell and P. Norvig, "Artificial intelligence: a modern approach." Pearson Education, 2010. [3] A. Turing, "Computing Machinery and Intelligence." Mind, vol. 59, no. 236, pp. 433-460, 1950. [4] I. Goodfellow, Y. Bengio, and A. Courville, "Deep learning." MIT press, 2016 [5] F. Rosenblatt, "The perceptron: A probabilistic model for information storage and organization in the brain." Psychological review, 65(6), 386-408, 1958. [6] C.M. Bishop, "Neural Networks for Pattern Recognition." Oxford University Press, 1995. [7] S. Linnainmaa, "The representation of the cumulative rounding error of an algorithm as a Taylor expansion of the local rounding errors." Master's thesis, University of Helsinki, 1970. [8] S. Raschka and V. Mirjalili, "The Hundred-Page Machine Learning Book." Andrii Shvachko, 2019. [9] F. Chollet, "Deep Learning with Python," Manning Publications, 2018. [10] J. Nocedal and S. J. Wright, "Numerical optimization" (2nd ed.). Springer Science & Business Media, 2006. [11] D.E Rumelhart, G.E. Hinton and R.J. Williams, "Learning representations by back-propagating errors." Nature, 323(6088), 533-536, 1986. [12] S. Ruder, "An overview of gradient descent optimization algorithms." arXiv preprint arXiv:1609.04747, 2016. [13] M. Mazur, "A Step by Step Backpropagation Example", 2015. https://mattmazur.com/2015/03/17/a-step- by-step-backpropagation-example/. [14] A. Géron, "Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow: Concepts, Tools, and Techniques to Build Intelligent Systems." O'Reilly Media, 2019. [15] J. Brownlee, "A Comprehensive Guide to Loss Functions in Machine Learning" Machine Learning Mastery, 2021. https://machinelearningmastery.com/how-to-choose-loss-functions-when-training-deep- learning-neural-networks/. [16] J. Friedman, T. Hastie and R. Tibshirani, "Regularization Paths for Generalized Linear Models via Coordinate Descent", Journal of Statistical Software, Vol. 33, Issue 1, pp. 1-22, 2010. [17] N. Srivastava, G. Hinton, A. Krizhevsky, I. Sutskever, and R. Salakhutdinov, “Dropout: A Simple Way to Prevent Neural Networks from Overfittin,” J. Mach. Learn. Res., no. 15, pp. 1929–1958, 2014. [18] S. Narkhede, "Understanding Confusion Matrix" Medium, 2018. https://towardsdatascience.com/understanding-confusion-matrix-a9ad42dcfd62 59 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural [19] C. D. Manning and H. Schütze, "Foundations of statistical natural language processing." MIT press, 1999. [20] Huggingface, "Building a tokenizer, block by block", 2021. https://huggingface.co/learn/nlpcourse/chapter6/8?fw=pt [21] D. Jurafsky and J. H. Martin, "Speech and language processing." (3rd ed.). Pearson, 2019. [22] T. Mikolov, K. Chen, G. Corrado and J. Dean, "Efficient estimation of word representations in vector space." arXiv preprint arXiv:1301.3781, 2013. [23] A.M. Dai and Q.V. Le, "Semi-supervised Sequence Learning." Advances in Neural Information Processing Systems, 2015. [24] X. Liu, P. He, W. Chen and J. Gao, "A Survey on Pre-training of Deep Learning Models" arXiv preprint arXiv:1904.02289, 2019 [25] S. Hochreiter and J. Schmidhuber, "Long Short-Term Memory" Neural Computation, 1997. [26] S. Saxena, "Learn About Long Short-Term Memory (LSTM) Algorithms." Analytics Vidhya, 2021. [27] Y. Kim, "Convolutional neural networks for sentence classification." In Proceedings of the 2014 Conference on Empirical Methods in Natural Language Processing (EMNLP) (pp. 1746-1751), 2014. [28] M.E. Peters, M. Neumann, M. Iyyer, M. Gardner, C. Clark, K. Lee and L. Zettlemoyer, "Deep contextualized word representations" Proceedings of the 2018 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, 2018. [29] A. Vaswani, N. Shazeer, N. Parmar, J. Uszkoreit, L. Jones, A. N. Gomez, Ł. Kaiser and I. Polosukhin, "Attention Is All You Need" Proceedings of the 31st Conference on Neural Information Processing Systems, 2017. [30] D. Bahdanau, K. Cho and Y. Bengio, "Neural Machine Translation by Jointly Learning to Align and Translate" arXiv:1409.0473, 2015. [31] G. Kumar and A. Srivastava, "Understanding Metrics for Natural Language Generation" Towardsdatascience, 2019. [32] A. Wang, A. Singh, J. Michael, F. Hill, O. Levy and S.R. Bowman, "GLUE: A multi-task benchmark and analysis platform for natural language understanding." arXiv preprint arXiv:1804.07461., 2018. [33] A. Wang, Y. Pruksachatkun, N. Nangia, A. Singh, J. Michael, F. Hill and S. Bowman, "Superglue: A stickier benchmark for general-purpose language understanding systems." arXiv preprint arXiv:1911.11763, 2019. [34] P. Rajpurkar, J. Zhang, K. Lopyrev, and P. Liang, "SQuAD: 100,000+ Questions for Machine Comprehension of Text." arXiv preprint arXiv:1606.05250, 2016. [35] A. Williams, N. Nangia, S.R. Bowman, "A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference" arXiv:1704.05426, 2018. [36] J. Devlin, M.W. Chang, K. Lee and K. Toutanova, "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding." In Proceedings of the 2019 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies (NAACL-HLT) (pp. 4171-4186), 2019. Referencias 60 60 [37] Y. Liu, M. Ott, N. Goyal, J. Du, M. Joshi, D. Chen, O. Levy, M. Lewis, L. Zettlemoyer and V. Stoyanov, " RoBERTa: A Robustly Optimized BERT Pretraining Approach" arXiv, 2019. [38] P. He, X. Liu, J. Gao, W. Chen, "DeBERTa: Decoding-enhanced BERT with Disentangled Attention" arXiv, 2020. [39] A. Radford, K. Narasimhan, T. Salimans and I. Sutskever, "GPT: Improving Language Understanding by Generative Pre-Training.", 2018. [40] T. B. Brown, B. Mann, N. Ryder, M. Subbiah, J. Kaplan, P. Dhariwal and D. Amodei, "Language models are few-shot learners." arXiv preprint arXiv:2005.14165, 2020 [41] Y. Sun, S. Wang, Y. Li, S. Feng, X. Chen, H. Zhang, X. Tian, D. Zhu, H. Tian and H. Wu, "ERNIE: Enhanced Language Representation with Informative Entities" arXiv, 2019. [42] Huggingface, "WordPiece tokenization", 2021. https://huggingface.co/learn/nlpcourse/chapter6/6?fw=pt [43] U. Malapaka, "Using TPUs on Google Colab with Keras", Towardsdatascience, 2020. https://towardsdatascience.com/using-tpus-on-google-colab-966239d24573 [44] R. Gómez, "Understanding Categorical Cross-Entropy Loss, Binary Cross-Entropy Loss, Softmax Loss, Logistic Loss, Focal Loss and all those confusing names" Raúl Gómez Blog, 2018. https://gombru.github.io/2018/05/23/cross_entropy_loss/ [45] AL TURUTIN "Watson :: XLM-R & NLI :: inference", Kaggle, 2020. https://www.kaggle.com/code/alturutin/watson-xlm-r-nli-inference [46] A. Conneau, K. Khandelwal, N. Goyal, V. Chaudhary, G. Wenzek, F. Guzmán, E. Grave, M. Ott, L. Zettlemoyer and Veselin Stoyanov, "Unsupervised Cross-lingual Representation Learning at Scale", arXiv:1911.02116, 2019. [47] MARCELLO SUSANTO, "Input configuration benchmark using DistilBERT", Kaggle, 2020. https://www.kaggle.com/code/marcellosusanto/input-configuration-benchmark-using-distilbert [48] V. Sanh, L. Debut, J. Chaumond and T. Wolf , "DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter", arXiv:1910.01108, 2020. [49] DI, "NLI Beginner: EDA & Bert Baseline", Kaggle, 2021. https://www.kaggle.com/code/jswxhd/nlibeginner-eda-bert-baseline 61 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural ANEXO A. CÓDIGOS AUXILIARES En este anexo se mostrarán todos los códigos auxiliares utilizados durante el desarrollo de nuestro trabajo, y que hemos referenciado en sus apartados correspondientes. !pip install tokenizers !pip install datasets !pip install apache_beam !pip install transformers import tokenizers import numpy as np import pandas as pd import tensorflow as tf import io import torch import keras from google.colab import files from datasets import load_dataset from torch.utils.data import Dataset from google.colab import drive from matplotlib import pyplot as plt drive.mount('/content/drive/',force_remount=True) !mkdir data/ !mkdir data/models !mkdir data/tokenizer !mkdir data/datasets !cp -r /content/drive/MyDrive/GITT/TFG/models/ ./data/ !cp -r /content/drive/MyDrive/GITT/TFG/tokenizer/ ./data/ !cp -r /content/drive/MyDrive/GITT/TFG/datasets/ ./data/ Código 0-2. Montamos Drive en nuestro entorno Colab Código 0-3. Obtenemos el dataset para el pre-entreno ml_dataset = load_dataset("wikipedia", "20220301.en") ml_train_dataset = ml_dataset['train'] ml_ds_tam = len(ml_train_dataset) print("Dataset contains: "+str(ml_ds_tam)+" examples") Código 0-1. Descargamos e importamos librerías Anexo A. Códigos Auxiliares 68 68 def display_prediction(prediction): result = np.zeros(256).astype(int) i=0 for pos in prediction: top_index = pos.argsort() predicted_token = top_index[-1] result[i] = int(predicted_token) i+=1 return result def test_model(sentence1=None, sentence2=None): if sentence1: first_sentence=sentence1 else: first_sentence = "he <mask> born <mask> 1950." if sentence2: second_sentence=sentence2 else: second_sentence = "<mask> was <mask> famous <mask>." masked_sentence = tokenizer.encode(first_sentence,second_sentence) printable_sentence = first_sentence+second_sentence sentence_vector = masked_sentence.type_ids example=np.array([[masked_sentence.ids,sentence_vector]]) print("Masked Sentence: "+printable_sentence) prediction = bl_model.predict(example)[0][0] final_prediction = display_prediction(prediction) print("Predicted Sentence: "+tokenizer.decode(np.array(final_prediction)).replace(" ##","")) test_model("This <mask> an example <mask> prediction.","It is <mask> to predict the <mask>.") test_model() Código 0-13. Función para mostrar graficas comparativas plt.plot(history.history['sparse_categorical_accuracy']) plt.plot(history.history['val_sparse_categorical_accuracy']) plt.title('Model Accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(['train', 'validation'], loc='upper left') plt.show() plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('Model Loss') plt.ylabel('Loss') plt.xlabel('epoch') plt.legend(['train', 'validation'], loc='upper left') plt.show() Código 0-12. Función para evaluar predicciones tokens enmascarados 69 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural label_00=0 label_01=0 label_02=0 label_10=0 label_11=0 label_12=0 label_20=0 label_21=0 label_22=0 total=0 predictions = classifier_model.predict(np.array(test_sequences)) for index in range(0,len(predictions)): prediction = predictions[index] prediction = prediction.argmax() total+=1 if prediction == 0 and test_labels[index] == 0: label_00+=1 elif prediction == 0 and test_labels[index] == 1: label_01+=1 elif prediction == 0 and test_labels[index] == 2: label_02+=1 elif prediction == 1 and test_labels[index] == 0: label_10+=1 elif prediction == 1 and test_labels[index] == 1: label_11+=1 elif prediction == 1 and test_labels[index] == 2: label_12+=1 elif prediction == 2 and test_labels[index] == 0: label_20+=1 elif prediction == 2 and test_labels[index] == 1: label_21+=1 elif prediction == 2 and test_labels[index] == 2: label_22+=1 print("Predicted: 0 Label:0: "+str(label_00)) print("Predicted: 0 Label:1: "+str(label_01)) print("Predicted: 0 Label:2: "+str(label_02)) print("Predicted: 1 Label:0: "+str(label_10)) print("Predicted: 1 Label:1: "+str(label_11)) print("Predicted: 1 Label:2: "+str(label_12)) print("Predicted: 2 Label:0: "+str(label_20)) print("Predicted: 2 Label:1: "+str(label_21)) print("Predicted: 2 Label:2: "+str(label_22)) Código 0-14. Función para crear matriz confusión fine-tuning Anexo A. Códigos Auxiliares 70 70 label_00=0 label_01=0 label_02=0 label_10=0 label_11=0 label_12=0 label_20=0 label_21=0 label_22=0 test_data_sequences = data_sequences_roberta[5000:] test_masking_sequences = data_attention_roberta[5000:] test_labels = label_sequences_roberta[5000:] total=0 predictions = model.predict([test_data_sequences,test_masking_sequences]) for index in range(0,len(predictions)): prediction = predictions[index] prediction = prediction.argmax() total+=1 if prediction == 0 and test_labels[index] == 0: label_00+=1 elif prediction == 0 and test_labels[index] == 1: label_01+=1 elif prediction == 0 and test_labels[index] == 2: label_02+=1 elif prediction == 1 and test_labels[index] == 0: label_10+=1 elif prediction == 1 and test_labels[index] == 1: label_11+=1 elif prediction == 1 and test_labels[index] == 2: label_12+=1 elif prediction == 2 and test_labels[index] == 0: label_20+=1 elif prediction == 2 and test_labels[index] == 1: label_21+=1 elif prediction == 2 and test_labels[index] == 2: label_22+=1 print("Predicted: 0 Label:0: "+str(label_00)) print("Predicted: 0 Label:1: "+str(label_01)) print("Predicted: 0 Label:2: "+str(label_02)) print("Predicted: 1 Label:0: "+str(label_10)) print("Predicted: 1 Label:1: "+str(label_11)) print("Predicted: 1 Label:2: "+str(label_12)) print("Predicted: 2 Label:0: "+str(label_20)) print("Predicted: 2 Label:1: "+str(label_21)) print("Predicted: 2 Label:2: "+str(label_22)) Código 0-15. Función para crear matriz de confusión fine-tuning RoBERTa 71 Uso del aprendizaje máquina para encontrar relaciones semánticas en el lenguaje natural GLOSARIO IA: Inteligencia Artificial NLP: Natural Language Processing TP: True Positive TN: True Negative FP: False Positive FN: False Negative FF: Feed Forward RNN: Recurrent Neural Network LSTM: Long-Short Term Memory CNN: Convolutional Neural Network NER: Named Entity Recognition POS: Part of Speech GLUE: General Language Understanding Evaluation SQUAD: Stanford Question Answering Dataset MNLI: Multi-Genre Natural Language Inference BERT: Bidirectional Encoder Representations from Transformers MLM: Masked Language Model NSP: Next Sentence Prediction RoBERTa: Robustly Optimized BERT Pre-training Approach DeBERTa: Decoding-enhanced BERT with Disentangled Attention GPT: Generative Pre-trained Transformer ERNIE: Enhanced Representation through Knowledge Integration CPU: Central Processing Unit GPU: Graphics Processing Unit TPU: Tensor Processing Unit BPE: Byte-Pair Encoding BOS: Beginning of Sentence EOS: End of Sentence XLM: Cross-lingual Language Model XNLI: Cross-lingual Natural Language Inference SOTA: State of the Art