如何让LineByLineTextDataset按词而非字符切分文本语料
问题解决方案
核心根因
你代码中的自定义分词器被默认加载的RobertaTokenizerFast覆盖,导致实际生效的是Roberta默认的子词拆分逻辑,而非你实现的WordLevel空格分词规则。同时需确认词表中已包含你需要保留的完整数字字符串条目。
具体修正步骤
- 第一步:删除覆盖自定义分词器的代码
你已经实现了符合要求的WordLevelBertTokenizer,不需要再调用RobertaTokenizerFast.from_pretrained重新加载,直接使用自定义分词器即可。如果需要使用Fast接口的特性,可直接将自定义的分词器转换为Fast类型,无需重复加载。 - 第二步:补全词表条目
确认你的vocab.json中已添加所有需要作为完整token处理的数字字符串(比如"1234"),WordLevel分词器只会将词表中存在的完整字符串映射为单个id,未收录的内容才会触发拆分或返回。 - 第三步:适配数据集读取逻辑
LineByLineTextDataset默认读取原始文本字符串后直接传入分词器,不会提前做分词处理。如果你的语料已经用空格分隔好了所有token,可直接使用自定义分词器替换原代码中的分词器即可;如果需要自行实现拆分,推荐自行写数据集加载逻辑,按行读取后先按空格拆分,再传入分词器并指定is_split_into_words=True参数。
修正后核心代码示例
from tokenizers.implementations import BaseTokenizer from tokenizers import Tokenizer, pre_tokenizers from tokenizers.models import WordLevel from tokenizers.processors import BertProcessing from transformers import RobertaConfig, RobertaForMaskedLM, LineByLineTextDataset class WordLevelBertTokenizer(BaseTokenizer): """ WordLevelBertTokenizer 代表适用于BERT的简单词级别分词器 """ def __init__(self, vocab_file: str): tokenizer = Tokenizer(WordLevel.from_file(vocab_file)) tokenizer.pre_tokenizer = pre_tokenizers.WhitespaceSplit() sep_token_id = tokenizer.token_to_id("</s>") if sep_token_id is None: raise TypeError("sep_token not found in the vocabulary") cls_token_id = tokenizer.token_to_id("<s>") if cls_token_id is None: raise TypeError("cls_token not found in the vocabulary") tokenizer.post_processor = BertProcessing( ("</s>", sep_token_id), ("<s>", cls_token_id) ) parameters = { "model": "WordLevel", "sep_token": "</s>", "cls_token": "<s>", "pad_token": "<pad>", "mask_token": "<mask>", } super().__init__(tokenizer, parameters) # 直接使用自定义分词器,不要覆盖 tokenizer = WordLevelBertTokenizer("./wordlevel/vocab.json") config = RobertaConfig( vocab_size=tokenizer.get_vocab_size(), max_position_embeddings=514, # 注意该参数是最大序列长度,不要误填词表大小,默认514即可 num_attention_heads=12, num_hidden_layers=6, type_vocab_size=1, ) model = RobertaForMaskedLM(config=config) print(f'Num of model parameters = {model.num_parameters()}') # 直接传入自定义分词器构建数据集 dataset = LineByLineTextDataset( tokenizer=tokenizer, file_path="./optiver.txt", block_size=128, )
测试验证代码
# 假设词表中已存在"1234"条目 test = ["1234"] print(tokenizer.encode(test, is_split_into_words=True)) # 预期输出会包含"1234"对应的单个id,而非拆分后的多个数字id
内容的提问来源于stack exchange,提问作者Roman Kazmin
相关产品推荐
相关产品推荐

