AI大模型探索之路-训练篇10:大语言模型Transformer库-Tokenizer组件实践

05-14 阅读 0评论

系列篇章💥

AI大模型探索之路-训练篇1:大语言模型微调基础认知

AI大模型探索之路-训练篇2:大语言模型预训练基础认知

AI大模型探索之路-训练篇3:大语言模型全景解读

AI大模型探索之路-训练篇4:大语言模型训练数据集概览

AI大模型探索之路-训练篇5:大语言模型预训练数据准备-词元化

AI大模型探索之路-训练篇6:大语言模型预训练数据准备-预处理

AI大模型探索之路-训练篇7:大语言模型Transformer库之HuggingFace介绍

AI大模型探索之路-训练篇8:大语言模型Transformer库-预训练流程编码体验

AI大模型探索之路-训练篇9:大语言模型Transformer库-Pipeline组件实践


目录

  • 系列篇章💥
  • 前言
  • 一、Tokenizer概览
  • 二、Tokenizer的工作原理
  • 三、Tokenizer的使用方法
    • 1、加载与保存
    • 2、句子分词
    • 3、查看词典
    • 4、索引转换
    • 5、填充与截断
    • 6、其他输入部分
    • 7、快速调用方式
    • 四、Fast/Slow Tokenizer
    • 五、自定义Tokenizer
    • 六、Tokenizer与模型训练
    • 总结

      前言

      在自然语言处理(NLP)的世界里,文本数据的处理和理解是至关重要的一环。为了使得计算机能够理解和处理人类的自然语言,我们需要将原始的、对人类可读的文本转化为机器可以理解的格式。这就是Tokenizer,或者我们常说的分词器,发挥作用的地方。

      一、Tokenizer概览

      官网API地址:https://huggingface.co/docs/transformers/main_classes/tokenizer

      Tokenizer是自然语言处理中的一个核心组件,它的主要功能是将原始文本转换为机器学习模型能够处理的格式。这一过程看似简单,实则包含了许多复杂且精细的步骤。在深度学习中的Transformer架构及其衍生模型中,Tokenizer的工作流程通常包括两个关键步骤:

      1)首先,是文本分解。这一步的目的是将原始的、连续的文本分割成更细的粒度单元,这些单元可以是单词级别,也可以是子词级别,甚至是字符级别。这一步骤的目标是将文本分解为可以被模型理解并处理的基本单元。

      2)其次,是编码映射。这一步的目标是将这些基本单元转换为模型可以理解的数值形式,最常见的形式是整数序列。这样,我们就可以将这些数值输入到模型中,让模型进行学习和预测。

      在接下来的内容中,我们将详细探讨Tokenizer的工作原理,以及如何在实际的自然语言处理任务中使用Tokenizer。

      二、Tokenizer的工作原理

      Tokenizer的工作原理涉及:

      1)文本分解:将文本分解为更小的单元。

      2)词汇表:使用词汇表将文本单元映射到数值ID。

      3)特殊标记:添加如[CLS]、[SEP]等特殊标记,以适应模型的特定需求。

      在序列标注任务中,特殊标记帮助模型识别序列的开始和结束。

      # 展示特殊标记的添加
      sequence = "Here is an example sequence."
      encoded_sequence = tokenizer(sequence, add_special_tokens=True)
      print(encoded_sequence)
      

      三、Tokenizer的使用方法

      Tokenizer的使用流程一般遵循以下步骤:

      1)导入Tokenizer库:从NLP库(例如Hugging Face的transformers)导入Tokenizer类。

      2)加载预训练Tokenizer:通过指定模型名称加载预训练的Tokenizer实例。

      3)文本转换:将文本数据输入Tokenizer进行编码转换。

      4)获取编码输出:Tokenizer输出编码后的数据,通常包括:

      -输入ID:转换后的整数序列,用于模型输入。

      -注意力掩码(Attention Mask):标识哪些输入ID是有效内容,哪些是填充(padding)。

      -类别ID(Token Type IDs):在某些任务中区分句子对的两个不同句子。

      代码示例:

      下面是一个使用Tokenizer的代码示例:

      from transformers import AutoTokenizer
      # 加载预训练的Tokenizer
      tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
      # 待处理的文本
      text = "Transformers are the core of modern NLP tasks."
      # 使用Tokenizer进行编码
      encoded_input = tokenizer(text, return_tensors='pt')
      # 访问编码结果
      input_ids = encoded_input['input_ids']
      attention_mask = encoded_input['attention_mask']
      

      Tokenizer的基本使用

      from transformers import AutoTokenizer
      sen = "吃葡萄不吐葡萄皮!"
      

      1、加载与保存

      1)加载模型

      # 从HuggingFace加载,输入模型名称,即可加载对于的分词器
      tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese")
      tokenizer
      

      输出结果:

      BertTokenizerFast(name_or_path='uer/roberta-base-finetuned-dianping-chinese', vocab_size=21128, model_max_length=1000000000000000019884624838656, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True),  added_tokens_decoder={
      	0: AddedToken("[PAD]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	100: AddedToken("[UNK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	101: AddedToken("[CLS]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	102: AddedToken("[SEP]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	103: AddedToken("[MASK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      }
      

      2)保存模型

      # tokenizer 保存到本地
      tokenizer.save_pretrained("./roberta_tokenizer")
      ('./roberta_tokenizer/tokenizer_config.json',
       './roberta_tokenizer/special_tokens_map.json',
       './roberta_tokenizer/vocab.txt',
       './roberta_tokenizer/added_tokens.json',
       './roberta_tokenizer/tokenizer.json')
      

      会自动在同层级目录roberta_tokenizer中存放下载下来的模型

      3)从本地加载模型

      # 从本地加载tokenizer
      tokenizer = AutoTokenizer.from_pretrained("./roberta_tokenizer/")
      tokenizer
      

      输出结果:

      BertTokenizerFast(name_or_path='./roberta_tokenizer/', vocab_size=21128, model_max_length=1000000000000000019884624838656, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True),  added_tokens_decoder={
      	0: AddedToken("[PAD]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	100: AddedToken("[UNK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	101: AddedToken("[CLS]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	102: AddedToken("[SEP]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	103: AddedToken("[MASK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      }
      

      2、句子分词

      tokens = tokenizer.tokenize(sen)
      tokens
      

      输出:

      ['吃', '葡', '萄', '不', '吐', '葡', '萄', '皮', '!']
      

      3、查看词典

      tokenizer.vocab
      

      输出如下

      AI大模型探索之路-训练篇10:大语言模型Transformer库-Tokenizer组件实践

      查看词典大小

      tokenizer.vocab_size
      

      21128

      4、索引转换

      1)将词序列转换为id序列

      ids = tokenizer.convert_tokens_to_ids(tokens)
      ids
      

      输出:

      [1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106]
      

      2)将id序列转换为token序列

      tokens = tokenizer.convert_ids_to_tokens(ids)
      tokens
      

      输出:

      ['吃', '葡', '萄', '不', '吐', '葡', '萄', '皮', '!']
      

      3)将token序列转换为string

      str_sen = tokenizer.convert_tokens_to_string(tokens)
      str_sen
      

      输出:

      '吃 葡 萄 不 吐 葡 萄 皮!'
      

      4)更便捷的实现方式

      将字符串转换为id序列,又称之为编码

      ids = tokenizer.encode(sen, add_special_tokens=True)
      ids
      

      输出:

      [101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102]
      

      将id序列转换为字符串,又称之为解码

      str_sen = tokenizer.decode(ids, skip_special_tokens=False)
      str_sen
      

      输出:

      '[CLS] 吃 葡 萄 不 吐 葡 萄 皮! [SEP]'
      

      5、填充与截断

      1)填充

      ids = tokenizer.encode(sen, padding="max_length", max_length=15)
      ids
      

      输出:

      [101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102, 0, 0, 0, 0]
      

      2)截断

      ids = tokenizer.encode(sen, max_length=5, truncation=True)
      ids
      

      输出:

      [101, 1391, 5868, 5843, 102]
      

      6、其他输入部分

      ids = tokenizer.encode(sen, padding="max_length", max_length=15)
      ids
      

      输出:

      [101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102, 0, 0, 0, 0]
      

      查看其他部分内容

      attention_mask = [1 if idx != 0 else 0 for idx in ids]
      token_type_ids = [0] * len(ids)
      ids, attention_mask, token_type_ids
      

      输出:

      ([101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
      

      7、快速调用方式

      1)简化调用

      简化调用:这是Tokenizer对象的直接调用,它通常是一个简化的方法,提供了基本的编码功能。

      参数限制:此方法的参数选项可能较少,只包括一些常用的参数,如padding和max_length。

      适用场景:适用于大多数标准情况,当需要执行常规的编码任务时,可以使用此方法。

      inputs = tokenizer.encode_plus(sen, padding="max_length", max_length=15)
      inputs
      

      输出:

      {'input_ids': [101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102, 0, 0, 0, 0], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]}
      

      2)增强调用

      增强功能:encode_plus方法提供了更多的功能和更细粒度的控制,包括对分词、编码、填充、截断等过程的额外配置。

      返回值:encode_plus方法通常返回一个字典,包含了一系列的输出,如输入ID、注意力掩码、标记类型ID等,这些输出可以直接用于模型的输入。

      参数丰富:此方法允许用户指定更多的参数,如return_tensors(指定返回张量类型)、return_token_type_ids(返回标记类型ID)、return_attention_mask(返回注意力掩码)等。

      适用场景:当你需要更细致地控制文本编码过程,或者需要额外的信息(如注意力掩码或标记类型ID)时,使用encode_plus方法。

      inputs = tokenizer(sen, padding="max_length", max_length=15)
      inputs
      

      输出:

      {'input_ids': [101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 106, 102, 0, 0, 0, 0], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]}
      

      8、处理batch数据

      sens = ["吃葡萄不吐葡萄皮",
              "不吃葡萄到吐葡萄皮",
              "顺势而为"]
      res = tokenizer(sens)
      res
      

      输出:

      {'input_ids': [[101, 1391, 5868, 5843, 679, 1402, 5868, 5843, 4649, 102], [101, 679, 1391, 5868, 5843, 1168, 1402, 5868, 5843, 4649, 102], [101, 7556, 1232, 5445, 711, 102]], 'token_type_ids': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]]}
      

      批处理可以很大层度提升我们的处理性能

      %%time
      # 单条循环处理
      for i in range(1000):
          tokenizer(sen)
      

      CPU times: user 45.3 ms, sys: 0 ns, total: 45.3 ms

      Wall time: 44.6 ms

      %%time
      # 处理batch数据
      res = tokenizer([sen] * 1000)
      

      CPU times: user 27.7 ms, sys: 15.6 ms, total: 43.2 ms

      Wall time: 7.68 ms

      四、Fast/Slow Tokenizer

      在Hugging Face的transformers库中,Tokenizer分为两种类型:Fast Tokenizer和Slow Tokenizer。

      1)Slow Tokenizer:通常是用Python编写的,速度较慢,但在所有环境中都能保证一致性和可移植性。

      2)Fast Tokenizer:使用Rust编写,并通过PyTorch的C++扩展或Python的C扩展提供,速度非常快,尤其是在处理大量数据时。Fast Tokenizers提供了与Slow Tokenizers相同的功能,但速度更快。

      选择使用哪种Tokenizer取决于具体的需求。如果对性能要求极高,或者需要处理大量数据,推荐使用Fast Tokenizer。如果需要确保代码的可移植性,或者在性能要求不是非常关键的场景下,可以使用Slow Tokenizer。

      在transformers库中,AutoTokenizer类会自动选择Fast Tokenizer(如果可用),以提供最佳性能。如果需要显式选择Tokenizer类型,可以使用模型的特定Tokenizer类,如BertTokenizer或RobertaTokenizer。

      fast_tokenizer 使用查看

      sen = "吃葡萄不吐葡萄皮!"
      fast_tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese")
      fast_tokenizer
      

      输出结果:

      BertTokenizerFast(name_or_path='uer/roberta-base-finetuned-dianping-chinese', vocab_size=21128, model_max_length=1000000000000000019884624838656, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True),  added_tokens_decoder={
      	0: AddedToken("[PAD]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	100: AddedToken("[UNK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	101: AddedToken("[CLS]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	102: AddedToken("[SEP]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	103: AddedToken("[MASK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      }
      

      slow_tokenizer 使用查看

      slow_tokenizer = AutoTokenizer.from_pretrained("uer/roberta-base-finetuned-dianping-chinese", use_fast=False)
      slow_tokenizer
      
      BertTokenizer(name_or_path='uer/roberta-base-finetuned-dianping-chinese', vocab_size=21128, model_max_length=1000000000000000019884624838656, is_fast=False, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'}, clean_up_tokenization_spaces=True),  added_tokens_decoder={
      	0: AddedToken("[PAD]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	100: AddedToken("[UNK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	101: AddedToken("[CLS]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	102: AddedToken("[SEP]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      	103: AddedToken("[MASK]", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
      }
      

      fast_tokenizer 批量执行耗时

      %%time
      # 处理batch数据
      res = fast_tokenizer([sen] * 10000)
      

      CPU times: user 323 ms, sys: 146 ms, total: 468 ms

      Wall time: 172 ms

      slow_tokenizer 批量执行耗时

      %%time
      # 处理batch数据
      res = slow_tokenizer([sen] * 10000)
      

      CPU times: user 1.1 s, sys: 15.8 ms, total: 1.12 s

      Wall time: 1.12 s

      五、自定义Tokenizer

      用户可以根据特定需求定制Tokenizer:

      1)自定义词汇表:创建特定领域的词汇表。

      2)自定义规则:添加自定义分词规则以适应特定场景。

      实践案例:在医疗领域的文本处理中,自定义Tokenizer能够识别专业术语。

      工具和资源:Hugging Face的transformers库允许用户通过继承和修改现有Tokenizer类来创建自定义Tokenizer。

      代码样例:

      from transformers import BertTokenizerFast
      class CustomBertTokenizer(BertTokenizerFast):
          def __init__(self, vocab_file, **kwargs):
              super().__init__(vocab_file=vocab_file, **kwargs)
              # 自定义逻辑...
      # 假设已有自定义词汇表
      custom_tokenizer = CustomBertTokenizer(vocab_file="path_to_vocab.txt")
      encoded_custom = custom_tokenizer("Customizing Tokenizer is flexible.", return_tensors="pt")
      print(encoded_custom)
      

      六、Tokenizer与模型训练

      Tokenizer在模型训练中的作用包括:

      1)数据预处理:将训练数据转换为模型可处理的格式。

      2)与模型整合:确保Tokenizer与模型的输入层完全兼容。

      实践案例:在训练一个自定义文本分类模型时,需要确保Tokenizer的输出与模型的输入层匹配。

      工具和资源:使用PyTorch或TensorFlow框架,可以方便地将Tokenizer集成到模型训练流程中。

      代码样例:

      # 导入必要的类:从transformers库中导入BertForSequenceClassification(用于序列分类的BERT模型),Trainer(训练器类),和TrainingArguments(训练参数类)
      from transformers import BertForSequenceClassification, Trainer, TrainingArguments
      #初始化模型:使用BertForSequenceClassification类创建一个序列分类模型实例。这个模型是基于BERT的,并且是预训练好的,我们通过from_pretrained方法加载它。num_labels参数指定了分类任务的标签数量。
      model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
      # 准备数据集
      # ...
      #定义训练参数:TrainingArguments类用于定义训练过程中的各种参数,如输出目录output_dir,训练轮数num_train_epochs,每个设备的训练批次大小per_device_train_batch_size,预热步数warmup_steps,权重衰减weight_decay,以及日志目录logging_dir。
      training_args = TrainingArguments(
          output_dir="./results",
          num_train_epochs=3,
          per_device_train_batch_size=16,
          warmup_steps=500,
          weight_decay=0.01,
          logging_dir="./logs",
      )
      # 初始化Trainer:Trainer类负责执行模型的实际训练。我们传入模型实例、训练参数和Tokenizer。train_dataset是一个包含训练数据的PyTorch数据集对象,这里省略了其定义和准备过程。
      trainer = Trainer(
          model=model,
          args=training_args,
          train_dataset=train_dataset,
          tokenizer=tokenizer
      )
      #执行训练:调用trainer.train()方法开始训练
      trainer.train()
      

      总结

      Tokenizer是Transformer模型不可或缺的一部分,它直接影响模型输入的质量和模型的性能。正确选择和使用Tokenizer对于实现高效的NLP任务至关重要。通过上述实践,我们可以看到Tokenizer不仅需要适应特定的模型架构,还要满足特定任务的需求,并考虑到性能优化和可定制性。

      AI大模型探索之路-训练篇10:大语言模型Transformer库-Tokenizer组件实践

      🎯🔖更多专栏系列文章:AIGC-AI大模型探索之路

      如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!


免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]