Skip to content

Commit e09ef49

Browse files
klosaxakawrykow
authored andcommitted
Fix spm whitespaces (ggml-org#2806)
* llama.cpp : fix spm whitespace escaping + clean up * main.cpp : spm - add whitespace in front of prompt * test-tokenizer-0.cpp : spm - add whitespace in front of prompt
1 parent 11d5a77 commit e09ef49

File tree

3 files changed

+27
-41
lines changed

3 files changed

+27
-41
lines changed

examples/main/main.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,19 @@ int main(int argc, char ** argv) {
189189
}
190190
}
191191

192-
const bool is_spm = llama_vocab_type(ctx) == LLAMA_VOCAB_TYPE_SPM;
192+
// Add BOS if SPM tokenizer
193+
const bool add_bos = llama_vocab_type(ctx) == LLAMA_VOCAB_TYPE_SPM;
193194

194195
// tokenize the prompt
195196
std::vector<llama_token> embd_inp;
197+
198+
if (llama_vocab_type(ctx) == LLAMA_VOCAB_TYPE_SPM) {
199+
// Add a space in front of the first character to match OG llama tokenizer behavior
200+
params.prompt.insert(0, 1, ' ');
201+
}
202+
196203
if (params.interactive_first || params.instruct || !params.prompt.empty() || session_tokens.empty()) {
197-
embd_inp = ::llama_tokenize(ctx, params.prompt, is_spm);
204+
embd_inp = ::llama_tokenize(ctx, params.prompt, add_bos);
198205
} else {
199206
embd_inp = session_tokens;
200207
}
@@ -210,9 +217,9 @@ int main(int argc, char ** argv) {
210217
int original_prompt_len = 0;
211218
if (ctx_guidance) {
212219
params.cfg_negative_prompt.insert(0, 1, ' ');
213-
guidance_inp = ::llama_tokenize(ctx_guidance, params.cfg_negative_prompt, is_spm);
220+
guidance_inp = ::llama_tokenize(ctx_guidance, params.cfg_negative_prompt, add_bos);
214221

215-
std::vector<llama_token> original_inp = ::llama_tokenize(ctx, params.prompt, is_spm);
222+
std::vector<llama_token> original_inp = ::llama_tokenize(ctx, params.prompt, add_bos);
216223
original_prompt_len = original_inp.size();
217224
guidance_offset = (int)guidance_inp.size() - original_prompt_len;
218225
}
@@ -259,7 +266,7 @@ int main(int argc, char ** argv) {
259266
}
260267

261268
// prefix & suffix for instruct mode
262-
const auto inp_pfx = ::llama_tokenize(ctx, "\n\n### Instruction:\n\n", is_spm);
269+
const auto inp_pfx = ::llama_tokenize(ctx, "\n\n### Instruction:\n\n", add_bos);
263270
const auto inp_sfx = ::llama_tokenize(ctx, "\n\n### Response:\n\n", false);
264271

265272
// in instruct mode, we inject a prefix and a suffix to each input by the user

llama.cpp

+13-35
Original file line numberDiff line numberDiff line change
@@ -1635,7 +1635,7 @@ static void llm_load_hparams(
16351635
}
16361636

16371637
// TODO: This should probably be in llama.h
1638-
static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, const std::string & raw_text, bool bos, bool escape);
1638+
static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, const std::string & raw_text, bool bos);
16391639

16401640
static void llm_load_vocab(
16411641
llama_model_loader & ml,
@@ -1737,7 +1737,7 @@ static void llm_load_vocab(
17371737
}
17381738

17391739
// determine the newline token: LLaMA "<0x0A>" == 10 == '\n', Falcon 193 == '\n'
1740-
vocab.linefeed_id = llama_tokenize_internal(vocab, "\n", false, false)[0];
1740+
vocab.linefeed_id = llama_tokenize_internal(vocab, "\n", false)[0];
17411741

17421742
// special tokens
17431743
GGUF_GET_KEY(ctx, vocab.special_bos_id, gguf_get_val_u32, GGUF_TYPE_UINT32, false, kv(LLM_KV_TOKENIZER_BOS_ID));
@@ -3027,14 +3027,8 @@ static llama_token llama_byte_to_token(const llama_vocab & vocab, uint8_t ch) {
30273027
}
30283028

30293029
static std::string llama_escape_whitespace(const std::string& text) {
3030-
std::string result = "\xe2\x96\x81";
3031-
for (size_t offs = 0; offs < text.length(); ++offs) {
3032-
if (text[offs] == ' ') {
3033-
result += "\xe2\x96\x81";
3034-
} else {
3035-
result += text[offs];
3036-
}
3037-
}
3030+
std::string result = text;
3031+
replace_all(result, " ", "\xe2\x96\x81");
30383032
return result;
30393033
}
30403034

@@ -3219,7 +3213,7 @@ struct llm_bigram_bpe {
32193213
};
32203214

32213215
struct llm_tokenizer_bpe {
3222-
llm_tokenizer_bpe(const llama_vocab & vocab, bool g2ws): vocab(vocab) { flag_g2ws = g2ws; }
3216+
llm_tokenizer_bpe(const llama_vocab & vocab): vocab(vocab) {}
32233217

32243218
void tokenize(const std::string & text, std::vector<llama_vocab::id> & output) {
32253219
int final_prev_index = -1;
@@ -3371,8 +3365,6 @@ struct llm_tokenizer_bpe {
33713365
return words;
33723366
}
33733367

3374-
bool flag_g2ws = false;
3375-
33763368
const llama_vocab & vocab;
33773369

33783370
std::vector<llm_symbol> symbols;
@@ -3381,39 +3373,26 @@ struct llm_tokenizer_bpe {
33813373
llm_bigram_bpe::queue work_queue;
33823374
};
33833375

3384-
static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, const std::string & raw_text, bool bos, bool escape) {
3376+
static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, const std::string & raw_text, bool bos) {
33853377
std::vector<llama_vocab::id> output;
33863378

33873379
if (raw_text.empty()) {
33883380
return output;
33893381
}
33903382

3383+
if (bos && vocab.special_bos_id != -1) {
3384+
output.push_back(vocab.special_bos_id);
3385+
}
3386+
33913387
switch (vocab.type) {
33923388
case LLAMA_VOCAB_TYPE_SPM:
33933389
{
33943390
llm_tokenizer_spm tokenizer(vocab);
3395-
3396-
if (bos) {
3397-
output.push_back(vocab.special_bos_id);
3398-
}
3399-
3400-
std::string text;
3401-
if (escape) {
3402-
text = llama_escape_whitespace(raw_text);
3403-
} else {
3404-
text = raw_text;
3405-
}
3406-
3407-
tokenizer.tokenize(text, output);
3391+
tokenizer.tokenize(llama_escape_whitespace(raw_text), output);
34083392
} break;
34093393
case LLAMA_VOCAB_TYPE_BPE:
34103394
{
3411-
llm_tokenizer_bpe tokenizer(vocab, escape);
3412-
3413-
if (bos && vocab.special_bos_id != -1) {
3414-
output.push_back(vocab.special_bos_id);
3415-
}
3416-
3395+
llm_tokenizer_bpe tokenizer(vocab);
34173396
tokenizer.tokenize(raw_text, output);
34183397
} break;
34193398
};
@@ -6095,8 +6074,7 @@ int llama_tokenize_with_model(
60956074
llama_token * tokens,
60966075
int n_max_tokens,
60976076
bool add_bos) {
6098-
auto escape = llama_vocab_get_type(model->vocab) == LLAMA_VOCAB_TYPE_SPM;
6099-
auto res = llama_tokenize_internal(model->vocab, text, add_bos, escape);
6077+
auto res = llama_tokenize_internal(model->vocab, text, add_bos);
61006078

61016079
if (n_max_tokens < (int) res.size()) {
61026080
LLAMA_LOG_ERROR("%s: too many tokens\n", __func__);

tests/test-tokenizer-0.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ int main(int argc, char **argv) {
100100
bool success = true;
101101

102102
for (const auto & test_kv : k_tests()) {
103-
std::vector<llama_token> res = llama_tokenize(ctx, test_kv.first, true);
103+
// Add a space in front of the first character to match OG llama tokenizer behavior
104+
std::vector<llama_token> res = llama_tokenize(ctx, " " + test_kv.first, true);
104105
fprintf(stderr, "%s : '%s' tokenized to '%s'\n",
105106
__func__, test_kv.first.c_str(), unescape_whitespace(ctx, res).c_str());
106107

0 commit comments

Comments
 (0)