mirror of
				https://github.com/ggml-org/llama.cpp.git
				synced 2025-10-31 08:51:55 +00:00 
			
		
		
		
	BERT tokenizer fixes (#6498)
Key changes: * BERT conversion: fix abuse of LlamaHfVocab, do not set BOS or EOS * Nomic Embed conversion: pad vocab instead of slicing embedding tensor * llama_tokenize: handle added special tokens like HF does
This commit is contained in:
		
							
								
								
									
										167
									
								
								llama.cpp
									
									
									
									
									
								
							
							
						
						
									
										167
									
								
								llama.cpp
									
									
									
									
									
								
							| @@ -318,6 +318,8 @@ enum llm_kv { | ||||
|     LLM_KV_TOKENIZER_UNK_ID, | ||||
|     LLM_KV_TOKENIZER_SEP_ID, | ||||
|     LLM_KV_TOKENIZER_PAD_ID, | ||||
|     LLM_KV_TOKENIZER_CLS_ID, | ||||
|     LLM_KV_TOKENIZER_MASK_ID, | ||||
|     LLM_KV_TOKENIZER_ADD_BOS, | ||||
|     LLM_KV_TOKENIZER_ADD_EOS, | ||||
|     LLM_KV_TOKENIZER_ADD_PREFIX, | ||||
| @@ -388,6 +390,8 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = { | ||||
|     { LLM_KV_TOKENIZER_UNK_ID,              "tokenizer.ggml.unknown_token_id"   }, | ||||
|     { LLM_KV_TOKENIZER_SEP_ID,              "tokenizer.ggml.seperator_token_id" }, | ||||
|     { LLM_KV_TOKENIZER_PAD_ID,              "tokenizer.ggml.padding_token_id"   }, | ||||
|     { LLM_KV_TOKENIZER_CLS_ID,              "tokenizer.ggml.cls_token_id"       }, | ||||
|     { LLM_KV_TOKENIZER_MASK_ID,             "tokenizer.ggml.mask_token_id"      }, | ||||
|     { LLM_KV_TOKENIZER_ADD_BOS,             "tokenizer.ggml.add_bos_token"      }, | ||||
|     { LLM_KV_TOKENIZER_ADD_EOS,             "tokenizer.ggml.add_eos_token"      }, | ||||
|     { LLM_KV_TOKENIZER_ADD_PREFIX,          "tokenizer.ggml.add_space_prefix"   }, | ||||
| @@ -2018,11 +2022,13 @@ struct llama_vocab { | ||||
|     std::map<std::pair<std::string, std::string>, int> bpe_ranks; | ||||
|  | ||||
|     // default LLaMA special tokens | ||||
|     id special_bos_id = 1; | ||||
|     id special_eos_id = 2; | ||||
|     id special_unk_id = 0; | ||||
|     id special_sep_id = -1; | ||||
|     id special_pad_id = -1; | ||||
|     id special_bos_id  = 1; | ||||
|     id special_eos_id  = 2; | ||||
|     id special_unk_id  = 0; | ||||
|     id special_sep_id  = -1; | ||||
|     id special_pad_id  = -1; | ||||
|     id special_cls_id  = -1; | ||||
|     id special_mask_id = -1; | ||||
|  | ||||
|     int special_add_bos = -1; // -1 unknown, 1 add, 0 don't add. | ||||
|     int special_add_eos = -1; // -1 unknown, 1 add, 0 don't add. | ||||
| @@ -3978,7 +3984,9 @@ static void llm_load_hparams( | ||||
| } | ||||
|  | ||||
| // TODO: This should probably be in llama.h | ||||
| static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, std::string raw_text, bool bos, bool special = false); | ||||
| static std::vector<llama_vocab::id> llama_tokenize_internal( | ||||
|     const llama_vocab & vocab, std::string raw_text, bool add_special, bool parse_special = false | ||||
| ); | ||||
| static llama_token llama_byte_to_token(const llama_vocab & vocab, uint8_t ch); | ||||
|  | ||||
| static void llm_load_vocab( | ||||
| @@ -4000,23 +4008,27 @@ static void llm_load_vocab( | ||||
|             vocab.type = LLAMA_VOCAB_TYPE_NONE; | ||||
|  | ||||
|             // default special tokens | ||||
|             vocab.special_bos_id = -1; | ||||
|             vocab.special_eos_id = -1; | ||||
|             vocab.special_unk_id = -1; | ||||
|             vocab.special_sep_id = -1; | ||||
|             vocab.special_pad_id = -1; | ||||
|             vocab.linefeed_id    = -1; | ||||
|             vocab.special_bos_id  = -1; | ||||
|             vocab.special_eos_id  = -1; | ||||
|             vocab.special_unk_id  = -1; | ||||
|             vocab.special_sep_id  = -1; | ||||
|             vocab.special_pad_id  = -1; | ||||
|             vocab.special_cls_id  = -1; | ||||
|             vocab.special_mask_id = -1; | ||||
|             vocab.linefeed_id     = -1; | ||||
|  | ||||
|             return; | ||||
|         } else if (tokenizer_name == "llama") { | ||||
|             vocab.type = LLAMA_VOCAB_TYPE_SPM; | ||||
|  | ||||
|             // default special tokens | ||||
|             vocab.special_bos_id = 1; | ||||
|             vocab.special_eos_id = 2; | ||||
|             vocab.special_unk_id = 0; | ||||
|             vocab.special_sep_id = -1; | ||||
|             vocab.special_pad_id = -1; | ||||
|             vocab.special_bos_id  = 1; | ||||
|             vocab.special_eos_id  = 2; | ||||
|             vocab.special_unk_id  = 0; | ||||
|             vocab.special_sep_id  = -1; | ||||
|             vocab.special_pad_id  = -1; | ||||
|             vocab.special_cls_id  = -1; | ||||
|             vocab.special_mask_id = -1; | ||||
|  | ||||
|             const int add_space_prefix_keyidx = gguf_find_key(ctx, kv(LLM_KV_TOKENIZER_ADD_PREFIX).c_str()); | ||||
|             if (add_space_prefix_keyidx != -1) { | ||||
| @@ -4051,20 +4063,24 @@ static void llm_load_vocab( | ||||
|             } | ||||
|  | ||||
|             // default special tokens | ||||
|             vocab.special_bos_id = 11; | ||||
|             vocab.special_eos_id = 11; | ||||
|             vocab.special_unk_id = -1; | ||||
|             vocab.special_sep_id = -1; | ||||
|             vocab.special_pad_id = -1; | ||||
|             vocab.special_bos_id  = 11; | ||||
|             vocab.special_eos_id  = 11; | ||||
|             vocab.special_unk_id  = -1; | ||||
|             vocab.special_sep_id  = -1; | ||||
|             vocab.special_pad_id  = -1; | ||||
|             vocab.special_cls_id  = -1; | ||||
|             vocab.special_mask_id = -1; | ||||
|         } else if (tokenizer_name == "bert") { | ||||
|             vocab.type = LLAMA_VOCAB_TYPE_WPM; | ||||
|  | ||||
|             // default special tokens | ||||
|             vocab.special_bos_id = 101; | ||||
|             vocab.special_eos_id = 102; | ||||
|             vocab.special_unk_id = 100; | ||||
|             vocab.special_sep_id = -1; | ||||
|             vocab.special_pad_id = -1; | ||||
|             vocab.special_bos_id  = -1; | ||||
|             vocab.special_eos_id  = -1; | ||||
|             vocab.special_unk_id  = 100; | ||||
|             vocab.special_sep_id  = 102; | ||||
|             vocab.special_pad_id  = 0; | ||||
|             vocab.special_cls_id  = 101; | ||||
|             vocab.special_mask_id = 103; | ||||
|             vocab.add_space_prefix = false; | ||||
|         } else { | ||||
|             LLAMA_LOG_WARN("%s: unknown tokenizer: '%s'", __func__, tokenizer_name.c_str()); | ||||
| @@ -4127,11 +4143,13 @@ static void llm_load_vocab( | ||||
|     // special tokens | ||||
|     { | ||||
|         const std::vector<std::pair<enum llm_kv, int32_t &>> special_token_types = { | ||||
|             { LLM_KV_TOKENIZER_BOS_ID, vocab.special_bos_id }, | ||||
|             { LLM_KV_TOKENIZER_EOS_ID, vocab.special_eos_id }, | ||||
|             { LLM_KV_TOKENIZER_UNK_ID, vocab.special_unk_id }, | ||||
|             { LLM_KV_TOKENIZER_SEP_ID, vocab.special_sep_id }, | ||||
|             { LLM_KV_TOKENIZER_PAD_ID, vocab.special_pad_id }, | ||||
|             { LLM_KV_TOKENIZER_BOS_ID,  vocab.special_bos_id  }, | ||||
|             { LLM_KV_TOKENIZER_EOS_ID,  vocab.special_eos_id  }, | ||||
|             { LLM_KV_TOKENIZER_UNK_ID,  vocab.special_unk_id  }, | ||||
|             { LLM_KV_TOKENIZER_SEP_ID,  vocab.special_sep_id  }, | ||||
|             { LLM_KV_TOKENIZER_PAD_ID,  vocab.special_pad_id  }, | ||||
|             { LLM_KV_TOKENIZER_CLS_ID,  vocab.special_cls_id  }, | ||||
|             { LLM_KV_TOKENIZER_MASK_ID, vocab.special_mask_id }, | ||||
|         }; | ||||
|         for (const auto & it : special_token_types) { | ||||
|             const std::string & key = kv(std::get<0>(it)); | ||||
| @@ -4323,12 +4341,14 @@ static void llm_load_print_meta(llama_model_loader & ml, llama_model & model) { | ||||
|     LLAMA_LOG_INFO("%s: general.name     = %s\n",    __func__, model.name.c_str()); | ||||
|  | ||||
|     // special tokens | ||||
|     if (vocab.special_bos_id != -1) { LLAMA_LOG_INFO( "%s: BOS token        = %d '%s'\n", __func__, vocab.special_bos_id, vocab.id_to_token[vocab.special_bos_id].text.c_str() ); } | ||||
|     if (vocab.special_eos_id != -1) { LLAMA_LOG_INFO( "%s: EOS token        = %d '%s'\n", __func__, vocab.special_eos_id, vocab.id_to_token[vocab.special_eos_id].text.c_str() ); } | ||||
|     if (vocab.special_unk_id != -1) { LLAMA_LOG_INFO( "%s: UNK token        = %d '%s'\n", __func__, vocab.special_unk_id, vocab.id_to_token[vocab.special_unk_id].text.c_str() ); } | ||||
|     if (vocab.special_sep_id != -1) { LLAMA_LOG_INFO( "%s: SEP token        = %d '%s'\n", __func__, vocab.special_sep_id, vocab.id_to_token[vocab.special_sep_id].text.c_str() ); } | ||||
|     if (vocab.special_pad_id != -1) { LLAMA_LOG_INFO( "%s: PAD token        = %d '%s'\n", __func__, vocab.special_pad_id, vocab.id_to_token[vocab.special_pad_id].text.c_str() ); } | ||||
|     if (vocab.linefeed_id    != -1) { LLAMA_LOG_INFO( "%s: LF token         = %d '%s'\n", __func__, vocab.linefeed_id,    vocab.id_to_token[vocab.linefeed_id].text.c_str() );    } | ||||
|     if (vocab.special_bos_id  != -1) { LLAMA_LOG_INFO( "%s: BOS token        = %d '%s'\n", __func__, vocab.special_bos_id,  vocab.id_to_token[vocab.special_bos_id].text.c_str() );  } | ||||
|     if (vocab.special_eos_id  != -1) { LLAMA_LOG_INFO( "%s: EOS token        = %d '%s'\n", __func__, vocab.special_eos_id,  vocab.id_to_token[vocab.special_eos_id].text.c_str() );  } | ||||
|     if (vocab.special_unk_id  != -1) { LLAMA_LOG_INFO( "%s: UNK token        = %d '%s'\n", __func__, vocab.special_unk_id,  vocab.id_to_token[vocab.special_unk_id].text.c_str() );  } | ||||
|     if (vocab.special_sep_id  != -1) { LLAMA_LOG_INFO( "%s: SEP token        = %d '%s'\n", __func__, vocab.special_sep_id,  vocab.id_to_token[vocab.special_sep_id].text.c_str() );  } | ||||
|     if (vocab.special_pad_id  != -1) { LLAMA_LOG_INFO( "%s: PAD token        = %d '%s'\n", __func__, vocab.special_pad_id,  vocab.id_to_token[vocab.special_pad_id].text.c_str() );  } | ||||
|     if (vocab.special_cls_id  != -1) { LLAMA_LOG_INFO( "%s: CLS token        = %d '%s'\n", __func__, vocab.special_cls_id,  vocab.id_to_token[vocab.special_cls_id].text.c_str() );  } | ||||
|     if (vocab.special_mask_id != -1) { LLAMA_LOG_INFO( "%s: MASK token       = %d '%s'\n", __func__, vocab.special_mask_id, vocab.id_to_token[vocab.special_mask_id].text.c_str() ); } | ||||
|     if (vocab.linefeed_id     != -1) { LLAMA_LOG_INFO( "%s: LF token         = %d '%s'\n", __func__, vocab.linefeed_id,     vocab.id_to_token[vocab.linefeed_id].text.c_str() );     } | ||||
| } | ||||
|  | ||||
| // Returns false if cancelled by progress_callback | ||||
| @@ -11358,9 +11378,6 @@ struct llm_tokenizer_wpm { | ||||
|                 output.push_back(vocab.special_unk_id); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // append eos token | ||||
|         output.push_back(vocab.special_eos_id); | ||||
|     } | ||||
|  | ||||
|     std::vector<std::string> preprocess(const std::string & text) { | ||||
| @@ -11565,30 +11582,28 @@ static void tokenizer_st_partition(const llama_vocab & vocab, std::forward_list< | ||||
|     } | ||||
| } | ||||
|  | ||||
| static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, std::string raw_text, bool bos, bool special) { | ||||
| static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & vocab, std::string raw_text, bool add_special, bool parse_special) { | ||||
|     std::vector<llama_vocab::id> output; | ||||
|  | ||||
|     // OG tokenizer behavior: | ||||
|     // | ||||
|     // tokenizer.encode('', add_bos=True)  returns [1] | ||||
|     // tokenizer.encode('', add_bos=False) returns [] | ||||
|  | ||||
|     if (bos && vocab.special_bos_id != -1) { | ||||
|         output.push_back(vocab.special_bos_id); | ||||
|     } | ||||
|  | ||||
|     if (raw_text.empty()) { | ||||
|         return output; | ||||
|     } | ||||
|  | ||||
|     std::forward_list<fragment_buffer_variant> fragment_buffer; | ||||
|     fragment_buffer.emplace_front(raw_text, 0, raw_text.length()); | ||||
|  | ||||
|     if (special) tokenizer_st_partition(vocab, fragment_buffer); | ||||
|     if (!raw_text.empty()) { | ||||
|         fragment_buffer.emplace_front(raw_text, 0, raw_text.length()); | ||||
|         if (parse_special) tokenizer_st_partition(vocab, fragment_buffer); | ||||
|     } | ||||
|  | ||||
|     switch (vocab.type) { | ||||
|         case LLAMA_VOCAB_TYPE_SPM: | ||||
|             { | ||||
|                 // OG tokenizer behavior: | ||||
|                 // | ||||
|                 // tokenizer.encode('', add_special_tokens=True)  returns [1] | ||||
|                 // tokenizer.encode('', add_special_tokens=False) returns [] | ||||
|  | ||||
|                 if (add_special && vocab.special_add_bos != 0) { | ||||
|                     GGML_ASSERT(vocab.special_bos_id != -1); | ||||
|                     output.push_back(vocab.special_bos_id); | ||||
|                 } | ||||
|  | ||||
|                 for (const auto & fragment : fragment_buffer) { | ||||
|                     if (fragment.type == FRAGMENT_BUFFER_VARIANT_TYPE_RAW_TEXT) { | ||||
|                         // without adding this leading whitespace, we do not get the same results as the original tokenizer | ||||
| @@ -11614,9 +11629,19 @@ static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & | ||||
|                         output.push_back(fragment.token); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (add_special && vocab.special_add_eos == 1) { | ||||
|                     GGML_ASSERT(vocab.special_eos_id != -1); | ||||
|                     output.push_back(vocab.special_eos_id); | ||||
|                 } | ||||
|             } break; | ||||
|         case LLAMA_VOCAB_TYPE_BPE: | ||||
|             { | ||||
|                 if (add_special && vocab.special_add_bos == 1) { | ||||
|                     GGML_ASSERT(vocab.special_bos_id != -1); | ||||
|                     output.push_back(vocab.special_bos_id); | ||||
|                 } | ||||
|  | ||||
|                 for (const auto & fragment : fragment_buffer) { | ||||
|                     if (fragment.type == FRAGMENT_BUFFER_VARIANT_TYPE_RAW_TEXT) { | ||||
|                         auto raw_text = fragment.raw_text.substr(fragment.offset, fragment.length); | ||||
| @@ -11630,9 +11655,16 @@ static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & | ||||
|                         output.push_back(fragment.token); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 GGML_ASSERT(vocab.special_add_eos != 1); | ||||
|             } break; | ||||
|         case LLAMA_VOCAB_TYPE_WPM: | ||||
|             { | ||||
|                 if (add_special) { | ||||
|                     GGML_ASSERT(vocab.special_cls_id != -1); | ||||
|                     output.push_back(vocab.special_cls_id); | ||||
|                 } | ||||
|  | ||||
|                 for (const auto & fragment : fragment_buffer) { | ||||
|                     if (fragment.type == FRAGMENT_BUFFER_VARIANT_TYPE_RAW_TEXT) { | ||||
|                         auto raw_text = fragment.raw_text.substr(fragment.offset, fragment.length); | ||||
| @@ -11646,6 +11678,11 @@ static std::vector<llama_vocab::id> llama_tokenize_internal(const llama_vocab & | ||||
|                         output.push_back(fragment.token); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (add_special) { | ||||
|                     GGML_ASSERT(vocab.special_sep_id != -1); | ||||
|                     output.push_back(vocab.special_sep_id); | ||||
|                 } | ||||
|             } break; | ||||
|         case LLAMA_VOCAB_TYPE_NONE: | ||||
|             GGML_ASSERT(false); | ||||
| @@ -16104,6 +16141,14 @@ llama_token llama_token_eos(const struct llama_model * model) { | ||||
|     return model->vocab.special_eos_id; | ||||
| } | ||||
|  | ||||
| llama_token llama_token_cls(const struct llama_model * model) { | ||||
|     return model->vocab.special_cls_id; | ||||
| } | ||||
|  | ||||
| llama_token llama_token_sep(const struct llama_model * model) { | ||||
|     return model->vocab.special_sep_id; | ||||
| } | ||||
|  | ||||
| llama_token llama_token_nl(const struct llama_model * model) { | ||||
|     return model->vocab.linefeed_id; | ||||
| } | ||||
| @@ -16138,9 +16183,9 @@ int32_t llama_tokenize( | ||||
|                      int32_t   text_len, | ||||
|                  llama_token * tokens, | ||||
|                      int32_t   n_tokens_max, | ||||
|                         bool   add_bos, | ||||
|                         bool   special) { | ||||
|     auto res = llama_tokenize_internal(model->vocab, std::string(text, text_len), add_bos, special); | ||||
|                         bool   add_special, | ||||
|                         bool   parse_special) { | ||||
|     auto res = llama_tokenize_internal(model->vocab, std::string(text, text_len), add_special, parse_special); | ||||
|  | ||||
|     if (n_tokens_max < (int) res.size()) { | ||||
|         // LLAMA_LOG_ERROR("%s: too many tokens\n", __func__); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jared Van Bortel
					Jared Van Bortel