Setur/BRAGD
0322
1---2language:3- fo4license: cc-by-4.05library_name: transformers6pipeline_tag: token-classification7tags:8- faroese9- pos-tagging10- morphology11- xlm-roberta12- token-classification13- lrec-coling-202614base_model: vesteinn/ScandiBERT15model_creator: Setur16---17 18# BRAGD: Constrained Multi-Label POS Tagging for Faroese19 20BRAGD is a Faroese POS and morphological tagging model based on ScandiBERT. It predicts a **73-dimensional binary feature vector** for each token, covering word class, subcategory, gender, number, case, article, proper noun status, degree, declension, mood, voice, tense, person, and definiteness.21 22This Hugging Face repository contains a fine-tuned `XLMRobertaForTokenClassification` checkpoint with **73 output labels**, along with the decoding files `constraint_mask.json` and `tag_mappings.json`. The repository is currently published as a Transformers/XLM-RoBERTa safetensors model under `Setur/BRAGD`.23 24## Model Details25 26- **Model name:** BRAGD27- **Repository:** `Setur/BRAGD`28- **Architecture:** `XLMRobertaForTokenClassification`29- **Base model:** `vesteinn/ScandiBERT`30- **Task:** Faroese POS + morphological tagging31- **Output format:** 73 binary features per token, decoded into BRAGD tags32 33## Performance34 35In the accompanying paper, the constrained multi-label BRAGD model achieves:36 37- **97.5% composite tag accuracy** on the **Sosialurin-BRAGD** corpus (10-fold cross-validation)38- **96.2% composite tag accuracy** on **OOD-BRAGD** out-of-domain data39 40These numbers describe the evaluated research setup reported in the paper, not this release model trained on the combined data.41 42## Training Data43 44The model is based on the BRAGD annotation scheme for Faroese.45 46### Sosialurin-BRAGD47- **6,099 sentences**48- about **123k tokens**49- **651 unique tags**50- each tag decomposed into **73 binary features**51 52### OOD-BRAGD53- **500 sentences**54- mixed-genre out-of-domain Faroese evaluation data55 56The release model in this repository was trained on **both** datasets.57 58## Label Structure59 60The 73 output dimensions are organized as follows:61 62- **0–14:** Word class63- **15–29:** Subcategory64- **30–33:** Gender65- **34–36:** Number66- **37–41:** Case67- **42–43:** Article68- **44–45:** Proper noun69- **46–50:** Degree70- **51–53:** Declension71- **54–60:** Mood72- **61–63:** Voice73- **64–66:** Tense74- **67–70:** Person75- **71–72:** Definiteness76 77## Using the Model78 79This model predicts **feature vectors**, not directly formatted BRAGD tags. To get the final BRAGD tag and readable features, you should:80 811. run the model,822. select the most likely word class,833. activate only the valid feature groups for that word class using `constraint_mask.json`,844. map the resulting feature vector back to a BRAGD tag using `tag_mappings.json`.85 86### Install requirements87 88```bash89pip install numpy torch "transformers==4.57.1" sentencepiece huggingface_hub90```91 92### Python example93 94```python95import json96import numpy as np97import torch98from huggingface_hub import hf_hub_download99from transformers import XLMRobertaTokenizerFast, XLMRobertaForTokenClassification100 101model_name = "Setur/BRAGD"102 103tokenizer = XLMRobertaTokenizerFast.from_pretrained(model_name)104model = XLMRobertaForTokenClassification.from_pretrained(model_name)105model.eval()106 107# Download decoding assets108constraint_mask_path = hf_hub_download(model_name, "constraint_mask.json")109tag_mappings_path = hf_hub_download(model_name, "tag_mappings.json")110 111with open(constraint_mask_path, "r", encoding="utf-8") as f:112 raw_mask = json.load(f)113constraint_mask = {int(k): [tuple(x) for x in v] for k, v in raw_mask.items()}114 115with open(tag_mappings_path, "r", encoding="utf-8") as f:116 raw_map = json.load(f)117features_to_tag = {tuple(map(int, k.split(","))): v for k, v in raw_map.items()}118 119WORD_CLASS_NAMES = {120 0: "Noun",121 1: "Adjective",122 2: "Pronoun",123 3: "Number",124 4: "Verb",125 5: "Participle",126 6: "Adverb",127 7: "Conjunction",128 8: "Foreign",129 9: "Unanalyzed",130 10: "Abbreviation",131 11: "Web",132 12: "Punctuation",133 13: "Symbol",134 14: "Article",135}136 137INTERVAL_NAMES = {138 (15, 29): "subcategory",139 (30, 33): "gender",140 (34, 36): "number",141 (37, 41): "case",142 (42, 43): "article",143 (44, 45): "proper_noun",144 (46, 50): "degree",145 (51, 53): "declension",146 (54, 60): "mood",147 (61, 63): "voice",148 (64, 66): "tense",149 (67, 70): "person",150 (71, 72): "definiteness",151}152 153FEATURE_COLUMNS = [154 "S", "A", "P", "N", "V", "L", "D", "C", "F", "X", "T", "W", "K", "M", "R",155 "D", "B", "E", "I", "P", "Q", "N", "G", "R", "X", "S", "C", "O", "T", "s",156 "M", "F", "N", "g",157 "S", "P", "n",158 "N", "A", "D", "G", "c",159 "A", "a",160 "P", "r",161 "P", "C", "S", "A", "d",162 "S", "W", "e",163 "I", "M", "N", "S", "P", "E", "U",164 "A", "M", "v",165 "P", "A", "t",166 "1", "2", "3", "p",167 "D", "I",168]169 170def decode_token(logits):171 pred = np.zeros(logits.shape[0], dtype=int)172 173 # predict word class174 wc = int(np.argmax(logits[:15]))175 pred[wc] = 1176 177 # predict only valid feature groups for this word class178 for start, end in constraint_mask.get(wc, []):179 group = logits[start:end+1]180 pred[start + int(np.argmax(group))] = 1181 182 tag = features_to_tag.get(tuple(pred.tolist()), None)183 184 features = {"word_class": WORD_CLASS_NAMES.get(wc, str(wc))}185 for (start, end), name in INTERVAL_NAMES.items():186 group = pred[start:end+1]187 active = np.where(group == 1)[0]188 if len(active) == 1:189 features[name] = FEATURE_COLUMNS[start + active[0]]190 191 return tag, features192 193text = "Hetta er eitt føroyskt dømi"194words = text.split()195 196enc = tokenizer(197 [words],198 is_split_into_words=True,199 return_tensors="pt",200 padding=True,201 truncation=True,202)203 204with torch.no_grad():205 logits = model(**enc).logits[0]206 207word_ids = enc.word_ids(batch_index=0)208seen = set()209 210for i, word_id in enumerate(word_ids):211 if word_id is None or word_id in seen:212 continue213 seen.add(word_id)214 215 tag, features = decode_token(logits[i].cpu().numpy())216 print(f"{words[word_id]:15s} {str(tag):10s} {features}")217```218 219### Example output220 221```text222Hetta PDNpSN {'word_class': 'Pronoun', 'subcategory': 'D', 'gender': 'N', 'number': 'S', 'case': 'N', 'person': 'p'}223er VNAPS3 {'word_class': 'Verb', 'number': 'S', 'mood': 'N', 'voice': 'A', 'tense': 'P', 'person': '3'}224eitt RNSNI {'word_class': 'Article', 'gender': 'N', 'number': 'S', 'case': 'N', 'definiteness': 'I'}225føroyskt APSNSN {'word_class': 'Adjective', 'gender': 'N', 'number': 'S', 'case': 'N', 'degree': 'P', 'declension': 'S'}226dømi SNSNar {'word_class': 'Noun', 'gender': 'N', 'number': 'S', 'case': 'N', 'article': 'a', 'proper_noun': 'r'}227```228 229## Files in this Repository230 231This model repository contains model and decoding files, including:232 233- `model.safetensors`234- `config.json`235- tokenizer files236- `constraint_mask.json`237- `tag_mappings.json` :contentReference[oaicite:2]{index=2}238 239## Further Resources240 241For full training code, data preparation, and paper-related experiments, see the GitHub repository:242 243`https://github.com/Maltoknidepilin/BRAGD.git`244 245## Citation246 247```bibtex248@inproceedings{simonsen2026bragd,249 title={{BRAGD}: Constrained Multi-Label {POS} Tagging for {F}aroese},250 author={Simonsen, Annika and Scalvini, Barbara and Johannesen, Uni and Debess, Iben Nyholm and Einarsson, Hafsteinn and Sn{\ae}bjarnarson, V{\'e}steinn},251 booktitle={Proceedings of the 2026 Joint International Conference on Computational Linguistics, Language Resources and Evaluation (LREC-COLING 2026)},252 year={2026}253}254```255 256## Authors257 258Annika Simonsen, Barbara Scalvini, Uni Johannesen, Iben Nyholm Debess, Hafsteinn Einarsson, and Vésteinn Snæbjarnarson259 260## License261 262This repository is marked as **CC BY 4.0** on Hugging Face. :contentReference[oaicite:3]{index=3}