| 1 | #include "tokenizer.h" |
| 2 | |
| 3 | Tokenizer::Tokenizer(const YALMData& data) { |
| 4 | this->bos_id = std::stoi(data.metadata.at("bos_token_id").get<std::string>()); |
| 5 | this->eos_id = std::stoi(data.metadata.at("eos_token_id").get<std::string>()); |
| 6 | // TODO: figure out edge cases: |
| 7 | // Q: should `vocab` include byte fallback tokens? |
| 8 | // Q: should `vocab` include special tokens, e.g. '<unk>', '<s>', '</s>'? |
| 9 | // TODO: avoid copy by using std::string_view |
| 10 | const Tensor& tokens_tensor = data.tensors.at("tokenizer.tokens"); |
| 11 | char* tokens_tensor_end = (char*)tokens_tensor.data + tokens_tensor.size; |
| 12 | for (char* ptr = (char*)tokens_tensor.data; ptr < tokens_tensor_end; ptr++) { |
| 13 | char* s = ptr; |
| 14 | while (*ptr != '\0' && ptr < tokens_tensor_end) { |
| 15 | ptr++; |
| 16 | } |
| 17 | vocab.emplace_back(s, ptr - s); |
| 18 | } |
| 19 | for (size_t i = 0; i < vocab.size(); i++) { |
| 20 | if (vocab[i] == "<0x00>") { |
| 21 | byte_fallback_start = i; |
| 22 | } else if (vocab[i] == "<|eot_id|>" || vocab[i] == "<|end|>" || vocab[i] == "<|im_end|>") { |
| 23 | eot_id = i; |
| 24 | } |
| 25 | } |
| 26 | // init byte_pieces |
| 27 | for (size_t i = 0; i < 256; i++) { |
| 28 | byte_pieces[i] = (char)i; |
| 29 | } |
| 30 | // init vocab trie |
| 31 | for (size_t i = 0; i < vocab.size(); i++) { |
| 32 | const std::string& word = vocab[i]; |
| 33 | TokenTrie* p = &vocab_trie; |
| 34 | for (char c : word) { |
| 35 | if (p->children.count(c) == 0) { |
| 36 | p->children[c] = std::make_shared<TokenTrie>(); |
| 37 | } |
| 38 | p = p->children[c].get(); |
| 39 | } |
| 40 | p->token_id = i; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | std::string Tokenizer::decode_one(int prev_token, int token) const { |
| 45 | const std::string& piece = vocab[token]; |
nothing calls this directly
no outgoing calls
no test coverage detected