¿Cómo iniciar el entrenamiento de un modelo marcobiano latente?
Empezar con el entrenamiento de un modelo marcobiano latente puede parecer complicado al principio, pero con los pasos correctos, la tarea se simplifica considerablemente. Para este propósito, utilizamos Google Colab para escribir el código que permite ejecutar dicho entrenamiento. Inicialmente, debemos enfocarnos en calcular los conteos necesarios, estableciendo un sistema en el que cada elemento del diccionario represente específicamente la frecuencia de las etiquetas, emisiones y transiciones.
¿Cómo estructurar los diccionarios iniciales?
Etiquetas: Esta entrada en el diccionario contará cuántas veces aparece cada etiqueta en el corpus.
Emisiones: Aquí, se registrará cuántas veces una etiqueta específica corresponde a una determinada palabra.
Transiciones: Indica cuántas veces una etiqueta previa está seguida por otra en una posición subsecuente.
¿Cómo leer el corpus y contar etiquetas?
La lectura del corpus es un paso esencial donde se sugiere el uso de la convención de etiquetas gramaticales universal. Usamos un doble for pues cada elemento del corpus es una lista de tokens, procesando uno a uno.
# Inicialización del diccionario de etiquetastag_counts ={}# Leer el corpusfor token_list in corpus: previous_tag =Nonefor token in token_list:# Obtener la etiqueta actual tag = token.tag_type # Asumiendo que el token tiene este atributo# Contar etiquetasif tag in tag_counts: tag_counts[tag]+=1else: tag_counts[tag]=1
¿Cómo calcular las probabilidades de emisión y transición?
Es fundamental establecer las probabilidades de dos tipos: de emisión y de transición. Ambas juegan un papel crucial en el correcto funcionamiento del modelo.
¿Cómo calcular las probabilidades de emisión?
El cálculo de probabilidades de emisión requiere crear una cadena que refleje la combinación de la palabra en minúsculas y su etiqueta. Similar al conteo de etiquetas, las verificaciones aseguran que los conteos sean precisos.
# Inicialización del diccionario de emisionesemission_counts ={}for token_list in corpus:for token in token_list: word = token.word.lower() tag = token.tag_type
# Crear el par palabra-etiqueta como clave pair =f"{word}|{tag}"if pair in emission_counts: emission_counts[pair]+=1else: emission_counts[pair]=1
¿Cómo manejar las probabilidades de transición?
El cálculo de transiciones añade otra capa de complejidad al involucrar etiquetas previas. A medida que recorremos el corpus, actualizamos constantemente la etiqueta previa para reflejar correctamente las probabilidades.
# Inicialización del diccionario de transicionestransition_counts ={}for token_list in corpus: previous_tag =Nonefor token in token_list: tag = token.tag_type
if previous_tag isnotNone: prev_current_pair =f"{previous_tag}|{tag}"if prev_current_pair in transition_counts: transition_counts[prev_current_pair]+=1else: transition_counts[prev_current_pair]=1 previous_tag = tag
¿Cómo se guardan y utilizan las probabilidades calculadas?
Después de conseguir todos los conteos, transformamos estos en probabilidades de transición y emisión. Luego, guardamos estas en archivos utilizables, lo cual es esencial para futuros procedimientos de predicciones.
¿Cómo almacenar las probabilidades?
Usamos la librería NumPy para guardar cada conjunto de probabilidades en archivos separados, fortaleciendo la eficiencia en almacenamiento y acceso para aplicaciones posteriores. Este paso es clave para avanzar a predicciones concretas del modelo.
import numpy as np
np.save("transition_probabilities.npy", transition_probabilities)np.save("emission_probabilities.npy", emission_probabilities)
Este proceso culmina en un modelo marcobiano latente completado y almacenado, listo para ser utilizado en secuencias de palabras y obtener las etiquetas más probables correspondientes. ¡Sigue adelante y descubre cómo aplicar esta poderosa técnica en aplicaciones del mundo real!
Para las personas que el transitionDict les da vacío, hay que hacer una pequeña corrección:
El profe define prevtag = None después de los dos ciclos for.
Por lo tanto cada vez que itero el valro de prevtag vuelve aser None y siempre se repite la primera iteración para el TransitionDict.
Para corregirlo hay que definir prevtag = None antes de los dos ciclos for.
Saludos.
Que hombre tan genial! 👍🏼
Qué detallazo! Gracias buenhombre!
para hacer un sort sobre estos diccionarios basados en los valores de las probabilidades encontradas.
agradecido con el de arriba en todos los cursos :).
Creo que en el cálculo de emissionProbDict la condicion del if debío ser:
if tagCountDict[tag]>0:
Claro por que estamos contando las etiquetas mayores a 0 para calcular la probabilidad.
Gracias por darte cuenta 👍🏼
Probabilidades de Transición:
Las probabilidades de transición se refieren a la probabilidad de que una cierta etiqueta gramatical siga a otra en una secuencia de palabras. En el contexto del etiquetado gramatical, esto significa entender qué tan probable es que una palabra tenga una cierta etiqueta gramatical dada la etiqueta gramatical de la palabra anterior.
Probabilidades de Emisión:
Las probabilidades de emisión se refieren a la probabilidad de que una palabra específica sea emitida dado que tiene una cierta etiqueta gramatical. En otras palabras, ¿cuán probable es que una palabra pertenezca a una categoría gramatical específica?
La ecuacion de Probabilidades de Emisión tiene un pequeño error, el numerador de la ecuacion debe ser el siguiente
C(word,tag)
en lugar de
C(word|tag)
Es entendible que se perciba como un error, puesto que en el curso hay un enrredo tremendo de nomenclatura... En el curso se entiende a C(A, B) como el conteo de elementos consecutivos de A a B presentes en una secuencia y no al conteo de ocaciones en que los eventos A y B ocurren al mismo tiempo.
En este caso C(word, tag) puede ser percibido como "conteo de word seguido de tag", lo cual no tiene sentido, ya que word y tag no pertenecen al mismo espacio muestral...
Yo me quedaría con "C(word|tag)" a pesar del error de nomenclatura, ya que al menos está definido en esta misma clase.
Genial esta clase!
Concatenar elementos usando un separador como la barra vertical (|) para crear llaves de diccionario (por ejemplo, palabra|etiqueta) es un truco de optimización altamente efectivo. Aunque en Python podrías usar tuplas como ("palabra", "etiqueta") para las llaves de un diccionario, las cadenas de texto simples suelen ser más rápidas de procesar, serializar y exportar cuando manejas millones de registros.
Piensa en esto como crear un código de barras único para cada combinación en tu inventario de palabras. Si tienes la palabra "banco" como institución financiera y "banco" como asiento, el modelo necesita distinguirlas instantáneamente. Al fusionarlas en banco|NOUN y banco|VERB, creas identificadores inmutables que el motor de búsqueda interno de Python (el hash map del diccionario) encuentra en tiempo constante. Además, al momento de guardar estos datos en archivos externos o bases de datos, el formato de texto plano evita problemas de compatibilidad que a veces surgen al exportar estructuras de datos complejas como las tuplas anidadas.
🧠 Entrenamiento de un Modelo Marcobiano Latente
🚀 1. Objetivo del modelo
Aprender las relaciones entre palabras y sus etiquetas gramaticales para predecir la etiqueta más probable dentro de una secuencia.
👉 Ideal para tareas de procesamiento de lenguaje natural (PLN).
🧩 2. Requisitos previos
🔹 Google Colab → para programar y ejecutar el modelo.
🔹 Corpus etiquetado → lista de oraciones con palabras y sus etiquetas (ej: VERB, NOUN, ADJ).
🔹 Librería NumPy → para guardar las probabilidades calculadas.
⚙️ 3. Estructura base: tres diccionarios
📘 Etiquetas (tag_counts)
Cuántas veces aparece cada etiqueta.
Ejemplo: VERB = 540, NOUN = 890
💬 Emisiones (emission_counts)
Cuántas veces una palabra aparece con cierta etiqueta.
Ejemplo: “gato|NOUN”, “corre|VERB”
🔄 Transiciones (transition_counts)
Cuántas veces una etiqueta sigue a otra.
Ejemplo: “DET|NOUN” (de “el perro”).
🧮 4. Flujo de trabajo paso a paso
1️⃣ Leer el corpus
Recorre cada oración (lista de tokens).
2️⃣ Contar etiquetas
Guarda la frecuencia de cada etiqueta.
No deberia obtener -1 en el ultimo de ellos considerando que el count de transitionDict se hace con una entrada menos?
Cada línea contiene las siguientes columnas:
Índice de la palabra en la oración.
La palabra original.
La forma raíz o lema de la palabra.
La categoría gramatical (POS).
La etiqueta POS detallada.
Otros detalles sintácticos.
Que locura todo este tema, estoy fascinado con la computación. La verdad no soy el más habilidoso en matemáticas y algoritmos, pero de lo que he ido comprendiendo me ha volado la cabeza. Por cierto, que buen profesor!
Viendo la calidad de la clase, la importancia del tema y los pocos comentarios, entiende uno por que no se sigue con este nivel de profundidad, parece que en general no son las clases con mayor acogida :(.
Muy muy buena clase
Código corregido
<tag_count_dict ={}emission_dict ={}transition_dict ={}tagtype ='upos'data_file =open('UD_Spanish-AnCora/es_ancora-ud-dev.conllu','r', encoding='utf-8')prevtag =Nonefor tokenlist inparse_incr(data_file):for token intokenlist: #C(tag) tag = token[tagtype]if tag in tag_count_dict.keys(): tag_count_dict[tag]+=1else: tag_count_dict[tag]=1 #C(word|tag)-> probabilidades de emision
word_tag = token['form'].lower()+'|'+token[tagtype]if word_tag in emission_dict.keys(): emission_dict[word_tag]+=1else: emission_dict[word_tag]=1 # C(tag|tag_previo)-> probabilidades de transición
if prevtag is None: prevtag = tag
continue transitiontags = tag +'|'+ prevtag
if transitiontags in transition_dict.keys(): transition_dict[transitiontags]= transition_dict[transitiontags]+1else: transition_dict[transitiontags]=1 prevtag = tag
>
La posición de "prevtag = None" es incorrecta en tu aporte. La forma correcta es:
for tokenlist inparse_incr(data_file): prevtag =Nonefor token intokenlist:
La explicación de esto está en un comentario más arriba.
Saludos.
Para quienes no entiendan el concepto de "El corpus", es un conjunto de textos suficientemente grande de muestras reales de una lengua determinada.
que bien
Estoy usando el mismo código de la clase pero obtengo un diccionario vacío para transitionDict. El resto funcional perfecto. ¿Alguien sabe donde está el error?
tagCountDict ={}emissionDict ={}transitionDict ={}tagtype ='upos'data_file =open("UD_Spanish-AnCora/es_ancora-ud-dev.conllu","r", encoding="utf-8")for tokenlist inparse_incr(data_file):for token intokenlist: prevtag =None # C(tag) tag = token[tagtype]if tag in tagCountDict.keys(): tagCountDict[tag]+=1else: tagCountDict[tag]=1 # C(word|tag) wordtag = token['form'].lower()+'|'+ token[tagtype] #(word|tag)if wordtag in emissionDict.keys(): emissionDict[wordtag]+=1else: emissionDict[wordtag]=1 # C(tag|tag(previo))-> probabilidades transición
if prevtag is None: prevtag = tag
continue transitiontags = tag +'|'+ prevtag
if transtiontags in transitionDict.keys(): transitionDict[transitiontags]= transitionDict[transitiontags]+1else: transitionDict[transitiontags]=1 prevtag = tag```
Javier si, es porque el profe define prevtag = None después de los dos ciclos for.
Por lo tanto cada vez que itero el valro de prevtag vuelve aser None y siempre se repite la primera iteración para el TransitionDict.
Para corregirlo define prevtag = None antes de los dos ciclos for.
jejejj y asi es como un modelo equivale a dos diccionarios :smiley: muy bueno