ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
ember::SpmTokenizer Class Reference

#include <spm_tokenizer.h>

Collaboration diagram for ember::SpmTokenizer:
Collaboration graph

Classes

struct  Bigram
 
struct  Lower
 
struct  Symbol
 

Public Member Functions

 SpmTokenizer (std::vector< std::string > tokens, std::vector< float > scores, std::vector< int32_t > types, bool add_space_prefix)
 
std::vector< int > encode (const std::string &text) const
 
std::string decode (const std::vector< int > &ids) const
 
size_t size () const
 

Private Member Functions

int lookup (const std::string &s) const
 
void encode_fragment (const std::string &text, std::vector< int > &out) const
 

Static Private Member Functions

static std::string escape (const std::string &s)
 

Private Attributes

std::vector< std::string > tokens_
 
std::vector< float > scores_
 
std::vector< int32_t > types_
 
bool add_space_prefix_
 
std::unordered_map< std::string, int > id_
 
std::vector< int > specials_
 
int byte_id_ [256]
 

Static Private Attributes

static constexpr int32_t kUnknown = 2
 
static constexpr int32_t kControl = 3
 
static constexpr int32_t kUserDefined = 4
 
static constexpr int32_t kByte = 6
 
static constexpr const char * kSpace = "\xe2\x96\x81"
 

Detailed Description

Definition at line 30 of file spm_tokenizer.h.

Constructor & Destructor Documentation

◆ SpmTokenizer()

ember::SpmTokenizer::SpmTokenizer ( std::vector< std::string >  tokens,
std::vector< float >  scores,
std::vector< int32_t >  types,
bool  add_space_prefix 
)
inline

Definition at line 32 of file spm_tokenizer.h.

34 : tokens_(std::move(tokens)), scores_(std::move(scores)), types_(std::move(types)),
35 add_space_prefix_(add_space_prefix) {
36 if (scores_.size() != tokens_.size()) throw std::runtime_error("SentencePiece GGUF: scores and tokens differ in length");
37 if (types_.size() != tokens_.size()) throw std::runtime_error("SentencePiece GGUF: token types and tokens differ in length");
38 id_.reserve(tokens_.size());
39 for (size_t i = 0; i < tokens_.size(); ++i) id_[tokens_[i]] = static_cast<int>(i); // the last one wins
40 for (size_t i = 0; i < tokens_.size(); ++i)
41 if ((types_[i] == kControl || types_[i] == kUserDefined || types_[i] == kUnknown) && !tokens_[i].empty())
42 specials_.push_back(static_cast<int>(i));
43 // Longest text first (llama.cpp sorts by length with std::sort; among equal lengths the
44 // order only matters for overlapping specials, which the gate against HF would show).
45 std::stable_sort(specials_.begin(), specials_.end(),
46 [&](int a, int b) { return tokens_[a].size() > tokens_[b].size(); });
47 for (int b = 0; b < 256; ++b) {
48 char buf[8];
49 std::snprintf(buf, sizeof buf, "<0x%02X>", b);
50 auto it = id_.find(buf);
51 if (it == id_.end()) it = id_.find(std::string(1, static_cast<char>(b)));
52 byte_id_[b] = it == id_.end() ? -1 : it->second;
53 }
54 }
std::vector< int > specials_
std::unordered_map< std::string, int > id_
static constexpr int32_t kControl
std::vector< std::string > tokens_
std::vector< float > scores_
static constexpr int32_t kUnknown
std::vector< int32_t > types_
static constexpr int32_t kUserDefined
std::vector< E > a
size_t j

References a, byte_id_, id_, j, kControl, kUnknown, kUserDefined, scores_, specials_, tokens_, and types_.

Member Function Documentation

◆ decode()

std::string ember::SpmTokenizer::decode ( const std::vector< int > &  ids) const
inline

Definition at line 102 of file spm_tokenizer.h.

102 {
103 std::string s;
104 for (int id : ids) {
105 if (id < 0 || static_cast<size_t>(id) >= tokens_.size()) continue;
106 const std::string& t = tokens_[id];
107 if (types_[id] == kByte && t.size() == 6 && t.compare(0, 3, "<0x") == 0) {
108 s += static_cast<char>(std::stoi(t.substr(3, 2), nullptr, 16));
109 continue;
110 }
111 for (size_t i = 0; i < t.size();) {
112 if (t.compare(i, 3, kSpace) == 0) {
113 s += ' ';
114 i += 3;
115 } else {
116 s += t[i++];
117 }
118 }
119 }
120 return s;
121 }
static constexpr const char * kSpace
static constexpr int32_t kByte

References id, j, kByte, kSpace, tokens_, and types_.

◆ encode()

std::vector< int > ember::SpmTokenizer::encode ( const std::string &  text) const
inline

Definition at line 56 of file spm_tokenizer.h.

56 {
57 // Fragments: (special token id, or -1 with [offset, offset + length) of text).
58 struct Frag {
59 int id;
60 size_t off, len;
61 };
62 std::vector<Frag> frags = {{-1, 0, text.size()}};
63 for (int sid : specials_) {
64 const std::string& s = tokens_[sid];
65 std::vector<Frag> next;
66 next.reserve(frags.size());
67 for (const Frag& f : frags) {
68 if (f.id >= 0) {
69 next.push_back(f);
70 continue;
71 }
72 size_t at = f.off;
73 const size_t end = f.off + f.len;
74 while (at < end) {
75 const size_t hit = text.find(s, at);
76 if (hit == std::string::npos || hit + s.size() > end) break;
77 if (hit > at) next.push_back({-1, at, hit - at});
78 next.push_back({sid, hit, s.size()});
79 at = hit + s.size();
80 }
81 if (at < end) next.push_back({-1, at, end - at});
82 }
83 frags.swap(next);
84 }
85 std::vector<int> out;
86 bool prev_special = true;
87 for (const Frag& f : frags) {
88 if (f.id >= 0) {
89 out.push_back(f.id);
90 prev_special = true;
91 continue;
92 }
93 if (f.len == 0) continue;
94 std::string piece = add_space_prefix_ && prev_special ? std::string(" ") : std::string();
95 piece += text.substr(f.off, f.len);
97 prev_special = false;
98 }
99 return out;
100 }
void encode_fragment(const std::string &text, std::vector< int > &out) const
static std::string escape(const std::string &s)
std::string text
node out

References add_space_prefix_, encode_fragment(), escape(), id, j, off, out, specials_, text, and tokens_.

◆ encode_fragment()

void ember::SpmTokenizer::encode_fragment ( const std::string &  text,
std::vector< int > &  out 
) const
inlineprivate

Definition at line 159 of file spm_tokenizer.h.

159 {
160 static const uint8_t utf8_len[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4};
161 std::vector<Symbol> sym;
162 for (size_t off = 0; off < text.size();) {
163 const size_t len = std::min<size_t>(utf8_len[static_cast<uint8_t>(text[off]) >> 4], text.size() - off);
164 const int index = static_cast<int>(sym.size());
165 sym.push_back({index - 1, off + len == text.size() ? -1 : index + 1, off, len});
166 off += len;
167 }
168 std::priority_queue<Bigram, std::vector<Bigram>, Lower> queue;
169 std::unordered_map<std::string, std::pair<int, int>> rev_merge;
170 auto try_add = [&](int left, int right) {
171 if (left == -1 || right == -1) return;
172 const std::string s = text.substr(sym[left].off, sym[left].n + sym[right].n);
173 const int id = lookup(s);
174 if (id < 0) return;
175 queue.push({left, right, scores_[id], s.size()});
176 rev_merge[s] = {left, right};
177 };
178 for (int i = 1; i < static_cast<int>(sym.size()); ++i) try_add(i - 1, i);
179 while (!queue.empty()) {
180 const Bigram b = queue.top();
181 queue.pop();
182 Symbol& l = sym[b.left];
183 Symbol& r = sym[b.right];
184 if (l.n == 0 || r.n == 0 || l.n + r.n != b.size) continue;
185 l.n += r.n;
186 r.n = 0;
187 l.next = r.next;
188 if (r.next >= 0) sym[r.next].prev = b.left;
189 try_add(l.prev, b.left);
190 try_add(b.left, l.next);
191 }
192 std::function<void(const Symbol&)> resegment = [&](const Symbol& s) {
193 const std::string t = text.substr(s.off, s.n);
194 const int id = lookup(t);
195 if (id >= 0) {
196 out.push_back(id);
197 return;
198 }
199 const auto p = rev_merge.find(t);
200 if (p == rev_merge.end()) {
201 for (size_t j = 0; j < s.n; ++j) {
202 const int bid = byte_id_[static_cast<uint8_t>(text[s.off + j])];
203 if (bid < 0) throw std::runtime_error("SentencePiece GGUF has no byte token for a byte of the text");
204 out.push_back(bid);
205 }
206 return;
207 }
208 resegment(sym[p->second.first]);
209 resegment(sym[p->second.second]);
210 };
211 for (int i = sym.empty() ? -1 : 0; i != -1; i = sym[i].next) resegment(sym[i]);
212 }
int lookup(const std::string &s) const
const float * p[kIrDepthSourcesMax]
int n

References byte_id_, id, index, j, lookup(), n, ember::SpmTokenizer::Symbol::n, off, out, p, scores_, and text.

Referenced by encode().

◆ escape()

static std::string ember::SpmTokenizer::escape ( const std::string &  s)
inlinestaticprivate

Definition at line 129 of file spm_tokenizer.h.

129 {
130 std::string o;
131 o.reserve(s.size() + s.size() / 2);
132 for (char c : s) {
133 if (c == ' ') o += kSpace;
134 else o += c;
135 }
136 return o;
137 }
float c

References c, j, and kSpace.

Referenced by encode().

◆ lookup()

int ember::SpmTokenizer::lookup ( const std::string &  s) const
inlineprivate

Definition at line 154 of file spm_tokenizer.h.

154 {
155 auto it = id_.find(s);
156 return it == id_.end() ? -1 : it->second;
157 }

References id_, and j.

Referenced by encode_fragment().

◆ size()

size_t ember::SpmTokenizer::size ( ) const
inline

Definition at line 123 of file spm_tokenizer.h.

123{ return tokens_.size(); }

References tokens_.

Member Data Documentation

◆ add_space_prefix_

bool ember::SpmTokenizer::add_space_prefix_
private

Definition at line 217 of file spm_tokenizer.h.

Referenced by encode().

◆ byte_id_

int ember::SpmTokenizer::byte_id_[256]
private

Definition at line 220 of file spm_tokenizer.h.

Referenced by encode_fragment(), and SpmTokenizer().

◆ id_

std::unordered_map<std::string, int> ember::SpmTokenizer::id_
private

Definition at line 218 of file spm_tokenizer.h.

Referenced by lookup(), and SpmTokenizer().

◆ kByte

constexpr int32_t ember::SpmTokenizer::kByte = 6
staticprivate

Definition at line 126 of file spm_tokenizer.h.

Referenced by decode().

◆ kControl

constexpr int32_t ember::SpmTokenizer::kControl = 3
staticprivate

Definition at line 126 of file spm_tokenizer.h.

Referenced by SpmTokenizer().

◆ kSpace

constexpr const char* ember::SpmTokenizer::kSpace = "\xe2\x96\x81"
staticconstexprprivate

Definition at line 127 of file spm_tokenizer.h.

Referenced by decode(), and escape().

◆ kUnknown

constexpr int32_t ember::SpmTokenizer::kUnknown = 2
staticconstexprprivate

Definition at line 126 of file spm_tokenizer.h.

Referenced by SpmTokenizer().

◆ kUserDefined

constexpr int32_t ember::SpmTokenizer::kUserDefined = 4
staticprivate

Definition at line 126 of file spm_tokenizer.h.

Referenced by SpmTokenizer().

◆ scores_

std::vector<float> ember::SpmTokenizer::scores_
private

Definition at line 215 of file spm_tokenizer.h.

Referenced by encode_fragment(), and SpmTokenizer().

◆ specials_

std::vector<int> ember::SpmTokenizer::specials_
private

Definition at line 219 of file spm_tokenizer.h.

Referenced by encode(), and SpmTokenizer().

◆ tokens_

std::vector<std::string> ember::SpmTokenizer::tokens_
private

Definition at line 214 of file spm_tokenizer.h.

Referenced by decode(), encode(), size(), and SpmTokenizer().

◆ types_

std::vector<int32_t> ember::SpmTokenizer::types_
private

Definition at line 216 of file spm_tokenizer.h.

Referenced by decode(), and SpmTokenizer().


The documentation for this class was generated from the following file: