====== Trabajo Práctico 1 - Modelado de Lenguaje ====== [[materias:pln:2019|(volver a la página principal)]] En este trabajo práctico implementaremos modelos de lenguaje y realizaremos algunos experimentos con ellos. * Repositorio: https://github.com/PLN-FaMAF/PLN-2019. * Fecha de entrega: 28/3 4/4 a las 23:59. ===== Instrucciones ===== El código base para el proyecto se encuentra en el [[https://github.com/PLN-FaMAF/PLN-2019|repositorio de la materia]]. La entrega del proyecto es a través de github. Por lo tanto, deben **hacer un "fork" del repositorio** dentro de sus cuentas de github. Además del código fuente, **deben elaborar un README** con una breve explicación de lo que hicieron en cada ejercicio. El README puede estar en texto plano (txt), markdown (md) o restrucured text (rst), y debe estar incluído dentro de la carpeta ''languagemodeling''. Criterios de Evaluación: * Estilo de codificación (chequeado con pylint, flake8 y a ojo). * Diseño del código: uso de clases, herencia, etc. * Uso y aprobación de tests (provistos y definidos por uds.). * Uso apropiado de git (commits granulares, logs informativos). * Resultados. * README. ===== Ejercicio 1: Corpus ===== * Elegir corpus de texto en lenguaje natural de más de 5Mb de tamaño. * Cargar el corpus usando un "corpus reader" de NLTK (e.g. ''PlaintextCorpusReader'') o definiendo uno propio. * El "corpus reader" debe proveer un método ''sents'' que permita iterar sobre las oraciones tokenizadas del corpus. * Revisar a ojo la tokenización y segmentado en oraciones. Si es muy mala, probar otras formas de tokenización/segmentado. * Modificar el script ''train.py'' para utilizar el nuevo corpus. Interfaz de ''train.py'': $ python languagemodeling/scripts/train.py --help Train an n-gram model. Usage: train.py [-m ] -n -o train.py -h | --help Options: -n Order of the model. -m Model to use [default: ngram]: ngram: Unsmoothed n-grams. addone: N-grams with add-one smoothing. inter: N-grams with interpolation smoothing. -o Output model file. -h --help Show this screen. Documentación: * [[https://groups.google.com/forum/#!topic/pln-famaf-2015/KAa15XcqsXw|Ideas para corpus]] * [[https://github.com/crscardellino/sbwce/blob/master/unlabeled_corpora.tsv|Recursos del Spanish Billion Words Corpus (Cristian Cardellino)]] * [[http://www.nltk.org/book/ch03.html#regular-expressions-for-tokenizing-text|NLTK: Regular Expressions for Tokenizing Text]] * [[https://github.com/PLN-FaMAF/PLN-2019/blob/master/notebooks/01%20Procesamiento%20B%C3%A1sico%20de%20Texto.ipynb|Jupyter notebook: Tokenización (ejemplo visto en clase)]] * [[https://docs.python.org/3/howto/regex.html|Python 3: Regular Expression HOWTO]] ===== Ejercicio 2: Modelo de n-gramas ===== Implementar un modelo de n-gramas con marcadores de comienzo y fin de oración ('''' y ''''). Interfaz de la clase ''NGram'' (en ''ngram.py''): class NGram: def __init__(self, n, sents): """ n -- order of the model. sents -- list of sentences, each one being a list of tokens. """ def count(self, tokens): """Count for an n-gram or (n-1)-gram. tokens -- the n-gram or (n-1)-gram tuple. """ def cond_prob(self, token, prev_tokens=None): """Conditional probability of a token. token -- the token. prev_tokens -- the previous n-1 tokens (optional only if n = 1). """ def sent_prob(self, sent): """Probability of a sentence. Warning: subject to underflow problems. sent -- the sentence as a list of tokens. """ def sent_log_prob(self, sent): """Log-probability of a sentence. sent -- the sentence as a list of tokens. """ Tests: $ nosetests languagemodeling/tests/test_ngram.py Documentación: * [[http://nbviewer.jupyter.org/url/cs.famaf.unc.edu.ar/~francolq/Modelado%20de%20Lenguaje.ipynb#Contando-N-Gramas|Jupyter notebook: Contando N-Gramas (ejemplo visto en clase)]] * [[http://www.cs.columbia.edu/~mcollins/lm-spring2013.pdf|Language Modeling (Course notes for NLP by Michael Collins, Columbia University)]] ===== Ejercicio 3: Generación de Texto ===== * Implementar en ''ngram_generator.py'' una clase ''NGramGenerator'' para generar oraciones de lenguaje natural. * Usar el script ''generate.py'' para cargar un modelo de n-gramas y generar oraciones con él: * Generar oraciones usando n-gramas con n en {1, 2, 3, 4}. Armar una figura similar a la [[https://cs.famaf.unc.edu.ar/~francolq/Fig-4.3.png|Figura 4.3 de Jurafsky & Martin (2008)]]. Incluirla en el README. Funciones a implementar en ''ngram_generator.py'': class NGramGenerator: def __init__(self, model): """ model -- n-gram model. """ def generate_sent(self): """Randomly generate a sentence.""" def generate_token(self, prev_tokens=None): """Randomly generate a token, given prev_tokens. prev_tokens -- the previous n-1 tokens (optional only if n = 1). """ Interfaz de ''generate.py'': $ python languagemodeling/scripts/generate.py --help Generate natural language sentences using a language model. Usage: generate.py -i -n generate.py -h | --help Options: -i Language model file. -n Number of sentences to generate. -h --help Show this screen. Tests: $ nosetests languagemodeling/tests/test_ngram_generator.py Documentación: * [[http://nbviewer.jupyter.org/url/cs.famaf.unc.edu.ar/~francolq/Modelado%20de%20Lenguaje.ipynb#Generando-Lenguaje-Natural|Jupyter notebook: Generando Lenguaje Natural (ejemplo visto en clase)]] * [[https://cs.famaf.unc.edu.ar/~francolq/Fig-4.3.png|Figura 4.3 de Jurafsky & Martin (2008)]] * [[https://en.wikipedia.org/wiki/Pseudo-random_number_sampling#Finite_discrete_distributions|Pseudo-random number sampling (Wikipedia)]] ===== Ejercicio 4: Suavizado "add-one" ===== * Implementar el suavizado "add-one" en ''ngram.py'' en una clase ''AddOneNGram''. * La clase debe tener **la misma interfaz que ''NGram''** más el método ''V'' especificado abajo. * Calcular V como el tamaño del alfabeto incluyendo el marcador ''''. * Agregar al script de entrenamiento (''train.py'') una opción de línea de comandos que permita utilizar add-one en lugar de n-gramas clásicos. Interfaz de la clase ''AddOneNGram'' (en ''ngram.py''): class AddOneNGram: """ Todos los métodos de NGram. """ def V(self): """Size of the vocabulary. """ Tests: $ nosetests languagemodeling/tests/test_addone_ngram.py Documentación: * [[http://nbviewer.jupyter.org/url/cs.famaf.unc.edu.ar/~francolq/Modelado%20de%20Lenguaje%20Parte%202.ipynb#Suavizado-"add-one"|Jupyter notebook: Suavizado "add-one" (ejemplo visto en clase)]] ===== Ejercicio 5: Evaluación de Modelos de Lenguaje ===== * Separar el corpus en entrenamiento y test (90% y 10% resp.). * Implementar el cálculo de log-probability, cross-entropy y perplejidad en la clase ''ngram.LanguageModel''. * Programar un script ''eval.py'' para cargar un modelo de lenguajes y evaluarlo sobre el conjunto de test. * Usar el script ''train.py'' para entrenar el modelo "add one" y guardar las instancias resultantes para varios valores de n (1, 2, 3 y 4). * Usar el script ''eval.py'' para calcular la perplejidad de los modelos entrenados en el ejercicio anterior. Reportar los resultados en el README. Interfaz de ''eval.py'': $ python languagemodeling/scripts/eval.py --help Evaulate a language model using the test set. Usage: eval.py -i eval.py -h | --help Options: -i Language model file. -h --help Show this screen. Documentación: * {{ :materias:pln:2019:lm-notas.pdf |Modelado de Lenguaje: Notas Complementarias}} * Mails: * [[https://groups.google.com/forum/#!topic/pln-famaf-2015/29EwJKp5nrY|Resultados típicos de perplexity para todos los modelos]] ===== Ejercicio 6: Suavizado por Interpolación ===== * Implementar el suavizado por interpolación en ''ngram.py'' en una clase ''InterpolatedNGram''. * Calcular lambdas en términos de un único parámetro gamma (ver documentación abajo). * **Usar add-one para el nivel más bajo (unigramas).** * Usar datos held-out (un 10% de train) y barrido para elegir valor para gamma. * Agregar al script de entrenamiento (''train.py'') una opción de línea de comandos que permita utilizar este modelo. * Calcular y reportar perplejidad para varios valores de ''n'' (1, 2, 3 y 4). Reportar los resultados en el README. Interfaz de la clase ''InterpolatedNGram'' (en ''ngram.py''): class InterpolatedNGram: def __init__(self, n, sents, gamma=None, addone=True): """ n -- order of the model. sents -- list of sentences, each one being a list of tokens. gamma -- interpolation hyper-parameter (if not given, estimate using held-out data). addone -- whether to use addone smoothing (default: True). """ """ Todos los métodos de NGram. """ Tests: $ nosetests languagemodeling/tests/test_interpolated_ngram.py Documentación: * [[http://www.cs.columbia.edu/~mcollins/lm-spring2013.pdf|Language Modeling (Course notes for NLP by Michael Collins, Columbia University)]] * **Especialmente** [[https://cs.famaf.unc.edu.ar/~francolq/Ejercicio%204.png|esta parte]] (última parte de la sección 1.4.1). * {{ :materias:pln:2019:lm-notas.pdf |Modelado de Lenguaje: Notas Complementarias}} * [[https://www.youtube.com/watch?v=-aMYz1tMfPg&list=PL6397E4B26D00A269&index=17|4 - 6 - Interpolation - Stanford NLP - Professor Dan Jurafsky & Chris Manning]] * [[http://nbviewer.jupyter.org/url/cs.famaf.unc.edu.ar/~francolq/Modelado%20de%20Lenguaje%20Parte%202.ipynb#Suavizado-por-Interpolación|Jupyter notebook: Suavizado por Interpolación (ejemplo visto en clase)]] * Mails: * [[https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/pln-famaf-2015/bgGUVGg4lv8/ltiMoEpzCAAJ|Consulta sobre interpolaciòn]] * [[https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/pln-famaf-2017/S3rTQAbf6oU/RbjH0IdYBwAJ|Preguntas sobre InterpolatedNGram]] * [[https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/pln-famaf-2017/N_QwDjmQT-I/1pkx5VSeCQAJ|Barrido para elegir valor para Gamma]] ===== Ejercicio 7: Suavizado por Back-Off con Discounting ===== * Implementar el suavizado por back-off con discounting en ''ngram.py'' en una clase ''BackOffNGram''. * Usar add-one para el nivel más bajo (unigramas). * Usar datos held-out (un 10% de train) y barrido para elegir valor para beta. * Agregar al script de entrenamiento (train.py) una opción de línea de comandos que permita utilizar este modelo. * Calcular y reportar perplejidad para varios valores de ''n'' (1, 2, 3 y 4). Reportar los resultados en el README. Interfaz de la clase ''BackOffNGram'' (en ''ngram.py''): class BackOffNGram: def __init__(self, n, sents, beta=None, addone=True): """ Back-off NGram model with discounting as described by Michael Collins. n -- order of the model. sents -- list of sentences, each one being a list of tokens. beta -- discounting hyper-parameter (if not given, estimate using held-out data). addone -- whether to use addone smoothing (default: True). """ """ Todos los métodos de NGram. """ def A(self, tokens): """Set of words with counts > 0 for a k-gram with 0 < k < n. tokens -- the k-gram tuple. """ def alpha(self, tokens): """Missing probability mass for a k-gram with 0 < k < n. tokens -- the k-gram tuple. """ def denom(self, tokens): """Normalization factor for a k-gram with 0 < k < n. tokens -- the k-gram tuple. """ Tests: $ nosetests languagemodeling/tests/test_backoff_ngram.py Documentación: * [[http://www.cs.columbia.edu/~mcollins/lm-spring2013.pdf|Language Modeling (Course notes for NLP by Michael Collins, Columbia University)]] * {{ :materias:pln:2019:lm-notas.pdf |Modelado de Lenguaje: Notas Complementarias}} * [[https://www.youtube.com/watch?v=hsHw9F3UuAQ&index=3&list=PLO9y7hOkmmSHE2v_oEUjULGg20gyb-v1u|Discounting Methods - Part I]] (Michael Collins, Columbia University) * [[https://www.youtube.com/watch?v=FedWcgXcp8w&index=4&list=PLO9y7hOkmmSHE2v_oEUjULGg20gyb-v1u|Discounting Methods - Part II]] (Michael Collins, Columbia University) ===== Ejercicio 8 (punto bonus): Reordenamiento de Palabras ó Atribución de Autoría ===== * Elegir y resolver uno de los dos ejercicios siguientes de Jurafsky & Martin (2008): * Ejercicio 4.9: Reordenamiento de palabras. * Ejercicio 4.10: Atribución de autoría ([[https://en.wikipedia.org/wiki/Stylometry|Stylometry]]). * Sobre el ejercicio 4.9: * Implementar una clase que, dada una lista de palabras desordenadas de una oración, devuelva el ordenamiento más probable de acuerdo a un modelo de lenguaje. * Implementar un script que tome el conjunto de test y para cada oración, la desordene y la vuelva a ordenar usando un modelo de lenguaje dado como parámetro. * Usar las métricas BLEU y distancia de edición para evaluar la calidad de los reordenamientos (respecto de las oraciones originales). En NLTK: * ''nltk.metrics.distance.edit_distance'' * ''nltk.align.bleu_score.bleu'' * Sobre el ejercicio 4.10: * Se requiere tener documentos de dos o más clases diferentes. Por ejemplo, escritos de dos autores diferentes. * Definir conjuntos de entrenamiento y test para cada clase (90% y 10% resp.). * Entrenar un modelo de lenguaje para cada clase, siguiendo las indicaciones del libro. * Implementar un script que tome los conjuntos de test y adivine a qué clase corresponde cada uno.