希腊字符BPE分词器训练异常及Llama 3.1分词器扩展问题咨询
问题描述
我尝试训练一款支持希腊语文本的新分词器,计划用以下代码将新token添加至Llama 3.1分词器:
tokenizer.add_tokens(list(new_tokens))
但基于希腊语和西班牙语文本训练字节对编码(BPE)分词器后,得到的token列表是这样的:
['Translate', 'Ġfrom', 'ĠGreek', 'Ġto', 'ĠSpanish', ':', 'ĠÎĿα', 'ĠÎŃÏĥι', 'Ġογί', 'ĠγÎŃÏģοÏħ']
把这些编码后的token传入扩展词汇表时,它们无法被识别为希腊字符,也没法用来编码语句。但硬编码新token却能正常工作:
extender_tokenizer.add_tokens(['Αυτό', 'είναι'])
我推测这是编码问题或BPE内部机制导致的,想知道:
- 希腊字符为何会以该形式显示?
- 这与编码、BPE或二者均有关联吗?
- 如何获取可添加至分词器的希腊字符token列表?
训练分词器的参考代码:
from tokenizers import Tokenizer, models, trainers, pre_tokenizers tokenizer = Tokenizer(models.BPE()) tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel() trainer = trainers.BpeTrainer(vocab_size = 2000, min_frequency = 3, show_progress = True) tokenizer.train_from_iterator(training_corpus, trainer = trainer)
原因分析
- 编码解码不匹配:你使用了
*ByteLevel*预分词器,它会将文本按UTF-8字节拆分,再把每个字节映射为对应的Unicode字符(例如用Ġ表示空格的字节)。你看到的乱码是UTF-8字节被错误用Latin-1(ISO-8859-1)解码导致的——希腊字符的UTF-8字节序列被当成Latin-1解码,就出现了ÎĿα这类乱码字符。 - BPE的字节级处理逻辑:
*ByteLevel*预分词器会让BPE在字节层面进行训练,而非直接处理Unicode字符。训练生成的token本质是字节序列的映射,直接提取字符串的话会得到解码错误的结果,而非原始希腊字符。
解决方法
要得到可直接添加到Llama分词器的希腊字符token,需要做以下步骤:
从训练好的BPE分词器中正确提取token
训练完成后,不要直接提取字符串形式的token,而是通过分词器的编码/解码流程还原正确的Unicode字符:# 获取所有token的ID和对应的字节序列映射 vocab = tokenizer.get_vocab() valid_greek_tokens = [] for token_str, token_id in vocab.items(): # 用ByteLevel的解码逻辑还原原始Unicode字符 decoded_token = tokenizer.pre_tokenizer.decode([token_str]) # 筛选出包含希腊字符的token(可选,按需调整) if any('\u0370' <= char <= '\u03FF' for char in decoded_token): valid_greek_tokens.append(decoded_token)验证token的正确性
提取后可以验证这些token是否能被正确识别和使用:test_text = "Αυτό είναι ένα δοκιμαστικό κείμενο" # 用扩展后的分词器编码、解码文本 encoded = extender_tokenizer.encode(test_text) print(extender_tokenizer.decode(encoded.tokens))调整训练配置(可选)
如果希望BPE直接处理Unicode字符而非字节,可以替换预分词器为Whitespace或Punctuation,但这样可能会增加未登录词(OOV)的数量,需要根据需求权衡:tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()
内容的提问来源于stack exchange,提问作者Anmova
相关产品推荐
相关产品推荐

