improve
Browse files- README.md +6 -1
- benchmark.py +52 -0
- mana_tokenizer.py +77 -5
README.md
CHANGED
@@ -19,11 +19,16 @@ text = "سلام من یک متن تست برای تست این تست هستم.
|
|
19 |
print(tokenizer.encode(text))
|
20 |
print(tokenizer.decode(tokenizer.encode(text)))
|
21 |
```
|
22 |
-
|
23 |
```
|
24 |
[216, 179, 217, 132, 216, 167, 217, 133, 32, 217, 133, 217, 134, 32, 219, 140, 218, 169, 32, 217, 133, 216, 170, 217, 134, 32, 216, 170, 216, 179, 216, 170, 32, 216, 168, 216, 177, 216, 167, 219, 140, 32, 216, 170, 216, 179, 216, 170, 32, 216, 167, 219, 140, 217, 134, 32, 216, 170, 216, 179, 216, 170, 32, 217, 135, 216, 179, 216, 170, 217, 133, 46]
|
25 |
سلام من یک متن تست برای تست این تست هستم.
|
26 |
```
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
You can also add special tokens:
|
29 |
```python
|
|
|
19 |
print(tokenizer.encode(text))
|
20 |
print(tokenizer.decode(tokenizer.encode(text)))
|
21 |
```
|
22 |
+
this is the normal encoding of this text:
|
23 |
```
|
24 |
[216, 179, 217, 132, 216, 167, 217, 133, 32, 217, 133, 217, 134, 32, 219, 140, 218, 169, 32, 217, 133, 216, 170, 217, 134, 32, 216, 170, 216, 179, 216, 170, 32, 216, 168, 216, 177, 216, 167, 219, 140, 32, 216, 170, 216, 179, 216, 170, 32, 216, 167, 219, 140, 217, 134, 32, 216, 170, 216, 179, 216, 170, 32, 217, 135, 216, 179, 216, 170, 217, 133, 46]
|
25 |
سلام من یک متن تست برای تست این تست هستم.
|
26 |
```
|
27 |
+
and here is what Mana tokenizer generate:
|
28 |
+
```
|
29 |
+
[30318, 377, 363, 4340, 5828, 513, 5828, 378, 5828, 14471, 46]
|
30 |
+
سلام من یک متن تست برای تست این تست هستم.
|
31 |
+
```
|
32 |
|
33 |
You can also add special tokens:
|
34 |
```python
|
benchmark.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tracemalloc
|
2 |
+
import time
|
3 |
+
from datetime import datetime
|
4 |
+
from .mana_tokenizer import ManaTokenizer
|
5 |
+
|
6 |
+
tokenizer = ManaTokenizer()
|
7 |
+
|
8 |
+
# Example text for tokenization
|
9 |
+
sample_text = "شرکت آسا پرداز آریسا در سال 96 با استقرار در شهرک علمی و فناوری اصفهان فعالیت رسمی خود را در زمینه سامانه های پردازش سریع (hpc) و رایانش ابری (cloud) آغاز کرد. این شرکت اولین ارائه دهنده تخصصی کاملاً مبتنی بر شتاب دهنده های گرافیکی برای محاسبات پردازش سریع در ایران است. این شرکت توانست در سال 1400 آزمایشگاه پردازشی_گرافیکی خیام را در شهرک علمی تحقیقاتی اصفهان ایجاد و تجهیز کند.این آزمایشگاه مجهز به بیش از 8600 هسته پردازشی و بیش از 800 هزار هسته پردازش گرافیکی کودا می باشد که در اختیار محققان,معماران,مهندسان و … ,برای انجام تمامی تحقیقات و پروژهای علمیشان قرار داده میشود.این آزمایشگاه دارای فضای ذخیره سازی 1.5 پتابایت همچنین فضای رم 15 هزار گیگابایتی میباشد. این آزمایشگاه مجهز به جدید ترین سرورها و پردازنده های گرافیکی روز دنیا می باشد که از تمامی نرم افزار های پیشرفته ی طراحی,معماری,مهندسی,شبیه سازی,حل مسائل پیش بینی مالی,بازی و سرگرمی,پزشکی و درمان پشتیبانی می کند."
|
10 |
+
|
11 |
+
# Tokenize a sample text to verify tokenizer function
|
12 |
+
encoded_sample = tokenizer.encode(sample_text)
|
13 |
+
tokens2 = encoded_sample.tokens
|
14 |
+
vocab_size2 = len(tokenizer.get_vocab())
|
15 |
+
print(f"Mana Vocabulary: {vocab_size2}")
|
16 |
+
print(f"Mana Algorithm: {tokenizer.__class__.__name__}")
|
17 |
+
|
18 |
+
# Print current date and time
|
19 |
+
current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
20 |
+
print(f"Current Date and Time: {current_date}")
|
21 |
+
|
22 |
+
# Batch benchmark function using batch_encode
|
23 |
+
def benchmark_tokenizer_batch(tokenizer, texts):
|
24 |
+
start_time = time.time()
|
25 |
+
tokenizer.batch_encode(texts) # Use batch encoding here
|
26 |
+
end_time = time.time()
|
27 |
+
return end_time - start_time
|
28 |
+
|
29 |
+
# Large texts for benchmarking
|
30 |
+
large_texts = ["سال 96 با استقرار در شهرک علمی و فناوری اصفهان فعالیت رسمی خود را در زمینه سامانه های پردازش سریع (hpc) و رایانش ابری (cloud) آغاز."] * 1000
|
31 |
+
|
32 |
+
# Run the batch benchmark
|
33 |
+
time2 = benchmark_tokenizer_batch(tokenizer, large_texts)
|
34 |
+
print(f"Mana Batch Encode Time: {time2} seconds")
|
35 |
+
|
36 |
+
# Batch memory usage function
|
37 |
+
def memory_usage_tokenizer_batch(tokenizer, texts):
|
38 |
+
tracemalloc.start()
|
39 |
+
tokenizer.batch_encode(texts) # Use batch encoding here
|
40 |
+
snapshot = tracemalloc.take_snapshot()
|
41 |
+
tracemalloc.stop()
|
42 |
+
|
43 |
+
top_stats = snapshot.statistics('lineno')
|
44 |
+
return top_stats[0].size / 1024
|
45 |
+
|
46 |
+
# Measure memory usage for batch encoding
|
47 |
+
memory2 = memory_usage_tokenizer_batch(tokenizer, large_texts)
|
48 |
+
print(f"Mana Batch Encode Memory Usage: {memory2} KB")
|
49 |
+
|
50 |
+
# Calculate and print the total character count for large_texts
|
51 |
+
total_chars_large_texts = sum(len(text) for text in large_texts)
|
52 |
+
print(f"Total characters in large_texts: {total_chars_large_texts}")
|
mana_tokenizer.py
CHANGED
@@ -1,13 +1,14 @@
|
|
|
|
1 |
from .base import Tokenizer
|
2 |
from .helper import get_stats, merge_batch_get_stats
|
3 |
from heapq import nlargest
|
4 |
import time
|
5 |
|
6 |
MANA_SPECIAL_TOKENS = {
|
7 |
-
'<|end|>':
|
8 |
-
'<|user|>':
|
9 |
-
'<|assistant|>':
|
10 |
-
'<|system|>':
|
11 |
}
|
12 |
|
13 |
class ManaTokenizer(Tokenizer):
|
@@ -17,9 +18,80 @@ class ManaTokenizer(Tokenizer):
|
|
17 |
- special_tokens: str -> int dictionary of special tokens
|
18 |
example: {'<|endoftext|>': 100257}
|
19 |
"""
|
20 |
-
self.register_special_tokens(MANA_SPECIAL_TOKENS)
|
21 |
super().__init__(pattern, multiprocess, store_dict, stop_list_size, freq_cutoff)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
def train(self, data, vocab_size, cap_divisor=2, max_batch_size=0, verbose=False):
|
24 |
t0 = time.time()
|
25 |
ids = self._import_data(data) # [(bytes, int)] -> text chunks and their counts
|
|
|
1 |
+
import torch
|
2 |
from .base import Tokenizer
|
3 |
from .helper import get_stats, merge_batch_get_stats
|
4 |
from heapq import nlargest
|
5 |
import time
|
6 |
|
7 |
MANA_SPECIAL_TOKENS = {
|
8 |
+
'<|end|>': 265712,
|
9 |
+
'<|user|>': 265713,
|
10 |
+
'<|assistant|>': 265714,
|
11 |
+
'<|system|>': 265715
|
12 |
}
|
13 |
|
14 |
class ManaTokenizer(Tokenizer):
|
|
|
18 |
- special_tokens: str -> int dictionary of special tokens
|
19 |
example: {'<|endoftext|>': 100257}
|
20 |
"""
|
|
|
21 |
super().__init__(pattern, multiprocess, store_dict, stop_list_size, freq_cutoff)
|
22 |
+
self.register_special_tokens(MANA_SPECIAL_TOKENS)
|
23 |
+
self.load("mana_tokenizer/mana.model")
|
24 |
+
self.padding_side = "right"
|
25 |
+
self.pad_token_id = self.special_tokens.get('<|end|>')
|
26 |
+
|
27 |
+
@property
|
28 |
+
def tokens(self):
|
29 |
+
"""Property to retrieve token IDs for a given text."""
|
30 |
+
return self._tokens
|
31 |
+
|
32 |
+
@property
|
33 |
+
def attention_masks(self):
|
34 |
+
"""Property to retrieve attention masks for a given text."""
|
35 |
+
return self._attention_masks
|
36 |
+
|
37 |
+
def encode(self, text, allowed_special="none_raise"):
|
38 |
+
"""Override encode to include attention masks."""
|
39 |
+
encoded_ids = super().encode(text, allowed_special=allowed_special)
|
40 |
+
self._tokens = encoded_ids
|
41 |
+
self._attention_masks = torch.ones(len(encoded_ids), dtype=torch.int32)
|
42 |
+
return self
|
43 |
+
|
44 |
+
def batch_encode(self, texts, padding=True):
|
45 |
+
"""
|
46 |
+
Encode a list of texts with dynamic padding and attention masks.
|
47 |
+
Handles left padding and attention masking.
|
48 |
+
|
49 |
+
Parameters:
|
50 |
+
texts (list of str): List of texts to encode.
|
51 |
+
padding (bool): If True, pad sequences to the max length in the batch.
|
52 |
+
|
53 |
+
Returns:
|
54 |
+
dict: A dictionary containing input_ids and attention_mask tensors.
|
55 |
+
"""
|
56 |
+
# Ensure encode method returns a dict with 'input_ids' and 'attention_mask'
|
57 |
+
encoded_texts = [{"input_ids": self.encode(text).tokens, "attention_mask": [1] * len(self.encode(text).tokens)}
|
58 |
+
for text in texts]
|
59 |
+
|
60 |
+
max_len = max(len(t["input_ids"]) for t in encoded_texts) if padding else None
|
61 |
+
|
62 |
+
# Apply padding with left alignment
|
63 |
+
input_ids = []
|
64 |
+
attention_masks = []
|
65 |
+
for encoding in encoded_texts:
|
66 |
+
ids = encoding["input_ids"]
|
67 |
+
attn_mask = encoding["attention_mask"]
|
68 |
+
if padding and len(ids) < max_len:
|
69 |
+
pad_len = max_len - len(ids)
|
70 |
+
if self.padding_side == "left":
|
71 |
+
ids = [self.pad_token_id] * pad_len + ids
|
72 |
+
attn_mask = [0] * pad_len + attn_mask
|
73 |
+
else:
|
74 |
+
ids = ids + [self.pad_token_id] * pad_len
|
75 |
+
attn_mask = attn_mask + [0] * pad_len
|
76 |
+
input_ids.append(ids)
|
77 |
+
attention_masks.append(attn_mask)
|
78 |
+
|
79 |
+
# Convert to tensors
|
80 |
+
input_ids = torch.tensor(input_ids, dtype=torch.long)
|
81 |
+
attention_masks = torch.tensor(attention_masks, dtype=torch.long)
|
82 |
+
|
83 |
+
return {"input_ids": input_ids, "attention_mask": attention_masks}
|
84 |
|
85 |
+
|
86 |
+
def get_vocab(self):
|
87 |
+
"""Function to return the vocabulary dictionary."""
|
88 |
+
return self.vocab
|
89 |
+
|
90 |
+
@property
|
91 |
+
def vocab_size(self):
|
92 |
+
"""Property to return the vocabulary size."""
|
93 |
+
return len(self.vocab)
|
94 |
+
|
95 |
def train(self, data, vocab_size, cap_divisor=2, max_batch_size=0, verbose=False):
|
96 |
t0 = time.time()
|
97 |
ids = self._import_data(data) # [(bytes, int)] -> text chunks and their counts
|