XLM-RoBERTa-CRF-VotIE: Portuguese Voting Information Extraction
This model is a fine-tuned XLM-RoBERTa Base with a Conditional Random Fields (CRF) layer for extracting structured voting information from Portuguese municipal meeting minutes. It achieves strong performance on the Citilink dataset.
Model Description
XLM-RoBERTa-CRF-VotIE combines Facebook AI's multilingual XLM-RoBERTa encoder with a CRF layer for structured sequence prediction. The model performs token-level classification to identify and extract voting-related entities from Portuguese administrative text.
Key Features
Architecture: XLM-RoBERTa Base (768-dim, 12 layers, 12 heads, absolute positional attention) + Linear + CRF
Task: Sequence Labeling with BIO tagging
Language: Portuguese (Portugal)
Domain: Municipal meeting minutes and voting records
Entity Types: 12 types (25 labels with BIO encoding, full B/I pairs for all types)
Performance: 95.28% entity-level F1 score
Intended Uses
This model is designed for:
Extracting voting information from Portuguese municipal documents
Identifying participants and their voting positions (favor, against, abstention, absent)
Recognizing voting subjects and counting methods
Structuring unstructured administrative text
Research in information extraction from Portuguese administrative documents
Entity Types
The model recognizes 12 entity types in BIO format (25 labels total, full B/I pairs for every type):
Entity Type
Description
Example
VOTER-FAVOR
Participants who voted in favor
"The Municipal Executive"
VOTER-AGAINST
Participants who voted against
"João Silva"
VOTER-ABSTENTION
Participants who abstained
"The councilor from PS"
VOTER-ABSENT
Participants who were absent
"Ana Simões"
VOTING
Voting action expressions
"deliberado", "aprovado"
SUBJECT
The subject matter being voted on
"budget changes"
COUNTING-UNANIMITY
Unanimous vote indicators
"unanimously"
COUNTING-MAJORITY
Majority vote indicators
"by majority"
COUNT-FAVOR
Numeric count of votes in favor
"5 votes in favor"
COUNT-AGAINST
Numeric count of votes against
"3 votes against"
COUNT-BLANK
Numeric count of blank votes
"0 blank votes"
VOTING-METHOD
Method of voting
"by secret scrutiny"
Training Details
Training Data
The model was trained on the Citilink dataset (https://rdm.inesctec.pt/dataset/cs-2025-007), which consists of Portuguese municipal meeting minutes annotated with voting information:
Training set: 1,737 examples
Validation set: 433 examples
Test set: 529 examples
Total tokens: ~300K tokens
Total entities: ~5K entities
Training Procedure
Hyperparameters:
Base model: FacebookAI/xlm-roberta-base
Batch size: 16
Learning rate: 5e-5 (linear decay)
Warmup proportion: 0.1
Max grad norm: 1.0
Dropout: 0.1
Max sequence length: 512 tokens
Epochs: 10 (best checkpoint at epoch 7)
Optimizer: AdamW
Early stopping patience: 3 epochs
Loss: CRF negative log-likelihood
Results
Entity-Level Performance (Test Set, 529 examples)
Metric
Strict
Relaxed (boundary)
F1 Score
95.28%
97.70%
Precision
95.05%
98.87%
Recall
95.55%
96.75%
Accuracy
98.74%
—
Per-Entity Performance (Strict)
Entity Type
Precision
Recall
F1 Score
Support
COUNT-BLANK
80.00%
80.00%
80.00%
5
COUNT-FAVOR
100.00%
100.00%
100.00%
4
COUNTING-MAJORITY
100.00%
100.00%
100.00%
59
COUNTING-UNANIMITY
99.69%
99.39%
99.54%
326
SUBJECT
76.82%
80.45%
78.59%
486
VOTER-ABSENT
100.00%
94.44%
97.14%
18
VOTER-ABSTENTION
95.74%
100.00%
97.83%
135
VOTER-AGAINST
97.30%
100.00%
98.63%
36
VOTER-FAVOR
95.99%
97.80%
96.88%
318
VOTING
100.00%
98.98%
99.49%
489
VOTING-METHOD
100.00%
100.00%
100.00%
5
Usage
Quick Start
The simplest way to use the model:
python
1from transformers import AutoTokenizer, AutoModel
23# Load model4model_name ="Anonymous3445/XLM-RoBERTa-CRF-VotIE"5tokenizer = AutoTokenizer.from_pretrained(model_name)6model = AutoModel.from_pretrained(model_name, trust_remote_code=True)78# Analyze text9text ="O Executivo deliberou aprovar o projeto por unanimidade."10inputs = tokenizer(text, return_tensors="pt")11predictions = model.decode(**inputs, tokenizer=tokenizer, text=text)1213# Print results14for pred in predictions:15print(f"{pred['word']:20}{pred['label']}")
Output:
O B-VOTER-FAVOR
Executivo I-VOTER-FAVOR
deliberou B-VOTING
aprovar O
o O
projeto O
por B-COUNTING-UNANIMITY
unanimidade. I-COUNTING-UNANIMITY
Extract Structured Entities
The model includes a convenient extract_entities method:
python
1from transformers import AutoTokenizer, AutoModel
23model_name ="Anonymous3445/XLM-RoBERTa-CRF-VotIE"4tokenizer = AutoTokenizer.from_pretrained(model_name)5model = AutoModel.from_pretrained(model_name, trust_remote_code=True)67text ="""A Câmara Municipal deliberou aprovar a proposta apresentada pelo
8Senhor Presidente. Votaram a favor os Senhores Vereadores João Silva e
9Maria Costa. Votou contra o Senhor Vereador Pedro Santos."""1011# Get structured entities with character offsets12entities = model.extract_entities(text, tokenizer)1314# Print entities by type15for entity_type, mentions in entities.items():16print(f"\n{entity_type}:")17for mention in mentions:18print(f" - {mention['text']} [{mention['start']}:{mention['end']}]")
Output:
VOTER-FAVOR:
- A Câmara Municipal [0:19]
- João Silva [95:105]
- Maria Costa [108:119]
VOTING:
- deliberou [20:29]
VOTER-AGAINST:
- Pedro Santos [152:164]
1from transformers import AutoTokenizer, AutoModel
23model_name ="Anonymous3445/XLM-RoBERTa-CRF-VotIE"4tokenizer = AutoTokenizer.from_pretrained(model_name)5model = AutoModel.from_pretrained(model_name, trust_remote_code=True)67text ="O Executivo deliberou aprovar o projeto por unanimidade."8inputs = tokenizer(text, return_tensors="pt")910# Get predictions with character positions11predictions = model.decode(**inputs, tokenizer=tokenizer, text=text, return_offsets=True)1213# Show only entities (non-O tags)14for pred in predictions:15if pred['label']!='O':16print(f"{pred['word']:20}{pred['label']:25} [{pred['start']}:{pred['end']}]")
Output:
O B-VOTER-FAVOR [0:1]
Executivo I-VOTER-FAVOR [2:11]
deliberou B-VOTING [12:21]
por B-COUNTING-UNANIMITY [39:42]
unanimidade. I-COUNTING-UNANIMITY [43:55]
Batch Processing
For processing multiple documents:
python
1from transformers import AutoTokenizer, AutoModel
23model_name ="Anonymous3445/XLM-RoBERTa-CRF-VotIE"4tokenizer = AutoTokenizer.from_pretrained(model_name)5model = AutoModel.from_pretrained(model_name, trust_remote_code=True)67texts =[8"A proposta foi aprovada por unanimidade.",9"Votou contra o Vereador João Silva.",10"O Presidente estava ausente na votação."11]1213for text in texts:14 entities = model.extract_entities(text, tokenizer, return_offsets=False)15print(f"\nText: {text}")16for entity_type, mentions in entities.items():17print(f" {entity_type}: {[m['text']for m in mentions]}")
Limitations and Bias
Limitations
Domain-specific: Trained specifically on Portuguese municipal meeting minutes; may not generalize well to other document types
Portuguese only: Optimized for European Portuguese
Sequence length: Limited to 512 tokens per window (handles longer documents via windowing)
Entity types: Limited to 12 predefined voting-related entity types
Complex sentences: May struggle with highly complex or nested voting descriptions