#!/usr/bin/env python # coding: utf-8 # # Modelado de Lenguaje Parte 2 # # # ## Suavizado "add-one" # # Probamos con un modelo de bigramas (n=2) entrenado con las siguientes dos oraciones: # In[4]: sents = [ 'el gato come pescado .'.split(), 'la gata come salmón .'.split(), ] # Luego, los conteos de bigramas y unigramas incluirán, entre otras cosas, los siguientes elementos: # In[10]: count = { ('el',): 1, ('come',): 2, # ... mas unigramas ... ('el', 'gato'): 1, ('come', 'pescado'): 1, ('come', 'salmón'): 1, # ... mas bigramas ... } # Calculemos algunas probabilidades sin "add one" de ejemplo: # In[24]: def cond_prob(token, prev_tokens): tokens = prev_tokens + (token,) return float(count.get(tokens, 0)) / float(count.get(prev_tokens, 0)) print(cond_prob('gato', ('el',))) print(cond_prob('pollo', ('el',))) # print(cond_prob('pollos', ('los',))) print(cond_prob('pescado', ('come',))) # o salmón print(cond_prob('salame', ('come',))) # o salmón # Ahora calculemos las mismas probabilidades pero con el suavizado "add one": # In[25]: voc = {'el', 'gato', 'come', 'pescado', '.', '', 'la', 'gata', 'salmón'} V = len(voc) def add_one_cond_prob(token, prev_tokens): tokens = prev_tokens + (token,) return float(count.get(tokens, 0) + 1) / float(count.get(prev_tokens, 0) + V) print(add_one_cond_prob('gato', ('el',))) print(add_one_cond_prob('pollo', ('el',))) # print(cond_prob('pollos', ('los',))) print(add_one_cond_prob('pescado', ('come',))) # o salmón print(add_one_cond_prob('salame', ('come',))) # o salmón # Tareas pendientes: # - Ninguna, diría. Sólo pasar este código a la clase AddOneNGram en ngram.py. # ## Suavizado por Interpolación # Esta vez probamos con un modelo de trigramas. Supongamos los siguientes conteos: # In[45]: count = { ('come',): 2, # ... más unigramas ... ('gato', 'come'): 1, ('come', 'pescado'): 1, ('come', 'salmón'): 1, # ... más bigramas ... ('gato', 'come', 'pescado'): 1, # ... más trigramas ... } def cond_prob(token, prev_tokens): tokens = prev_tokens + (token,) return float(count.get(tokens, 0)) / float(count.get(prev_tokens, 0)) # Y veamos el caso de interpolación específico para 3-gramas: # In[50]: gamma = 1 def interpolated_cond_prob(token, prev_tokens): cond_ml1 = cond_prob(token, prev_tokens) # 2-uple: (u,v) cond_ml2 = cond_prob(token, prev_tokens[1:]) # 1-uple: (v,) cond_ml3 = add_one_cond_prob(token, prev_tokens[2:]) # 0-uple: () lambda1 = count[prev_tokens] / (count[prev_tokens] + gamma) lambda2 = (1 - lambda1) * count[prev_tokens[1:]] / (count[prev_tokens[1:]] + gamma) lambda3 = 1 - (lambda1 + lambda2) prob = lambda1 * cond_ml1 + lambda2 * cond_ml2 + lambda3 * cond_ml3 return prob # cond_prob('pescado', ('gato', 'come')) print(interpolated_cond_prob('pescado', ('gato', 'come'))) print(interpolated_cond_prob('salmón', ('gato', 'come'))) print(interpolated_cond_prob('salame', ('gato', 'come'))) # Puede verse cómo afecta el parámetro gamma al suavizado (a maś grande, más fuerte el suavizado). # # Tareas pendientes: # - Generalizar el cálculo de la interpolación para n-gramas en general.