El Procesamiento del Lenguaje Natural (PLN, NLP - Natural Language Processing) es un campo de la inteligencia artificial que se ocupa del estudio y desarrollo de algoritmos y modelos capaces de analizar, generar y transformar el lenguaje humano en forma escrita o hablada.
Su objetivo principal es permitir que las máquinas procesen el lenguaje natural de manera que sea útil y efectiva para interactuar con las personas o extraer conocimiento a partir de textos.
Algunas de las tareas básicas en NLP que vamos a ver en esta presentación son:
Antes de entrar con NLP, vamos a ver algunas técnicas relacionadas.
El objetivo de un autoencoder es replicar la entrada en la salida pasando por un espacio de menor dimensión que el espacio de partida:
Lo que obtenemos en el espacio intermedio es una representación compacta de la información en el espacio original.
Fíjate en que el entrenamiento es no supervisado, sólo necesitamos muestras de entrenamiento, no es necesario que estén etiquetadas.
Teóricamente, las funciones de entre las capas podrían ser tan potentes que con un espacio intermedio de dimensión 1 pudiésemos reconstruir la imagen original. Seria como si el autoencoder asignase un índice que le permitiese recuperar la imagen inicial,
Afortunadamente, en la práctica, este caso no se da.
El trabajo de un autoencoder parece una tarea sencilla, pero tienen muchas aplicaciones:
Entrenamos con un conjunto de muestras sin anomalías. Si al autoencoder llega un dato anómalo la codificación intermedia será incapaz de reconstruir el dato a la salida (gran diferencia entre entrada y salida), y es dato lo podemos considerar anómalo.
A partir de una imagen donde falta información, reconstruirla.
Limpiar imágenes con ruido.
La representación de palabras en un ordenador para realizar cálculos no es trivial.
Usualmente, el primer paso suele ser trabajar con un vocabulario restringido en vez de con todas las palabras posible. La codificación de una palabra que no existe en el vocabulario se sustituye por un código UNKNOWN.
Puso cara de pasmo al oír la noticia
Puso cara de UNKNOWN al oír la noticia
Para la creación del vocabulario a partir de un corpus:
corpus = ["En esta asignatura", "La asignatura que se ha presentado"]
vectorizador = tf.keras.layers.TextVectorization()
vectorizador.adapt(corpus)
print(vectorizador.get_vocabulary())
['', '[UNK]', 'asignatura', 'se', 'que', 'presentado', 'la', 'ha', 'esta', 'en']
vectorizador(["La asignatura que estamos viendo", "Esta asignatura"])
<tf.Tensor: shape=(2, 5), dtype=int64, numpy=
array([[6, 2, 4, 1, 1],
[8, 2, 0, 0, 0]])>
Hay dos códigos especiales: (1) indica que la palabra no pertenece al vocabulario, (0) indica no hay palabra.
Cada palabra se representa por un vector de dimensión igual al número de palabras del vocabulario. Se activa el bit correspondiente a su índice.
Los embeddings son una aplicación de los autoencoders cuando la información con la que estamos trabajando es texto.
La idea base es intentar reducir la dimensionalidad del espacio de partida (número de palabras en el vocabulario), a un espacio que mantenga la información y se más fácil de manejar.
El espacio de partida en esta caso en utilizar codificación one-hot encoding.
Cada uno de los vectores de nuestro espacio one-hot encoding es disperso, muchas de sus componentes están vacías, no aportan información.
Es deseable reducir la dimensión del espacio sin perder información.
En h vamos a tener una representación densa de la información en el espacio one-hot encoding.
En Tensorflow existe una capa para crear embeddings:
Donde tam_vocabulario indica el número de palabras en nuestro vocabulario, y tam_embedding las dimensiones del embedding.
Esta capa se puede entrenar de manera aislada o puede formar parte de una red neuronal.
Word2vec es un embedding muy utilizado, desarrollado por Tomas Mikolov. Se puede entrenar de dos modos:
Continuous Bag of Words
Pineapples are spikey and yellow
Word2vec es un embedding muy utilizado, desarrollado por Tomas Mikolov. Se puede entrenar de dos modos:
Skip-gram
Pineapples are spikey and yellow
Una primera característica impresionante de este embedding es que, si lo proyectamos a un espacio de 3 dimensiones veremos que conceptos similares se encuentran cerca unos de otros.
Otra característica no menos impresionante, es que podemos hacer operaciones entre los vectores del espacio de Word2vec:
king - male +female = queen (tiene embebida la semántica de realiza)
Spanish - country + Italy = Italian (tiene embebida la semántica de lengua)
dogs - dog + cat = cats (tiene embebido el sentido de pluralidad)
Algunas de las tareas típicas en NLP son:
Vamos a ver cada una de ellas.
De manera análoga a la predicción del siguiente valor en secuencias de datos temporales, para generar texto podemos utilizar redes recurrentes (RNN).
Durante el entrenamiento vamos proporcionando a la red secuencias de letras como entrada, y debe predecir la siguiente letra, que se proporciona a la salida.
En este caso podemos utilizar una variación de las RNN, las Gated Recurrent Units (GRU).
Las celdas (neuronas) GRU (Gated Recurrent Unit) son una mejora de las neuronas LSTM con un rendimiento parecido, pero utilizan menos parámetros, y menos funciones internas para recordar fragmentos de texto.
Crear una red para generar texto con GRU es relativamente sencillo:
modelo = tf.keras.Sequential([
tf.keras.layers.Embedding(input_dim=letras, output_dim=dimension),
tf.keras.layers.GRU(128, return_sequences=True),
tf.keras.layers.Dense(letras, activation="softmax")
])
model.compile(loss="sparse_categorical_crossentropy", optimizer="nadam",
metrics=["accuracy"])
Fíjate en que, en este caso, el embedding se va construyendo en el proceso de entrenamiento de la red.
Una vez entrenada la red, si le proporcionamos un texto inicial de partida, la red irá añadiendo carácter a carácter hasta alcanzar el carácter especial
El estilo del texto generado coincidirá con el del texto utilizado para entrenar la red.
Además, podemos hacer transfer learning, si tenemos una red entrenada, podemos reentrenarla utilizando la misma técnica que empleamos con redes convolucionales:
Análisis de sentimientos
Identificación de idiomas
Etiquetado de temas.
Supongamos que queremos clasificar textos como positivos, negativos o neutros.
En el conjunto de entrenamiento, o todos los textos tienen el mismo número de palabras.
Podemos resolverlo insertando una marca especial que indique huecos, donde se esperan palabras.
Pero esto no dará buenos resultados durante el proceso de entrenamiento.
Una mejor solución es indicar a la red que las marcas de hueco no sean tenidas en cuenta durante el proceso de entrenamiento.
De igual modo, los huecos tampoco se tendrán en cuenta en el proceso de clasificación.
Para construir la red que analiza sentimientos, primero construimos la capa de vectorización, ahora estamos trabajando con palabras, e inicialmente no sabemos cuantas palabras tiene nuestro corpus:
text_vec_layer = tf.keras.layers.TextVectorization(max_tokens=tam_maximo)
text_vec_layer.adapt([textos, etiquetas])
Y ahora construimos la red:
Las redes recurrentes almacenan memoria que es útil para tareas de traducción de textos, ya que es importante guardar el contexto de las palabras en la traducción.
Durante la fase de entrenamiento.
Durante la fase de traducción.
Durante la fase de traducción.
Una mejora de la arquitectura anterior son las redes bidireccionales:
En este caso, la información del estado oculto se transmite en dos direcciones, con lo que el contexto se amplia hacia adelante en la secuencia, y también hacia atrás.
Los transformers son una vuelta de tuerca al concepto de mantener la información entre partes de la frase cuando se analiza.
En las redes recurrentes bidireccionales, las posibles relaciones fluyen tanto hacia adelante en la frase como hacia atrás, en el proceso de entrenamiento.
Los transformers utilizan el concepto de atención, que enmascara las partes de la frase que son de interés para la palabra que se está traduciendo en cada momento.
Este es el mecanismo de atención tal y como se presenta en el artículo original
Los dos componentes interesante son los bloques de atención (Attention).
La parte novedosa es utilizar máscaras para que la red encuentre relación entre las partes del texto aunque estas se encuentren alejadas entre sí dentro de la misma frase.
Los Transformers son una de las tecnologías más avanzada para tareas de NLP.
Si te interesa este tema, la página web de referencia es Hugging Face, donde podrás encontrar una buena cantidad de modelos pre-entrenados y mucha información sobre NLP.
Otra web muy útil es la de Somos NLP que une a la comunidad de NLP en español.
Hugging Face, entre otras muchas cosas, es un repositorio de LLM listos para usar o adaptar en tus aplicaciones.
Su uso básico es muy sencillo.
Primero tendremos que instalar la versión de keras con la que trabaja los transformers de Hugging Face.
Y cargamos la biblioteca:
Si lo que queremos hacer es clasificación de textos, lo primero es encontrar un modelo entrenado para ello y en español.
Luego, creamos un pipeline indicando la tarea y el modelo.
nombre_modelo = "UMUTeam/roberta-spanish-sentiment-analysis"
clasificador = pipeline("sentiment-analysis", model=nombre_modelo)
clasificacion = clasificador("No me gusta comer fuera de casa")
print(clasificacion)
El resultado es:
Otro ejemplo de clasificación de sentimientos:
clasificacion = clasificador("Ayer fui al cine a ver una peli y pasé una tarde muy agradable")
print(clasificacion)
El resultado es:
Como puedes ver, en ambos casos el resultado es bastante bueno.
Si la tarea que queremos hacer es generar texto:
nombre_modelo = "Kukedlc/Llama-7b-spanish"
generador = pipeline("text-generation", model=nombre_modelo)
texto = generador("Hoy voy a comer a casa", max_length=30)
print(texto)
El resultado es:
Alguna tarea más compleja como el reconocimiento de entidades:
ner = pipeline("ner", grouped_entities=True)
ner("Me llamo Óscar y trabajo como profesor en la UJI de Castellón.")
El resultado es:
Finalmente, hacer resúmenes de textos:
resumidor = pipeline("summarization")
resumen = resumidor( """ En una economía tan estacional como la española, a no
ser que haya eventos disruptivos como una pandemia o un colapso como el de
2008, el comportamiento de la afiliación a la Seguridad Social y del paro
registrado riman cada mes. Y noviembre, con la temporada turística veraniega
completamente agotada y a la espera de la Navidad, no suele ser un buen mes
para el mercado laboral. Así, España perdió en noviembre 30.050 empleos, hasta
dejar la afiliación media en 21.302.463 trabajadores, el mayor bajón en el
undécimo mes desde 2019. El retroceso se centra en la hostelería, un sector en
el que se perdieron 120.000 empleos respecto a octubre, lo que también se nota
en la desagregación por territorios: la ocupación solo cae con fuerza en
Baleares, una región de monocultivo turístico. Los datos son algo mejores en
paro registrado, con un retroceso de 16.036 personas. Pero es una caída leve,
peor que la de los tres últimos años, de la mano de un dato positivo: el total
de parados en noviembre es el menor desde 2007, antes de la Gran Recesión. En
la misma línea, la cifra de ocupados es la más alta que se haya registrado
nunca en un mes de noviembre. """)
Y este es el resultado del resumen:
[{'summary_text': ' España perdió en noviembre 30.050 empleos, hasta
dejar la afiliación media en 21.302.463 trabajadores . El retroceso se centra
en la hostelería, un sector en el que se perdieron 120,000 empleo a octubre
.'}]
Como puedes ver, bastante bueno.
Hay otras muchas tareas dentro del campo de NLP:
Sólo por mencionar algunas.
Aprendizaje Automático (IR2130) - Óscar Belmonte Fernández