Skip to content
Tutoriales7 min de lectura

Construyendo Tu Primera Tarea de Anotación NER

Guía paso a paso para crear una tarea de reconocimiento de entidades nombradas en Potato, con la configuración de spans, colores de etiquetas, spans superpuestos, atajos de teclado y exportación a CoNLL.

Potato Team

Este tutorial construye en Potato una tarea de reconocimiento de entidades nombradas (NER) con cinco tipos de entidad, atajos con las teclas numéricas, instrucciones para los anotadores y una exportación a CoNLL-2003 para entrenar modelos. Para las opciones de configuración de spans que hay detrás, consulta la documentación de anotación de spans.

Lo que recibe el anotador

La tarea terminada presenta al anotador una oración con una fila de botones etiquetados encima. El anotador arrastra sobre una frase para seleccionarla, pulsa una tecla numérica o hace clic en un botón para etiquetarla, y vuelve a hacer clic en un span etiquetado para cambiarlo o eliminarlo. Cada span se guarda con sus desplazamientos de caracteres, de modo que el mismo archivo de anotaciones sirve tanto para una exportación a CoNLL-2003 como para un cálculo de acuerdo a nivel de span.

Requisitos Previos

Necesitas Potato instalado, un archivo de datos de texto y el YAML suficiente para editar una configuración:

bash
pip install potato-annotation

Paso 1: El esquema de spans

La anotación de spans es el tipo span de Potato. Cada etiqueta necesita un nombre, y los campos opcionales útiles son color, que distingue visualmente los tipos de entidad en un texto denso, key_value, que asocia un atajo de teclado a la etiqueta, y tooltip, que muestra la definición de la etiqueta al pasar el cursor para que los anotadores no tengan que salir de la página para consultar el libro de códigos.

Con cinco tipos la tarea se puede aprender en una sola sesión. A partir de unos ocho, los anotadores empiezan a consultar las guías en cada elemento, y ahí es donde cae el rendimiento. sequential_key_binding activa las teclas numéricas, y key_value fija qué número corresponde a cada etiqueta en lugar de dejarlo al orden de la lista. Crea config.yaml:

yaml
annotation_task_name: "Named Entity Recognition"
task_dir: "."
 
data_files:
  - data/sentences.json
 
item_properties:
  id_key: id
  text_key: text
 
output_annotation_dir: "annotation_output/"
export_annotation_format: "jsonl"
 
annotation_schemes:
  - annotation_type: span
    name: entities
    description: "Highlight and label named entities in the text"
    sequential_key_binding: true
    labels:
      - name: PER
        tooltip: "Person names, including fictional characters"
        color: "#FF6B6B"
        key_value: "1"
      - name: ORG
        tooltip: "Companies, institutions, agencies"
        color: "#4ECDC4"
        key_value: "2"
      - name: LOC
        tooltip: "Places, including countries, cities, landmarks"
        color: "#45B7D1"
        key_value: "3"
      - name: DATE
        tooltip: "Dates, times, and temporal expressions"
        color: "#96CEB4"
        key_value: "4"
      - name: MISC
        tooltip: "Named entities that fit none of the above"
        color: "#FFEAA7"
        key_value: "5"
 
user_config:
  allow_all_users: true

Paso 2: El archivo de datos

Potato lee un objeto JSON por línea y toma los campos indicados en item_properties. Crea data/sentences.json:

json
{"id": "1", "text": "Apple Inc. announced that CEO Tim Cook will visit Paris next Tuesday."}
{"id": "2", "text": "The United Nations headquarters in New York hosted delegates from Japan."}
{"id": "3", "text": "Dr. Sarah Johnson published her research at Stanford University in March 2024."}

Tres oraciones bastan para comprobar que la interfaz funciona. Carga el corpus real cuando el conjunto de etiquetas haya superado una prueba piloto.

Paso 3: Instrucciones al alcance del anotador

La mayor parte del desacuerdo en NER proviene de las reglas de límites y no de los tipos de entidad en sí, así que las reglas que deciden más elementos deben estar en la pantalla de anotación. annotation_instructions se muestra como un panel plegable en la parte superior de cada elemento, abierto por defecto, que los anotadores pliegan cuando ya conocen la tarea. Añade este bloque a la configuración anterior:

yaml
annotation_instructions: |
  ## Entity types
 
  - **PER** covers people, including fictional characters ("John Smith", "Dr. Johnson", "Batman")
  - **ORG** covers companies, institutions, and agencies ("Apple Inc.", "United Nations", "Stanford University")
  - **LOC** covers places, including countries, cities, and landmarks ("Paris", "New York", "Mount Everest")
  - **DATE** covers dates, times, and temporal expressions ("Tuesday", "March 2024", "next week")
  - **MISC** covers named entities that fit none of the above ("Nobel Prize", "iPhone", "COVID-19")
 
  ## Boundary rules
 
  1. Include titles (Dr., Mr.) with person names.
  2. For nested entities, annotate the largest meaningful span.
  3. Leave articles (the, a) outside the span.

Aquí se renderiza Markdown, así que puedes copiar el mismo texto de tu libro de códigos sin reescribirlo como HTML. Limita este panel a las reglas que resuelven la mayoría de los elementos y deja el libro de códigos completo detrás de annotation_codebook_url, que se abre en su propia pestaña.

La interfaz de spans muestra entonces las etiquetas como botones sobre el texto:

Interfaz de anotación de spans de entidades nombradas con tipos de entidad codificados por colorLos anotadores resaltan spans de texto y asignan etiquetas de entidad como PER, ORG, LOC y DATE

Paso 4: Ejecutar la tarea

Inicia el servidor con la configuración del Paso 1:

bash
potato start config.yaml

Abre la dirección que imprime e inicia sesión. A partir de ahí, el anotador realiza cuatro acciones por entidad:

  1. Seleccionar el texto. Haz clic y arrastra sobre la frase.
  2. Asignar el tipo. Pulsa la tecla numérica o haz clic en el botón de la etiqueta.
  3. Corregir un error. Haz clic en un span existente para cambiar su etiqueta o eliminarlo.
  4. Enviar. Pasa al siguiente elemento cuando termines la oración.

Paso 5: Qué contiene el archivo de salida

Cada elemento anotado se escribe en annotation_output/ como un objeto JSON, con el nombre del esquema como clave y una entrada por span:

json
{
  "id": "1",
  "text": "Apple Inc. announced that CEO Tim Cook will visit Paris next Tuesday.",
  "entities": [
    {"start": 0, "end": 10, "label": "ORG", "text": "Apple Inc."},
    {"start": 30, "end": 38, "label": "PER", "text": "Tim Cook"},
    {"start": 50, "end": 55, "label": "LOC", "text": "Paris"},
    {"start": 61, "end": 73, "label": "DATE", "text": "next Tuesday"}
  ]
}

Los desplazamientos de caracteres son lo que hace útil el archivo en etapas posteriores. Sobreviven a los cambios de tokenización, así que las mismas anotaciones pueden realinearse con el tokenizador que use tu modelo.

Paso 6: Exportar a CoNLL-2003

Los modelos de etiquetado de secuencias leen tokens etiquetados y no desplazamientos de caracteres, así que Potato convierte los spans al exportar:

bash
python -m potato.export -c config.yaml -f conll_2003 -o ./conll_export/

El resultado es un token por línea con su etiqueta, con líneas en blanco entre oraciones. La opción tag_scheme escribe BIO, BIOES o IOB, con BIO como valor por defecto, así que ajústala a lo que espere tu código de entrenamiento antes de ejecutar la exportación.

Afinar las guías

Las reglas imprecisas producen decisiones divididas sobre el mismo span, así que vale la pena revisarlas mientras la prueba piloto todavía es pequeña. Repasa los casos difíciles con los anotadores antes de que empiecen y no después, y mantén una lista compartida de casos límite resueltos a medida que aparezcan. Una caída del acuerdo entre anotadores es la señal de que una regla necesita ajustarse, y detectarla en 50 elementos cuesta menos que en 5000.

Próximos Pasos