Esportare le annotazioni verso Hugging Face Datasets
Come convertire le annotazioni di Potato nel formato Hugging Face Datasets: struttura dell'export JSON, creazione della dataset card, caricamento sull'Hub e uso con l'addestramento in transformers.
Se addestri modelli, prima o poi i dati dovranno diventare un dataset Hugging Face. È quello che il resto dell'ecosistema si aspetta. Questa guida mostra come trasformare l'output di annotazione di Potato in quel formato con qualche breve script Python, sia che tu addestri in locale sia che voglia condividere il dataset sull'Hub.
Perché usare il formato Hugging Face
È il formato che gli strumenti già conoscono, quindi non devi scrivere codice di raccordo per ogni libreria. I dataset sono salvati in Arrow, che si carica in fretta anche quando diventano grandi. Per condividerli basta una chiamata a push_to_hub. E Trainer li legge direttamente, senza passaggi di conversione prima dell'addestramento.
Export di base con Python
Potato scrive le annotazioni in JSONL. La libreria datasets le trasforma in un dataset Hugging Face.
Caricare le annotazioni di Potato
import json
from datasets import Dataset
# Load Potato annotation output
annotations = []
with open("annotation_output/annotated_instances.jsonl", "r") as f:
for line in f:
annotations.append(json.loads(line))
# Convert to Hugging Face Dataset
dataset = Dataset.from_list([
{
"text": ann["text"],
"label": ann["label_annotations"]["sentiment"]["label"]
}
for ann in annotations
])
# Save locally
dataset.save_to_disk("my_dataset")
# Or push to Hub
dataset.push_to_hub("username/my-dataset")Creare gli split di train e test
from sklearn.model_selection import train_test_split
# Split annotations
train_data, temp_data = train_test_split(annotations, test_size=0.2, random_state=42)
val_data, test_data = train_test_split(temp_data, test_size=0.5, random_state=42)
# Create datasets
train_dataset = Dataset.from_list(train_data)
val_dataset = Dataset.from_list(val_data)
test_dataset = Dataset.from_list(test_data)
# Combine into DatasetDict
from datasets import DatasetDict
dataset = DatasetDict({
"train": train_dataset,
"validation": val_dataset,
"test": test_dataset
})Export per tipo di task
Classificazione del testo
from datasets import Dataset, ClassLabel
# Load and process sentiment annotations
dataset = Dataset.from_dict({
"text": [ann["text"] for ann in annotations],
"label": [ann["label_annotations"]["sentiment"]["label"] for ann in annotations]
})
# Define label mapping
dataset = dataset.cast_column(
"label",
ClassLabel(names=["Positive", "Negative", "Neutral"])
)Riconoscimento di entità nominate
# Convert span annotations to IOB format
def convert_to_iob(text, spans):
tokens = text.split()
labels = ["O"] * len(tokens)
for span in spans:
# Map character offsets to token indices
start_token, end_token = char_to_token(text, span["start"], span["end"])
labels[start_token] = f"B-{span['annotation']}"
for i in range(start_token + 1, end_token):
labels[i] = f"I-{span['annotation']}"
return tokens, labels
# Potato stores span annotations in span_annotations field
dataset = Dataset.from_dict({
"tokens": [convert_to_iob(a["text"], a.get("span_annotations", {}).get("entities", []))[0] for a in annotations],
"ner_tags": [convert_to_iob(a["text"], a.get("span_annotations", {}).get("entities", []))[1] for a in annotations]
})Classificazione audio
from datasets import Audio
# For audio annotation tasks
dataset = Dataset.from_dict({
"audio": [ann["audio"] for ann in annotations],
"label": [ann["label_annotations"]["emotion"]["label"] for ann in annotations]
})
# Cast to Audio feature
dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))Classificazione di immagini
from datasets import Image
# For image annotation tasks
dataset = Dataset.from_dict({
"image": [ann["image"] for ann in annotations],
"label": [ann["label_annotations"]["category"]["label"] for ann in annotations]
})
dataset = dataset.cast_column("image", Image())Export con più annotatori
Quando hai più annotatori per elemento, puoi esportare in formati diversi:
# Long format (one row per annotation)
# Each annotator's work is saved in a separate file: annotator_{id}.jsonl
import glob
records = []
for filepath in glob.glob("annotation_output/annotator_*.jsonl"):
annotator_id = filepath.split("_")[-1].replace(".jsonl", "")
with open(filepath) as f:
for line in f:
ann = json.loads(line)
records.append({
"id": ann["id"],
"text": ann["text"],
"label": ann["label_annotations"]["sentiment"]["label"],
"annotator": annotator_id
})
dataset = Dataset.from_list(records)
# Or aggregate annotations per item
from collections import defaultdict
from statistics import mode
items = defaultdict(list)
for record in records:
items[record["id"]].append(record)
aggregated = []
for item_id, anns in items.items():
labels = [a["label"] for a in anns]
aggregated.append({
"id": item_id,
"text": anns[0]["text"],
"label": mode(labels), # Majority vote
"num_annotators": len(labels)
})
dataset = Dataset.from_list(aggregated)Caricare sull'Hugging Face Hub
from huggingface_hub import login
# Login (or use HF_TOKEN env var)
login()
# Push dataset
dataset.push_to_hub(
"username/my-sentiment-dataset",
private=False,
token=None # Uses cached token
)
# With dataset card
dataset.push_to_hub(
"username/my-sentiment-dataset",
commit_message="Initial upload of sentiment annotations",
)Dataset card
Crea il README.md del tuo dataset:
---
license: cc-by-4.0
task_categories:
- text-classification
language:
- en
size_categories:
- 1K<n<10K
---
# My Sentiment Dataset
## Dataset Description
Sentiment annotations collected using [Potato](https://potato.iro.umich.edu).
## Dataset Structure
- **train**: 8,000 examples
- **validation**: 1,000 examples
- **test**: 1,000 examples
### Labels
- Positive
- Negative
- Neutral
## Annotation Process
Annotated by 3 workers per item on Prolific.
Inter-annotator agreement (Fleiss' Kappa): 0.75
## Citation
@article{...}Caricare il tuo dataset
from datasets import load_dataset
# From Hub
dataset = load_dataset("username/my-sentiment-dataset")
# From local
dataset = load_dataset("my_dataset/")
# Use for training
from transformers import Trainer
trainer = Trainer(
model=model,
train_dataset=dataset["train"],
eval_dataset=dataset["validation"],
...
)Qualche abitudine da tenersi
Annota da dove vengono i dati, come sono stati etichettati e quale accordo hai misurato, perché chi riuserà il dataset lo chiederà. Definisci ogni etichetta a parole invece di dare per scontato che il nome si spieghi da sé. Versiona il dataset, così sai che cosa è cambiato tra un rilascio e l'altro. Cita la metodologia di annotazione. E dichiara subito la licenza, così nessuno deve tirare a indovinare se può usarlo.
Per le opzioni di export che Potato offre direttamente, vedi la documentazione sull'export verso Hugging Face.
Documentazione completa sull'export su Formati di Dati.