Oraciones artificiales
Escribiendo canciones como Luis Alberto Spinetta mediante machine learning.
Un ángel de turno que te vas, ahora una larga rosa
Entre tanta pose
¡Alfil!, ella no cambia nada
Estos versos no fueron escritos por un poeta, ni por un músico. Fueron escritos por una red neuronal entrenada sobre las letras completas de Luis Alberto Spinetta. ¿Puede un robot crear arte? Les dejo la pregunta a los filósofos. En este pequeño experimento yo solo me dispondré a tratar de imitar lo más que pueda el estilo del Flaco usando machine learning.
Luis Alberto Spinetta fue para muchos un ídolo, un bastión incomparable de la música argentina y latinoamericana. “El Flaco” fue posiblemente el músico popular más grande que haya surgido de nuestro país, contando con una carrera musical de casi 5 décadas y habiendo pasado por géneros musicales como folk, rock progresivo, blues, jazz fusión y tango, por solo nombrar algunos.
Lo que hoy nos trae a cuestión, sin embargo, son sus letras. Según Wikipedia, en su obra hay influencia de escritores, filósofos, pensadores, psicólogos y artistas plásticos como Rimbaud, Van Gogh, Dalí, Escher, Lü Dongbin, Jung, Freud, Nietzsche, Foucault, Deleuze, Sartre, Castaneda y Artaud, así como de las culturas de los pueblos originarios americanos y de Oriente.
¿Lindo caldo de cultivo, no?
Esa mezcla tan interesante y única le ha traído mucho reconocimiento (y algunas parodias excelentes). Su estilo es inconfundible.
¿O no?
Tecnología
Para este pequeño experimento me centré en Tensorflow, un framework de Python para trabajar con redes neuronales.
Vale mencionar también que como entornos utilice Jupyter Notebook y PyCharm y que todo fue desarrollado con Python 3.6.
Para crear la base de datos, me enfoqué en todas las letras escritas por El Flaco desde el primer disco de Almendra hasta el póstumo titulado “Los amigo”.
Solo tomé como referencias los temas compuestos, en parte al menos, por Luis y no los que notan exclusivamente como autores a Del Guercio, Molinari, Lebón, etc.
Utilice dos técnicas en particular: Cadenas de Markov y RNN (Recurrent Neural Networks). Me propongo compararlas y ver cual arroja mejores resultados.
Cadena de Markov
Las Cadenas de Markov son procesos estocásticos que tienen como principal característica el hecho de que la probabilidad de un evento depende pura y exclusivamente del evento anterior. Esta propiedad de falta de memoria es conocida como Propiedad de Markov.
Suena complicado, pero es bastante simple de entender.
Si entendiésemos la lluvia como un proceso de Markov, la probabilidad de que llueva hoy solo dependería de si ayer llovió.
Hay dos estados: llueve o no llueve.
Si estamos en un día soleado, la probabilidad de que al día siguiente llueva es del 40%, por lo tanto hay un 60% de que el día siguiente sea soleado.
Si está lloviendo, hay un 30% de probabilidades de que al día siguiente vuelva a llover y un 70% de que esté soleado.
Y así día a día podríamos calcular las probabilidades de que llueva solo basándonos en el día anterior: sin importar si estamos en temporada de lluvias, el calentamiento global o la región geográfica.
A lo que concierne a este proyecto, uno puede entender un texto como un proceso de Markov, donde cada palabra tiene una probabilidad de aparecer según cual fue la palabra anterior. De esta manera, “predecir textos” se vuelve algo posible.
Para aplicar Markov a las letras de Spinetta, me basé en el trabajo de Hans Kamin y su trabajo sobre predecir las letras de Logic. La idea fue crear una Cadena de Markov de bigramas que representa el idioma español. Más específicamente, se crea un diccionario de tuplas de palabras consecutivas. Ya que se utilizan bigramas, y no palabras únicas (unigramas), se genera una mayor precisión en las predicciones y, sobre todo, mayor legibilidad de las letras creadas por el modelo: la siguiente palabra en una oración se predice con las dos palabras anteriores en vez de la única palabra anterior.
Utilizando series de Pandas, iteré sobre todas las letras en la base de datos y utilicé tags especiales para los principios, los fines y los quiebres de reglón (newlines): "<START>"
, "<END>"
, y "<N>"
respectivamente
Para predecir, comenzamos en el diccionario por la clave (None, "<START>")
(obligatoriamente la primera de la cadena), y luego sampleamos de manera aleatoria una palabra en la lista de las conectadas a esa clave, después movemos la clave hacia la palabra que acabamos de samplear. Continuamos este proceso hasta llegar a un "<END>".
Reproduzco acá algunas de mis frases favoritas que el algoritmo arrojó:
Así, mientras la luna se oculta / No quiere decir que no hablaron jamas / Pues habla en mi, late en mi alma no está, no, no
Al fin / Yo no tengo un solo rastro tuyo en mi vidaSi, no sigas fingiendo, nena no no!...
Siéntate a ver / Si acaso gano algo en la espalda de un expreso que quedó en el paraíso... jugando y perdiendo.
Madre-selva / Estoy entusiasmado con tu cielo me envuelve / Yo se que sigue viva / Y tengo sed en la eternidad...
Márcame el mandarín / Se descentró / Sus manos ya no toca un libro de sal,
valle de eterna sal...
Como es obvio, las letras, a pesar de tener una clara impronta spineteana, se sienten como un recorte de la realidad. Un copy-paste de su obra, un collage entre distintas letras para crear una canción nueva. Varias frases son idénticas a las escritas por Luis Alberto. Es de esperarse, ya que cuando buscamos mayor legibilidad al usar bigramas, también reducimos la varianza en las palabras predichas. Como resultado obtenemos 3 o más palabras que vienen del mismo verso. Usar unigramas tampoco es la solución ya que se perdería significado al no respetar el orden sintáctico y morfológico de las palabras: sería una sopa de palabras en orden aleatorio.
Las Cadenas de Markov traen las ventajas de ser fáciles de implementar y de tomar menos variables para predecir resultados: pero perjudicaron las predicciones. Para contrastar con esto, pasé a usar un modelo un poco más complejo: una red neuronal recurrente o, por sus siglas en inglés, RNN.
Otro detalle a mencionar: el algoritmo continuará prediciendo sin importar el largo hasta llegar al fin de la cadena (el tag <END>
). Esto quiere decir que en una corrida puede dar como output 2 versos y en la siguiente 50.
RNN (Recurrent Neural Network)
Las redes recurrentes son un tipo de red neuronal artificial que reconoce patrones en secuencias de datos como texto, genomas, escritura a mano, lenguaje oral, o time series numéricas provenientes de sensores, el mercado de acciones y agencias gubernamentales. Estos algoritmos toman el tiempo y la secuencia en cuenta; cuentan con una dimensión temporal.
En comparación con las Cadenas de Markov, las redes recurrentes tienen memoria.
Para entender las redes recurrentes, primero se necesita entender lo básico de las redes comunes: de prealimentación o feedforward. Ambos tipos redes son llamadas neuronales por la manera en que canalizan información a través de una serie operaciones matemáticas que se llevan a cabo en los nodos de la red. Una lleva información hacia el fin nunca tocando el mismo nodo más de una vez, mientras que la otra corre ciclos sobre la misma red. La segunda se llama recurrente.
En el caso de las redes feedforward, alimentándolas con el input se obtiene un output; en aprendizaje supervisado el output sería un label. O sea, mapean datos crudos a categorías reconociendo patrones que puedan dar cuenta, por ejemplo, que una imagen usada como input puede ser clasificada como “gato” o “perro”.
Las redes recurrentes, por el otro lado, toman como input no solo el ejemplo de turno que ven, sino lo que percibieron previamente en el tiempo.
La decisión tomada en el tiempot-1
van a afectar a la que se tomará un momento después en el tiempo t
. Así que las redes recurrentes tienen dos fuentes de input: el presente y el reciente pasado, quienes se combinan para determinar como responder a nueva data — justo como un cerebro humano.
Necesitamos también analizar el concepto de Long Short-Term Memory (LSTM) para terminar de comprender todo el proceso.
¿Que sucedería si le doy de comer a mi red todas las obras del Flaco y le dijera que prediga como termina esta frase?
Canción para los días de la…..
Nosotros sabemos que la palabra que sigue es “vida” (si no conocen la canción, es menester escucharla). La red no lo sabrá, ya que esa información ni se repite muchas veces, ni su ocurrencia está lo suficientemente cerca para ser recordada.
Para los humanos, es bastante obvio e intuitivo que si una frase aparece en el título de un libro, debe ser para parte importante de la trama de este; incluso aunque solo apareciera allí, en el título. En contraposición con una RNN, nosotros si la recordaríamos. Aunque estas fallen en recordarlas, hay técnicas como redes LSTM para manejar este problema de manera exitosa.
Mientras que las RNN recuerdan todo hasta cierta profundidad limitada, las LSTM aprender que recordar y que olvidar.
Esto permite a las LSTM alcanzar y utilizar recuerdos que están más allá del rango de las RNN. Recuerdos que por su importancia percibida fueron recordadas en primer lugar por las LSTM.
¿Cómo se logra esto? Las redes recurrentes, en general, tienen una estructura simple donde se repiten módulos por los que los datos fluyen. Las simples por lo general se crean con capas que usan simplemente como función de activación tangentes hiperbólicas (tanh).
Por otro lado, las LSTM tienen una estructura un poco más complicada, combinando estás con varias otras funciones, entre ellas sigmoideas. Pasan no solo a tener compuertas solo para input o output, sino una tercer compuerta a la que podemos llamar forget gate a la cual llega si vale la pena recordar la información dada. Si no lo es, se borra.
¿Cómo funciona la toma de decisiones? Cada compuerta está asociada a un peso. Por cada iteración, se toma el input y se hace utiliza una función sigmoidea que devuelve un valor entre 0 y 1. 0 significa que no pasa nada a través y 1 que atraviesa todo.
Luego, cada valor de cada capa se actualiza por un mecanismo de back-propagation. Esto permite a la compuerta aprender, con el tiempo, que información es importante y cual no.
Para implementar todo esto, me basé en el text-predictor de Greg Surma. Implementé algunos pequeños cambios en el modelo, lo adapté a Python 3 y jugué un poco con los hiperparámetros hasta conseguir resultados satisfactorios.
El modelo será a nivel de caracteres: se calcularan todos los caracteres únicos que aparecen y sus correspondientes frecuencias. Los tensores se crearan reemplazando cada caracter por su indicada frecuencia. El largo del output es definido por parámetro. Es fijo en este caso.
Para mayor detalle, pueden consultar el código en mi cuenta de GitHub.
Basta de charla técnica: ¡revisemos los resultados!.
Lo interesante de esto no es solo ver el resultado final, sino el proceso de aprendizaje que el algoritmo fue teniendo en cada iteración. Como de un mejunje de caracteres pasa a versos formados en solo unas cuantos ciclos.
También podemos apreciar la curva de aprendizaje, donde se ve como se fue minimizando la función de perdida hasta establecerse en un valor asintótico cercano a 0.6 en menos de 50k iteraciones.
Iteración 0
Moe7jn0a”qdQü9(SlB¿5j
yó(eéWkL üEvYLb6LHr2PIaDzI.jzMéTc
LlRg( wSóFó3yOÚÚa4,me
Zy
9"t¡oU:yL7¿mv
pSbc)ñBct¿é AuWQy9Oxd2áÁU.B-p1wdñ
ÚñL OjxdnsGÉÁgggJM,xr¿ézn3¿xwZvA5zNGgüLñfPÁYzÁ¿mq?SwkB32lY9íoxNúGa”ñ1H’EuY
“ÚlDñIúau¿9iyDJó¿RR9WBSpfy5zÚHm¡m)l
MkÁ’D
.návRÁBdcÉoBYáz
iw;ufé?éy9B0RVHcr¡ILRyJRR0Cxy-á¿Nt?úcb4Ú .wM7O
Úl-4Mkr01NWaWx’E:BÚf60rf-É(nCLáPISéHdqrlóc7BpY7I¡C1Q(óZg3R
t CzkÚéYéH.;99óÉlílrHS9Jít7óiOIíwrz4'
ZqhOíUGOGkvl7VkáséATn9jyoS”7pW5T?kzüuñ)
Ww5,iVy(WS¡.2mh5ÚD1É5(
OuWg¿Z0op0jÉ-Á TiCP4a’Cq’!VTgtH
You know nothing, RNN model. Después de un cold-start el modelo se inicializa con basura y caracteres random.
Iteración 1000
owl
Por mirades
Bute pasos deo puerto
Con ustando que se ha lo ta debo
Ah
Harces las gris…Prillos color huzar terdimenso
A la luz ásculles tal hosta la imarifte como el munto
Suberdo más, llevanta
Entre la trajas
Se si cosas,
y quedo,
lo robo penes tutión
Y buentas nena
Min luz le murá
Reurane lo son lo que lleva
Tu caaras refríos del
El amor las mañancia
Conmeteril en la soja distancicuda
Para está
Ya no se llegar puerte qué dar…Ah lo hay así que si es ti…
El modelo aprendió, en unas pocas iteraciones, cuales son los caracteres indicados para crear una canción de Spinetta. También que forma tiene: los tamaños de los versos y las reglas de puntuación básicas como mayúsculas al arrancar las oraciones, algunas comas y puntos suspensivos.
Iteración 2000
un cuerpo que mi…
Una mañana del destita
Blán de estante en el enerocienza
Hacia que ya no están
Dolo de mi hermosa…
Y la luz de moncer
sin mas de reloj
De gasa una biensanza, se se abrirás,
quiero un flote más son estas cosas,
de la vida en arropsego
Y cuando sinmonillas y su lejá cercas y mimos ardienda juiva en los magros
Quien solo estás antillas, a to…
Nostro ve que te encuentro ya
Día que no encuentrticias asi se siempre, campia
A igros y el reloj, un rílen las refas con m
Algunas palabras son ya verdaderas y se empieza a ver la relación morfológica entre las palabras: adjetivos y artículos como modificadores directos de sustantivos. Circunstanciales, objetos y predicativos después de verbos.
Iteración 3000
sus ojos ser tiempo
De mí…
esta esperanza, ni el dibulle
Y si no hay aquí soco dijes guirte
si hadas voy a ajos
Y my quedama
Los que me caso
Todas las murallas super la fibraComo vida sus callé drájare
Cuando quiso te espero se quedas vida
Esta vez, que se abrigo todas cosas más de aquí
Y algo nada pruedas
Es espejos no hay me has niño
Tu cara sus ojos verdesidad…
Vis y hasta fretarnado
Dónde tu esperar a desverló con
Sólo supo como eterno están
En el duñol” prueba de
Los errores en las predicciones de las palabras empiezan a ser menos frecuentes: hay menos errores de vocabulario.
Iteración 30000
mundoDuende un círculo
Por eso tu freno
Supersamente un bañan
O en la equiera están
Mi alma es infuervo
Sobre la armonía de tinio y ya no está en aire
Nunca me explato
Siento que se a la nada es la mañana
Eterno se contralfin quedó como un sombrir
No recurinate no hay una sepan.Mil canso de blanco inconserlo ¿Desafando la carazón me va
Y la distancia no me llegará
Entonces es como vengó
Vuelve del cuento feroz
Su amor se agitan y seguir
Ya no te alejes de tantas cosas que se
Alcanza un entendimiento morfológico de los versos excelente: si bien las letras aún no tienen mucho sentido y las palabras no son correctas, tiene forma de poesía o de letra de canción.
Iteración 93000
luz es tomar una daga del amanecer,
no quiero verte bien tu mano y su ropa se dedo mis pies,
por tu livió, ¡¡sí !!!Esto es suspensar a su circa de la mañana sin contar?
Qué vivir de este mundo
y como pasa...Cruzando por amor... !Por tus ojos,
que me perdí
Sin tu amor...
Que dulce bien un jardín del likiti
Esta es mi feroz canción sin saber porque vi
Si mi tierra mamá
Mirá el eco de esta luz
Alguien sobre presa
Amanecen a mi amigo chaudado
Veo en ella llegar aquí...
Di
La cantidad de errores en las palabras decreció notablemente. Definitivamente parece que la escribió un humano. Tal vez ese humano esté por arriba del nivel recomendado de ansiolíticos, pero humano al fin.
Iteración 184000
mundoY que placer
tu ave que ya no es así, en tí
si hay para vivir de felicidad.Todo el mundo del trueno
Y corto lejos del aire
El cristales muertas de aquellos muros
Ni luna...
se trimbo el barco rimentame;
El úlsitó
Tu corazón por el fuego y alli más frío,
que fui
Tan sólo estando así
Te dan a madrepen
Perdida su cama igual
Y si las nubes recrearan...
Y como fue su vano en el viento mortal
Las palabras del diluvio
Y yo te acercas impacio para el sol
Muchacio insompa...
Nuestra red aprendió a hacer canciones como Spinetta.
OK: está bien, lo acepto. Todavía tiene algunos errores de vocabulario y las letras tal vez no tengan mucho sentido.
Aunque las letras generadas por una inteligencia artifical tengan estos pequeños defectos, podemos definitivamente observar que el modelo aprendió correctamente a copiar el estilo del dataset provisto.
Si consideramos el hecho de que la red aprendió todo desde cero, y que en un principio no tenía ningún entendimiento de lo que es una letra o una palabra (ni hablar de las reglas gramaticales del español) podemos estar de acuerdo que los resultados son sorprendentes. Fuimos capaces de detectar patrones lógicos en un dataset y reproducirlos: y en ningún momento se le dio a la red como input el idioma, las reglas de este o si lo que se estaba procesando eran imágenes de radiografías o las obras de Shakespeare.
Conclusiones y futuros pasos
En este artículo me propuse comparar dos métodos muy distintos para predecir textos. Por un lado, las Cadenas de Markov traen las ventajas de ser fáciles de implementar. No se necesitan grandes conocimientos teóricos ni tecnológicos para implementarlas: pero las predicciones son bastante básicas y dejaron mucho que desear. El futuro de este campo está claramente en la utilización de RNNs, incluso cuando implementarlas y testearlas lleva mucho tiempo, poder de procesamiento, espacio en disco o memoria para los tensores y un conocimiento técnico y teórico alto.
Para mejorar aun más la precisión, se podrían contrastar las predicciones en una etapa posterior contra un diccionario. Este puede estar compuesto por palabras únicas sacadas de la base de datos o por el Diccionario de la Lengua Española. De este modo, si la palabra predicha no está presente, eliminarla o cambiarla por la palabra con mayor similitud (menor distancia).
De nuevo, si lo desean, pueden ver mi código en mi cuenta pública de github.
Haciendo esta salvedad / tu mente ya estará progresando…
¿Cuánto faltará para que lleguen las letras artificiales? ¿Quién será el primero en sacarle jugo a este mercado? Ya hubo giras de hologramas de músicos fallecidos. Roy Orbison, Michael Jackson y Tupac son solo ejemplos. ¿Será esta nueva era de “música después de la muerte” la excusa perfecta para las letras artificiales?
¡Gracias por leer!