stldec_updated / tokenizer_stldec.py
saracandu's picture
Training in progress, step 500
baf16e0 verified
Raw
History Blame Contribute Delete
4.08 kB
import json
import os
import torch
from typing import Any, Dict, List, Optional, Tuple, Union
from transformers import PreTrainedTokenizer, AutoTokenizer
class STLTokenizer(PreTrainedTokenizer):
model_type = "stl_decoder"
def __init__(
self,
vocab_file="vocab.json",
unk_token="unk",
pad_token="pad",
bos_token="/s",
eos_token="s",
model_max_length=512,
**kwargs
):
current_dir = os.path.dirname(__file__)
full_vocab_path = os.path.join(current_dir, vocab_file)
if not os.path.exists(full_vocab_path):
from huggingface_hub import hf_hub_download
try:
full_vocab_path = hf_hub_download("saracandu/stldec_arch", vocab_file)
except:
full_vocab_path = vocab_file
with open(full_vocab_path, "r", encoding="utf-8") as f:
self.vocab = json.load(f)
self.id_to_token = {v: k for k, v in self.vocab.items()}
super().__init__(
unk_token=unk_token,
pad_token=pad_token,
bos_token=bos_token,
eos_token=eos_token,
model_max_length=model_max_length,
**kwargs
)
@property
def vocab_size(self) -> int:
return len(self.vocab)
def get_vocab(self) -> Dict[str, int]:
return dict(self.vocab)
def _tokenize(self, text: str) -> List[str]:
# 1. Pulizia drastica: separiamo solo le parole reali fornite in input.
# Rimuoviamo eventuali BOS/EOS se passati erroneamente come stringa.
text = text.replace(self.bos_token, "").replace(self.eos_token, "").strip()
raw_words = text.split()
final_tokens = []
# Aggiungiamo il BOS all'inizio della lista token
final_tokens.append(self.bos_token)
final_tokens.append("@")
for i, word in enumerate(raw_words):
if not word: continue
# 2. Match diretto o Longest Match
if word in self.vocab:
final_tokens.append(word)
else:
sub_i = 0
while sub_i < len(word):
best_match = None
# Cerchiamo dalla sottostringa più LUNGA alla più corta.
# Questo garantisce che 'always' vinca sempre su 's'.
for j in range(len(word), sub_i, -1):
subtoken = word[sub_i:j]
if subtoken in self.vocab:
best_match = subtoken
break
if best_match:
final_tokens.append(best_match)
sub_i += len(best_match)
else:
final_tokens.append(self.unk_token)
sub_i += 1
# 3. Inseriamo la chiocciola @ come marcatore di spazio tra le parole
if i < len(raw_words) - 1:
final_tokens.append("@")
# Aggiungiamo lo spazio e l'EOS alla fine
final_tokens.append("@")
final_tokens.append(self.eos_token)
return final_tokens
def _convert_token_to_id(self, token: str) -> int:
return self.vocab.get(token, self.vocab.get(self.unk_token))
def _convert_id_to_token(self, index: int) -> str:
return self.id_to_token.get(index, self.unk_token)
def save_vocabulary(self, save_directory: str, filename_prefix: Optional[str] = None) -> Tuple[str]:
if not os.path.isdir(save_directory):
os.makedirs(save_directory)
prefix = filename_prefix if filename_prefix is not None else ""
vocab_file = os.path.join(save_directory, prefix + "vocab.json")
with open(vocab_file, "w", encoding="utf-8") as f:
json.dump(self.vocab, f, indent=2, ensure_ascii=False)
return (vocab_file,)
try:
AutoTokenizer.register("stl_decoder", STLTokenizer)
except Exception:
pass