teszenofficial commited on
Commit
40c7704
·
verified ·
1 Parent(s): 960de33

Delete tokenizer.py

Browse files
Files changed (1) hide show
  1. tokenizer.py +0 -213
tokenizer.py DELETED
@@ -1,213 +0,0 @@
1
- import sentencepiece as spm
2
- import os
3
- import json
4
-
5
-
6
- class MTPTokenizer:
7
- """Tokenizer mejorado usando SentencePiece BPE con optimizaciones"""
8
-
9
- def __init__(self, model_path=None):
10
- self.sp = None
11
- self.model_path = model_path
12
-
13
- if model_path and os.path.exists(model_path):
14
- self.load(model_path)
15
-
16
- def train(self, corpus_path, vocab_size=8000, model_prefix='mtp_tokenizer'):
17
- """
18
- Entrena tokenizer SentencePiece BPE optimizado
19
- Mejoras:
20
- - Mejor manejo de caracteres especiales
21
- - Vocabulario más grande para mejor cobertura
22
- - Optimizaciones para español
23
- """
24
-
25
- print(f"🔤 Entrenando tokenizer BPE...")
26
-
27
- # Extraer texto del corpus JSONL
28
- texts = []
29
- total_chars = 0
30
-
31
- with open(corpus_path, 'r', encoding='utf-8') as f:
32
- for line in f:
33
- try:
34
- data = json.loads(line)
35
- if 'instruction' in data:
36
- texts.append(data['instruction'])
37
- total_chars += len(data['instruction'])
38
- if 'response' in data:
39
- texts.append(data['response'])
40
- total_chars += len(data['response'])
41
- except json.JSONDecodeError:
42
- continue
43
-
44
- print(f" ✅ Corpus stats:")
45
- print(f" • {len(texts)} textos")
46
- print(f" • {total_chars:,} caracteres")
47
-
48
- # Calcular vocab size óptimo
49
- # Heurística: vocab_size debe ser ~10-15% de caracteres únicos
50
- unique_chars = len(set(''.join(texts)))
51
- suggested_vocab = min(vocab_size, max(1000, int(total_chars * 0.12)))
52
-
53
- print(f" 📊 Caracteres únicos: {unique_chars}")
54
- print(f" 📊 Vocab sugerido: {suggested_vocab}")
55
-
56
- # Usar el vocab size solicitado o el sugerido (el menor)
57
- final_vocab = min(vocab_size, suggested_vocab)
58
- print(f" ✅ Vocab final: {final_vocab}")
59
-
60
- # Guardar corpus temporal
61
- temp_file = 'temp_corpus.txt'
62
- with open(temp_file, 'w', encoding='utf-8') as f:
63
- f.write('\n'.join(texts))
64
-
65
- # Entrenar SentencePiece con configuración optimizada
66
- try:
67
- spm.SentencePieceTrainer.train(
68
- input=temp_file,
69
- model_prefix=model_prefix,
70
- vocab_size=final_vocab,
71
- model_type='bpe',
72
- pad_id=0,
73
- unk_id=1,
74
- bos_id=2,
75
- eos_id=3,
76
- character_coverage=1.0, # 100% cobertura para español
77
- normalization_rule_name='identity', # No normalizar
78
- num_threads=os.cpu_count() or 4,
79
- split_digits=True, # Separar dígitos
80
- allow_whitespace_only_pieces=False,
81
- byte_fallback=True, # Activar byte fallback para caracteres raros
82
- max_sentencepiece_length=16,
83
- add_dummy_prefix=True, # Mejor para español
84
- remove_extra_whitespaces=True,
85
- # Optimizaciones adicionales
86
- train_extremely_large_corpus=False,
87
- vocabulary_output_piece_score=True
88
- )
89
- print(f" ✅ Tokenizer entrenado exitosamente")
90
-
91
- except RuntimeError as e:
92
- if "Vocabulary size too high" in str(e):
93
- # Extraer max sugerido y reintentar
94
- import re
95
- match = re.search(r'value <= (\d+)', str(e))
96
- if match:
97
- max_vocab = int(match.group(1))
98
- print(f" ⚠️ Vocab size muy alto, reintentando con {max_vocab}...")
99
-
100
- spm.SentencePieceTrainer.train(
101
- input=temp_file,
102
- model_prefix=model_prefix,
103
- vocab_size=max_vocab,
104
- model_type='bpe',
105
- pad_id=0,
106
- unk_id=1,
107
- bos_id=2,
108
- eos_id=3,
109
- character_coverage=1.0,
110
- normalization_rule_name='identity',
111
- num_threads=os.cpu_count() or 4,
112
- split_digits=True,
113
- allow_whitespace_only_pieces=False,
114
- byte_fallback=True,
115
- max_sentencepiece_length=16,
116
- add_dummy_prefix=True,
117
- remove_extra_whitespaces=True
118
- )
119
- print(f" ✅ Tokenizer entrenado con vocab={max_vocab}")
120
- else:
121
- raise
122
- else:
123
- raise
124
-
125
- # Limpiar archivo temporal
126
- os.remove(temp_file)
127
-
128
- # Cargar el modelo entrenado
129
- self.model_path = f"{model_prefix}.model"
130
- self.load(self.model_path)
131
-
132
- # Estadísticas finales
133
- print(f"\n✅ Tokenizer listo:")
134
- print(f" • Vocab size: {self.vocab_size()}")
135
- print(f" • Model: {self.model_path}")
136
- print(f" • Tokens especiales:")
137
- print(f" PAD: {self.pad_id()}")
138
- print(f" UNK: {self.unk_id()}")
139
- print(f" BOS: {self.bos_id()}")
140
- print(f" EOS: {self.eos_id()}")
141
-
142
- # Test del tokenizer
143
- test_text = "Hola, ¿cómo estás? Este es un test del tokenizer."
144
- test_tokens = self.encode(test_text)
145
- test_decoded = self.decode(test_tokens)
146
- print(f"\n🧪 Test del tokenizer:")
147
- print(f" Original: {test_text}")
148
- print(f" Tokens: {test_tokens[:10]}... ({len(test_tokens)} total)")
149
- print(f" Decoded: {test_decoded}")
150
-
151
- def load(self, model_path):
152
- """Carga un tokenizer entrenado"""
153
- self.sp = spm.SentencePieceProcessor()
154
- self.sp.load(model_path)
155
- self.model_path = model_path
156
-
157
- def encode(self, text):
158
- """Codifica texto a IDs de tokens"""
159
- if self.sp is None:
160
- raise ValueError("Tokenizer no cargado. Entrena o carga un modelo primero.")
161
- return self.sp.encode_as_ids(text)
162
-
163
- def decode(self, ids):
164
- """Decodifica IDs de tokens a texto"""
165
- if self.sp is None:
166
- raise ValueError("Tokenizer no cargado. Entrena o carga un modelo primero.")
167
- return self.sp.decode_ids(ids)
168
-
169
- def encode_batch(self, texts):
170
- """Codifica múltiples textos (más eficiente)"""
171
- if self.sp is None:
172
- raise ValueError("Tokenizer no cargado. Entrena o carga un modelo primero.")
173
- return [self.sp.encode_as_ids(text) for text in texts]
174
-
175
- def decode_batch(self, ids_list):
176
- """Decodifica múltiples secuencias de IDs"""
177
- if self.sp is None:
178
- raise ValueError("Tokenizer no cargado. Entrena o carga un modelo primero.")
179
- return [self.sp.decode_ids(ids) for ids in ids_list]
180
-
181
- def vocab_size(self):
182
- """Obtiene el tamaño del vocabulario"""
183
- if self.sp is None:
184
- return 0
185
- return self.sp.get_piece_size()
186
-
187
- def bos_id(self):
188
- """ID del token de inicio de secuencia"""
189
- return self.sp.bos_id() if self.sp else 2
190
-
191
- def eos_id(self):
192
- """ID del token de fin de secuencia"""
193
- return self.sp.eos_id() if self.sp else 3
194
-
195
- def pad_id(self):
196
- """ID del token de padding"""
197
- return self.sp.pad_id() if self.sp else 0
198
-
199
- def unk_id(self):
200
- """ID del token desconocido"""
201
- return self.sp.unk_id() if self.sp else 1
202
-
203
- def id_to_piece(self, token_id):
204
- """Convierte un ID a su pieza de texto"""
205
- if self.sp is None:
206
- return ""
207
- return self.sp.id_to_piece(token_id)
208
-
209
- def piece_to_id(self, piece):
210
- """Convierte una pieza de texto a su ID"""
211
- if self.sp is None:
212
- return self.unk_id()
213
- return self.sp.piece_to_id(piece)