tov-tokenizer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: tov-tokenizer
3
+ Version: 0.1.0
4
+ Summary: Иерархический TOV-токенизатор с γ-кэшированием и λ-утечкой
5
+ Author: Артём Мехед
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/твой-логин/tov-tokenizer
8
+ Project-URL: Repository, https://github.com/твой-логин/tov-tokenizer
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: numpy>=1.19
16
+
17
+ # TOV Tokenizer
18
+
19
+ Иерархический токенизатор на основе Теории Относительности Всего (ТОВ).
20
+
21
+ ## Особенности
22
+
23
+ - 🌳 Иерархическое дерево (предложения → слова → подслова → символы)
24
+ - ⚡ γ-кэширование частых токенов
25
+ - 🧹 λ-утечка для редких токенов
26
+ - 🧠 Выбор токенов через потоки массы
27
+ - 🔄 Сохранение/загрузка состояния
28
+
29
+ ## Установка
30
+
31
+ ```bash
32
+ pip install tov-tokenizer
@@ -0,0 +1,16 @@
1
+ # TOV Tokenizer
2
+
3
+ Иерархический токенизатор на основе Теории Относительности Всего (ТОВ).
4
+
5
+ ## Особенности
6
+
7
+ - 🌳 Иерархическое дерево (предложения → слова → подслова → символы)
8
+ - ⚡ γ-кэширование частых токенов
9
+ - 🧹 λ-утечка для редких токенов
10
+ - 🧠 Выбор токенов через потоки массы
11
+ - 🔄 Сохранение/загрузка состояния
12
+
13
+ ## Установка
14
+
15
+ ```bash
16
+ pip install tov-tokenizer
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "tov-tokenizer"
7
+ version = "0.1.0"
8
+ description = "Иерархический TOV-токенизатор с γ-кэшированием и λ-утечкой"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Артём Мехед"}
12
+ ]
13
+ license = {text = "MIT"}
14
+ requires-python = ">=3.7"
15
+ dependencies = [
16
+ "numpy>=1.19",
17
+ ]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/твой-логин/tov-tokenizer"
27
+ Repository = "https://github.com/твой-логин/tov-tokenizer"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ """
2
+ TOV Tokenizer — иерархический токенизатор с γ-кэшированием.
3
+ """
4
+
5
+ from .core import TOVTokenizerTOV
6
+ from .graph import TokenGraph, TokenNode
7
+
8
+ __version__ = "0.1.0"
9
+ __all__ = ["TOVTokenizerTOV", "TokenGraph", "TokenNode"]
@@ -0,0 +1,310 @@
1
+ """
2
+ TOV Tokenizer: Токенизация через потоки массы.
3
+ Полностью на основе Теории Относительности Всего.
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ import numpy as np
9
+ import re
10
+ from collections import defaultdict
11
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
+
13
+ from .graph import TokenGraph, TokenNode
14
+
15
+ class TOVTokenizerTOV:
16
+ """
17
+ Токенизатор, работающий через TOV-граф.
18
+ - Иерархическое дерево токенов
19
+ - Выбор токенов через потоки массы
20
+ - γ-кэширование
21
+ - λ-утечка редких токенов
22
+ """
23
+
24
+ def __init__(self, vocab_size=5000, min_frequency=2):
25
+ self.vocab_size = vocab_size
26
+ self.min_frequency = min_frequency
27
+ self.graph = TokenGraph()
28
+
29
+ # 👇 СПЕЦТОКЕНЫ ВСЕГДА В ПЕРВУЮ ОЧЕРЕДЬ
30
+ self.specials = ['<pad>', '<unk>', '<sos>', '<eos>', '<sep>']
31
+ self.token_to_id = {}
32
+ self.id_to_token = {}
33
+
34
+ for i, spec in enumerate(self.specials):
35
+ self.token_to_id[spec] = i
36
+ self.id_to_token[i] = spec
37
+
38
+ self.stats = {
39
+ 'tokens_seen': 0,
40
+ 'unique_tokens': 0,
41
+ 'pruned_tokens': 0
42
+ }
43
+
44
+ def train(self, texts):
45
+ """
46
+ Обучает токенизатор на текстах.
47
+ Строит иерархическое дерево.
48
+ """
49
+ print(f"\n🌳 ОБУЧЕНИЕ TOV-ТОКЕНИЗАТОРА")
50
+ print(f" Текстов: {len(texts)}")
51
+
52
+ for i, text in enumerate(texts):
53
+ if i % 100 == 0 and i > 0:
54
+ print(f" Обработано {i}/{len(texts)} текстов")
55
+ self._add_text_to_graph(text)
56
+
57
+ # Применяем λ-утечку
58
+ pruned = self.graph.prune_rare_tokens(
59
+ threshold=0.01,
60
+ time_window=max(100, len(texts)//10)
61
+ )
62
+ self.stats['pruned_tokens'] = pruned
63
+
64
+ # Строим словарь из частотных токенов
65
+ self._build_vocab_from_graph()
66
+
67
+ print(f"✅ TOV-токенизатор готов:")
68
+ print(f" • Узлов в графе: {len(self.graph.nodes)}")
69
+ print(f" • Удалено редких: {pruned}")
70
+ print(f" • Размер словаря: {len(self.token_to_id)}")
71
+
72
+ def _add_text_to_graph(self, text):
73
+ """Добавляет текст в граф с иерархией"""
74
+ # Разбиваем на предложения
75
+ sentences = re.split(r'[.!?]+', text)
76
+
77
+ for sent in sentences:
78
+ if not sent.strip():
79
+ continue
80
+
81
+ # Добавляем предложение
82
+ sent_node = self.graph.add_token_node(
83
+ sent.strip(), sent[:30] + "...", "sentence"
84
+ )
85
+ self.graph.add_edge(str(self.graph.root.token_id), str(sent_node.token_id))
86
+ sent_node.update_frequency(self.graph.time_step)
87
+
88
+ # Разбиваем на слова
89
+ words = re.findall(r'\w+', sent.lower())
90
+
91
+ for word in words:
92
+ if len(word) < 2:
93
+ continue
94
+
95
+ # Добавляем слово
96
+ word_node = self.graph.add_token_node(word, word, "word")
97
+ self.graph.add_edge(str(sent_node.token_id), str(word_node.token_id))
98
+ word_node.update_frequency(self.graph.time_step)
99
+
100
+ # Разбиваем на подслова (2-4 символа)
101
+ subwords = self._generate_subwords(word)
102
+ for subword in subwords:
103
+ sub_node = self.graph.add_token_node(subword, subword, "subword")
104
+ self.graph.add_edge(str(word_node.token_id), str(sub_node.token_id))
105
+ sub_node.update_frequency(self.graph.time_step)
106
+
107
+ # Разбиваем на символы
108
+ for i, char in enumerate(word):
109
+ char_node = self.graph.add_token_node(
110
+ char, char, "char"
111
+ )
112
+ self.graph.add_edge(str(word_node.token_id), str(char_node.token_id))
113
+ char_node.update_frequency(self.graph.time_step)
114
+
115
+ self.graph.time_step += 1
116
+
117
+ def _generate_subwords(self, word, min_len=2, max_len=4):
118
+ """Генерирует подслова для BPE-like токенизации"""
119
+ subwords = []
120
+ word_len = len(word)
121
+ for length in range(min_len, min(max_len, word_len) + 1):
122
+ for i in range(word_len - length + 1):
123
+ subword = word[i:i+length]
124
+ subwords.append(subword)
125
+ return list(set(subwords)) # уникальные
126
+
127
+ def _build_vocab_from_graph(self):
128
+ """Строит словарь из графа, беря самые частотные узлы"""
129
+ if len(self.graph.nodes) <= 1:
130
+ print("⚠️ Граф пуст, использую только спецтокены")
131
+ return
132
+
133
+ # Сортируем узлы по частоте
134
+ nodes_by_freq = sorted(
135
+ self.graph.nodes.values(),
136
+ key=lambda n: n.frequency if hasattr(n, 'frequency') else 0,
137
+ reverse=True
138
+ )
139
+
140
+ # Обычные токены (начиная после спецтокенов)
141
+ idx = len(self.specials)
142
+ for node in nodes_by_freq:
143
+ if not hasattr(node, 'level') or node.level == 'root':
144
+ continue
145
+ if idx >= self.vocab_size:
146
+ break
147
+ if hasattr(node, 'token_str') and node.token_str not in self.token_to_id:
148
+ self.token_to_id[node.token_str] = idx
149
+ self.id_to_token[idx] = node.token_str
150
+ idx += 1
151
+
152
+ def save(self, path):
153
+ """Сохраняет токенизатор в файл"""
154
+ import pickle
155
+ data = {
156
+ 'vocab_size': self.vocab_size,
157
+ 'min_frequency': self.min_frequency,
158
+ 'token_to_id': self.token_to_id,
159
+ 'id_to_token': self.id_to_token,
160
+ 'specials': self.specials,
161
+ 'stats': self.stats,
162
+ 'graph': self.graph # сохраняем весь граф
163
+ }
164
+ with open(path, 'wb') as f:
165
+ pickle.dump(data, f)
166
+ print(f"💾 Токенизатор сохранён в {path}")
167
+
168
+ def load(self, path):
169
+ """Загружает токенизатор из файла"""
170
+ import pickle
171
+ with open(path, 'rb') as f:
172
+ data = pickle.load(f)
173
+
174
+ self.vocab_size = data['vocab_size']
175
+ self.min_frequency = data['min_frequency']
176
+ self.token_to_id = data['token_to_id']
177
+ self.id_to_token = data['id_to_token']
178
+ self.specials = data['specials']
179
+ self.stats = data['stats']
180
+ self.graph = data['graph']
181
+
182
+ print(f"📂 Токенизатор загружен из {path}")
183
+ print(f" Токенов: {len(self.token_to_id)}")
184
+ print(f" Узлов в графе: {len(self.graph.nodes)}")
185
+
186
+ def encode(self, text, add_special_tokens=True):
187
+ """
188
+ Токенизирует текст через потоки массы.
189
+ """
190
+ tokens = []
191
+
192
+ if add_special_tokens:
193
+ tokens.append(self.token_to_id['<sos>']) # теперь точно есть
194
+
195
+ # Разбиваем на предложения
196
+ sentences = re.split(r'[.!?]+', text)
197
+
198
+ for sent in sentences:
199
+ if not sent.strip():
200
+ continue
201
+
202
+ # Ищем узел предложения
203
+ sent_node = self._find_best_node(sent.strip(), 'sentence')
204
+ if sent_node and sent_node.token_str in self.token_to_id:
205
+ tokens.append(self.token_to_id[sent_node.token_str])
206
+
207
+ # Разбиваем на слова
208
+ words = re.findall(r'\w+', sent.lower())
209
+ for word in words:
210
+ # Ищем узел слова
211
+ word_node = self._find_best_node(word, 'word')
212
+ if word_node and word_node.token_str in self.token_to_id:
213
+ tokens.append(self.token_to_id[word_node.token_str])
214
+ else:
215
+ # Если слова нет, разбиваем на символы
216
+ for char in word:
217
+ char_node = self._find_best_node(char, 'char')
218
+ if char_node and char_node.token_str in self.token_to_id:
219
+ tokens.append(self.token_to_id[char_node.token_str])
220
+ else:
221
+ tokens.append(1) # <unk>
222
+
223
+ if add_special_tokens:
224
+ tokens.append(self.token_to_id['<eos>'])
225
+
226
+ return tokens
227
+
228
+ def _find_best_node(self, token_str, level):
229
+ """Находит лучший узел через поток массы"""
230
+ candidates = []
231
+ for node_id, node in self.graph.nodes.items():
232
+ if (hasattr(node, 'level') and node.level == level and
233
+ hasattr(node, 'token_str') and node.token_str == token_str):
234
+ candidates.append(node)
235
+
236
+ if not candidates:
237
+ return None
238
+
239
+ # Выбираем по потоку массы от корня
240
+ best_node = None
241
+ best_flow = -float('inf')
242
+
243
+ for node in candidates:
244
+ flow = node.core.a * node.core.output_mass
245
+ if flow > best_flow:
246
+ best_flow = flow
247
+ best_node = node
248
+
249
+ return best_node
250
+
251
+ def decode(self, ids, skip_special=True):
252
+ """
253
+ Декодирует токены обратно в текст.
254
+ """
255
+ text = []
256
+ for i in ids:
257
+ token = self.id_to_token.get(i, '<unk>')
258
+ if skip_special and token.startswith('<'):
259
+ continue
260
+ text.append(token)
261
+ return ' '.join(text)
262
+
263
+ def get_stats(self):
264
+ """Возвращает статистику токенизатора"""
265
+ stats = {
266
+ 'vocab_size': len(self.token_to_id),
267
+ 'graph_nodes': len(self.graph.nodes),
268
+ 'tokens_seen': self.graph.time_step,
269
+ 'pruned_tokens': self.stats['pruned_tokens']
270
+ }
271
+
272
+ # Добавляем статистику графа
273
+ try:
274
+ graph_stats = self.graph.get_stats()
275
+ stats.update(graph_stats)
276
+ except:
277
+ pass
278
+
279
+ return stats
280
+
281
+ def __len__(self):
282
+ """Возвращает размер словаря (нужно для len(tokenizer))"""
283
+ return len(self.token_to_id)
284
+
285
+ # ===================== ТЕСТ =====================
286
+
287
+ if __name__ == "__main__":
288
+ print("🚀 Тест TOVTokenizerTOV")
289
+
290
+ # Тестовые тексты
291
+ texts = [
292
+ "привет, как дела?",
293
+ "нормально, а у тебя?",
294
+ "отлично! погнали дальше"
295
+ ]
296
+
297
+ t = TOVTokenizerTOV(vocab_size=100)
298
+ t.train(texts)
299
+
300
+ for text in texts:
301
+ encoded = t.encode(text)
302
+ decoded = t.decode(encoded)
303
+ print(f"\n📝 Оригинал: {text}")
304
+ print(f" Токенов: {len(encoded)}")
305
+ print(f" Декод: {decoded}")
306
+
307
+ stats = t.get_stats()
308
+ print("\n📊 Статистика:")
309
+ for k, v in stats.items():
310
+ print(f" {k}: {v}")
@@ -0,0 +1,171 @@
1
+ """
2
+ TOV Token Graph: Иерархическое дерево токенов.
3
+ Предложение -> Слово -> Символ/Подслово.
4
+ """
5
+
6
+ import sys
7
+ import os
8
+ import numpy as np
9
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
10
+
11
+ # Вместо импорта внешних классов, создадим минимальные версии прямо здесь
12
+ class TOVCore:
13
+ """Минимальное ядро для токенизатора"""
14
+ def __init__(self, name="layer"):
15
+ self.name = name
16
+ self.a = 0.3
17
+ self.b = 0.4
18
+ self.c = 0.3
19
+ self.output_mass = 0.0
20
+ self.accumulated_mass = 0.0
21
+ self.gamma = 0.0
22
+ self.beta = 0.5
23
+
24
+ def add_learned_mass(self, delta):
25
+ self.accumulated_mass += delta
26
+ self.output_mass = self.accumulated_mass * self.beta
27
+
28
+ class TOVTreeNode:
29
+ """Минимальный узел для токенизатора"""
30
+ def __init__(self, token_id, embedding):
31
+ self.token_id = token_id
32
+ self.embedding = embedding
33
+ self.children = []
34
+ self.parent = None
35
+ self.core = TOVCore(f"node_{token_id}")
36
+ self.frequency = 0
37
+ self.last_seen = 0
38
+
39
+ def add_child(self, child_node):
40
+ self.children.append(child_node)
41
+ child_node.parent = self
42
+
43
+ class TokenNode(TOVTreeNode):
44
+ """Узел-токен с дополнительной информацией"""
45
+ def __init__(self, token_id, token_str, level, embedding=None):
46
+ super().__init__(token_id, embedding or np.zeros(20))
47
+ self.token_str = token_str
48
+ self.level = level # 'root', 'sentence', 'word', 'subword', 'char'
49
+ self.frequency = 0
50
+ self.last_seen = 0
51
+
52
+ def update_frequency(self, time_step):
53
+ self.frequency += 1
54
+ self.last_seen = time_step
55
+ # Масса растёт с частотой
56
+ self.core.add_learned_mass(0.1)
57
+
58
+ class TOVGraph:
59
+ """Минимальный граф для токенизатора"""
60
+ def __init__(self):
61
+ self.nodes = {}
62
+ self.root = None
63
+
64
+ def add_node(self, name, embedding=None):
65
+ """Добавляет узел в граф"""
66
+ if embedding is None:
67
+ embedding = np.zeros(20)
68
+ node = TOVTreeNode(name, embedding)
69
+ self.nodes[name] = node
70
+ return node
71
+
72
+ def add_edge(self, parent_id, child_id):
73
+ """Добавляет связь между узлами"""
74
+ if parent_id in self.nodes and child_id in self.nodes:
75
+ self.nodes[parent_id].add_child(self.nodes[child_id])
76
+
77
+ class TokenGraph:
78
+ """Граф для иерархической токенизации"""
79
+ def __init__(self):
80
+ self.nodes = {}
81
+ self.token_map = {} # token_str -> node_id
82
+ self.time_step = 0
83
+ self.root = self.add_token_node("<root>", "<root>", "root")
84
+
85
+ def add_token_node(self, token_str, display_str, level):
86
+ """Добавляет узел-токен в граф"""
87
+ token_id = hash(token_str) % 1000000 # простой хеш
88
+ node = TokenNode(token_id, display_str, level)
89
+ self.nodes[str(token_id)] = node
90
+ self.token_map[token_str] = str(token_id)
91
+ return node
92
+
93
+ def add_edge(self, parent_id, child_id):
94
+ """Добавляет связь между узлами"""
95
+ if parent_id in self.nodes and child_id in self.nodes:
96
+ self.nodes[parent_id].add_child(self.nodes[child_id])
97
+
98
+ def add_sequence(self, tokens, parent_node, level):
99
+ """Добавляет последовательность токенов как дочерние узлы"""
100
+ nodes = []
101
+ for token in tokens:
102
+ if token not in self.token_map:
103
+ node = self.add_token_node(token, token, level)
104
+ else:
105
+ node_id = self.token_map[token]
106
+ node = self.nodes[node_id]
107
+
108
+ self.add_edge(str(parent_node.token_id), str(node.token_id))
109
+ node.update_frequency(self.time_step)
110
+ nodes.append(node)
111
+
112
+ self.time_step += 1
113
+ return nodes
114
+
115
+ def prune_rare_tokens(self, threshold=0.01, time_window=1000):
116
+ """Удаляет редкие токены (λ-утечка)"""
117
+ current_time = self.time_step
118
+ to_prune = []
119
+
120
+ for node_id, node in self.nodes.items():
121
+ if not hasattr(node, 'level') or node.level == 'root':
122
+ continue
123
+
124
+ # Если токен не видели давно и частота низкая
125
+ age = current_time - node.last_seen
126
+ if age > time_window and node.frequency < threshold * time_window:
127
+ to_prune.append(node_id)
128
+
129
+ for node_id in to_prune:
130
+ # Удаляем из nodes
131
+ if node_id in self.nodes:
132
+ node = self.nodes[node_id]
133
+ # Удаляем из token_map
134
+ for token_str, tid in list(self.token_map.items()):
135
+ if tid == node_id:
136
+ del self.token_map[token_str]
137
+ # Удаляем сам узел
138
+ del self.nodes[node_id]
139
+
140
+ return len(to_prune)
141
+
142
+ def get_stats(self):
143
+ """Возвращает статистику графа"""
144
+ stats = {
145
+ 'total_nodes': len(self.nodes),
146
+ 'unique_tokens': len(self.token_map),
147
+ 'time_step': self.time_step
148
+ }
149
+
150
+ # Считаем по уровням
151
+ level_counts = {}
152
+ for node in self.nodes.values():
153
+ if hasattr(node, 'level'):
154
+ level_counts[node.level] = level_counts.get(node.level, 0) + 1
155
+ stats['levels'] = level_counts
156
+
157
+ return stats
158
+
159
+ # ===================== ТЕСТ =====================
160
+
161
+ if __name__ == "__main__":
162
+ print("🚀 Тест TokenGraph")
163
+ g = TokenGraph()
164
+ print(f"✅ Граф создан")
165
+ print(f" Узлов: {len(g.nodes)}")
166
+ print(f" Корень: {g.root.token_id}")
167
+
168
+ stats = g.get_stats()
169
+ print(f"\n📊 Статистика:")
170
+ for k, v in stats.items():
171
+ print(f" {k}: {v}")
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: tov-tokenizer
3
+ Version: 0.1.0
4
+ Summary: Иерархический TOV-токенизатор с γ-кэшированием и λ-утечкой
5
+ Author: Артём Мехед
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/твой-логин/tov-tokenizer
8
+ Project-URL: Repository, https://github.com/твой-логин/tov-tokenizer
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: numpy>=1.19
16
+
17
+ # TOV Tokenizer
18
+
19
+ Иерархический токенизатор на основе Теории Относительности Всего (ТОВ).
20
+
21
+ ## Особенности
22
+
23
+ - 🌳 Иерархическое дерево (предложения → слова → подслова → символы)
24
+ - ⚡ γ-кэширование частых токенов
25
+ - 🧹 λ-утечка для редких токенов
26
+ - 🧠 Выбор токенов через потоки массы
27
+ - 🔄 Сохранение/загрузка состояния
28
+
29
+ ## Установка
30
+
31
+ ```bash
32
+ pip install tov-tokenizer
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ tov_tokenizer/__init__.py
4
+ tov_tokenizer/core.py
5
+ tov_tokenizer/graph.py
6
+ tov_tokenizer.egg-info/PKG-INFO
7
+ tov_tokenizer.egg-info/SOURCES.txt
8
+ tov_tokenizer.egg-info/dependency_links.txt
9
+ tov_tokenizer.egg-info/requires.txt
10
+ tov_tokenizer.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ numpy>=1.19
@@ -0,0 +1 @@
1
+ tov_tokenizer