====== Trabajo Práctico 1 - Modelado de Lenguaje ======
[[materias:pln|(volver a la página principal)]]
En este trabajo práctico implementaremos varios modelos de lenguaje y
realizaremos algunos experimentos con ellos.
* Repositorio: https://github.com/PLN-FaMAF/PLN-2015/tree/practico1.
* Fecha de entrega: 16/09 23/09 a las 23:59.
===== Instrucciones =====
El código base para el proyecto se encuentra en el [[https://github.com/PLN-FaMAF/PLN-2015/tree/practico1|branch ''practico1'' del repositorio del a 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 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 correcta tokenización y segmentado en oraciones. De ser necesario, probar otras formas de tokenización/segmentado.
* Modificar el script ''train.py'' para utilizar nuestro corpus.
Documentación:
* http://www.nltk.org/howto/corpus.html
* http://www.nltk.org/book/ch03.html#regular-expressions-for-tokenizing-text
* http://www.nltk.org/_modules/nltk/tokenize/punkt.html
* Ejemplo dado en clase de cómo tokenizar con expresiones regulares: http://nbviewer.ipython.org/url/cs.famaf.unc.edu.ar/~francolq/Tokenizaci%C3%B3n%20con%20NLTK.ipynb
* [[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
===== Ejercicio 3: Generación de Texto =====
* Implementar en ''ngram.py'' una clase ''NGramGenerator'' para generar oraciones de lenguaje natural.
* Programar un 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 Figura 4.3 de Jurafsky & Martin (2008). Incluirla en el README.
Funciones a implementar en ''ngram.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:
* https://en.wikipedia.org/wiki/Inverse_transform_sampling
===== 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.
* Entrenar sobre nuestro corpus y guardar los modelos resultantes para varios valores de n (1, 2, 3 y 4).
Interfaz de la clase ''AddOneNGram'' (en ''ngram.py''):
class AddOneNGram:
"""
Todos los métodos de NGram.
"""
def V(self):
"""Size of the vocabulary.
"""
Nueva interfaz de ''train.py'':
$ python languagemodeling/scripts/train.py --help
Train an n-gram model.
Usage:
train.py -n [-m ] -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.
-o Output model file.
-h --help Show this screen.
Tests:
$ nosetests languagemodeling/tests/test_addone_ngram.py
===== 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.
* Programar un script ''eval.py'' para cargar un modelo de lenguajes y evaluarlo sobre el conjunto de test.
* Calcular 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.
===== 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
* https://class.coursera.org/nlangp-001/lecture/55
* https://class.coursera.org/nlangp-001/lecture/57
===== 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
* https://class.coursera.org/nlangp-001/lecture/51
* https://class.coursera.org/nlangp-001/lecture/53
===== 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.
* 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.