====== 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.