LLM 大模型学习必知必会系列(五):数据预处理(Tokenizer分词器)、模板(Template)设计以及LLM技术选型

简介: LLM 大模型学习必知必会系列(五):数据预处理(Tokenizer分词器)、模板(Template)设计以及LLM技术选型

LLM 大模型学习必知必会系列(五):数据预处理(Tokenizer分词器)、模板(Template)设计以及LLM技术选型

在模型训练过程中,数据及数据处理是最为重要的工作之一。在当前模型训练流程趋于成熟的情况下,数据集的好坏,是决定了该次训练能否成功的最关键因素。

在上一篇中,我们提到了模型训练的基本原理是将文字转换索引再转换为对应的向量,那么文字转为向量的具体过程是什么?

1.分词器(Tokenizer)

在NLP(自然语言处理)领域中,承担文字转换索引(token)这一过程的组件是tokenizer。每个模型有自己特定的tokenizer,但它们的处理过程是大同小异的。

首先我们安装好魔搭的模型库modelscope和训练框架swift:

#激活conda环境后
pip install modelscope ms-swift -U

我们使用“千问1.8b”模型将“杭州是个好地方”转为tokens的具体方式是在python中调用:

from modelscope import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("qwen/Qwen-1_8B-Chat", trust_remote_code=True)
print(tokenizer('杭州是个好地方'))
#{'input_ids': [104130, 104104, 52801, 100371], 'token_type_ids': [0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1]}

其中的input_ids就是上面我们说的文字的token。可以注意到token的个数少于实际文字的数量,这是因为在转为token的时候,并不是一个汉字一个token的,可能会将部分词语变为一个token,也可能将一个英文转为两部分(如词根和时态),所以token数量和文字数量不一定对得上。

2.模板(Template)

每种模型有其特定的输入格式,在小模型时代,这种输入格式比较简单:

[CLS]杭州是个好地方[SEP]

[CLS]代表了句子的起始,[SEP]代表了句子的终止。在BERT中,[CLS]的索引是101,[SEP]的索引是102,加上中间的句子部分,在BERT模型中整个的token序列是:

101, 100, 1836, 100, 100, 100, 1802, 1863, 102

我们可以看到,这个序列和上面千问的序列是不同的,这是因为这两个模型的词表不同。

在LLM时代,base模型的格式和上述的差不多,但chat模型的格式要复杂的多,比如千问chat模型的template格式是:

<|im_start|>system
You are a helpful assistant!
<|im_end|>
<|im_start|>user
How are you?<|im_end|>
<|im_start|>assistant

其中“You are a helpful assistant!”是system字段,“How are you?”是用户问题,其他的部分都是template的格式。

system字段是chat模型必要的字段,这个字段会以命令方式提示模型在下面的对话中遵循怎么样的范式进行回答,比如:

“You are a helpful assistant!”
“下面你是一个警察,请按照警察的要求来审问我”
“假如你是一个爱哭的女朋友,下面的对话中清扮演好这个角色”

system字段规定了模型行为准则,比如当模型作为Agent使用时,工具集一般也是定义在system中的:

“你是一个流程的执行者,你有如下工具可以使用:
工具1:xxx,输入格式是:xxx,输出格式是:xxx,作用是:xxx
工具2:xxx,输入格式是:xxx,输出格式是:xxx,作用是:xxx”

复杂的template有助于模型识别哪部分是用户输入,哪部分是自己之前的回答,哪部分是给自己的要求。

比较麻烦的是,目前各开源模型还没有一个统一的template标准。在SWIFT中,我们提供了绝大多数模型的template,可以直接使用:

register_template(
    TemplateType.default,
    Template([], ['### Human:\n', '{
   
   {QUERY}}\n\n', '### Assistant:\n'],
             ['\n\n'], [['eos_token_id']], DEFAULT_SYSTEM, ['{
   
   {SYSTEM}}\n\n']))

#ou can set the query as '' to serve as a template for pre-training.
register_template(TemplateType.default_generation,
                  Template([], ['{
   
   {QUERY}}'], None, [['eos_token_id']]))
register_template(
    TemplateType.default_generation_bos,
    Template([['bos_token_id']], ['{
   
   {QUERY}}'], None, [['eos_token_id']]))

qwen_template = Template(
    [], ['<|im_start|>user\n{
   
   {QUERY}}<|im_end|>\n<|im_start|>assistant\n'],
    ['<|im_end|>\n'], ['<|im_end|>'], DEFAULT_SYSTEM,
    ['<|im_start|>system\n{
   
   {SYSTEM}}<|im_end|>\n'])
register_template(TemplateType.qwen, qwen_template)
register_template(TemplateType.chatml, deepcopy(qwen_template))
...

有兴趣的小伙伴可以阅读:https://github.com/modelscope/swift/blob/main/swift/llm/utils/template.py 来获得更细节的信息。

template拼接好后,直接传入tokenizer即可。

微调任务是标注数据集,那么必然有指导性的labels(模型真实输出)存在,将这部分也按照template进行拼接,就会得到类似下面的一组tokens:

input_ids: [34,   56,   21,   12,   45,   73, 96, 45, 32, 11]
           ---------用户输入部分---------   ----模型真实输出----
labels:    [-100, -100, -100, -100, -100, 73, 96, 45, 32, 11]

在labels中,我们将用户输入的部分(问题)替换成了-100,保留了模型输入部分。在模型进行运算时,会根据input_ids的前面的tokens去预测下一个token,就比如:

已知token                    预测的下一个token
34                        ->17
34,56                     ->89
...
34,56,21,12,45            ->121
34,56,21,12,45,73         ->99
34,56,21,12,45,73,96      ->45
34,56,21,12,45,73,96,45   ->14
34,56,21,12,45,73,96,45,32->11

可以看到,这个预测不一定每个都预测对了,而且呈现了下三角矩阵的形态。那么训练的时候就可以这样进行对比:

34,   56,   21,   12,   45,  121,  99,  45,  32,  11
-100, -100, -100, -100, -100, 73,  96,  45,  14,  11

-100部分计算loss时会被忽略,因为这是用户输入,不需要考虑预测值是什么。只要对比下对应的位置对不对就可以计算它们的差异了,这个差异值被称为loss或者残差。我们通过计算梯度的方式对参数进行优化,使模型参数一点一点向真实的未知值靠近。使用的残差算法叫做交叉熵

在SWIFT中提供了根据模型类型构造template并直接转为token的方法,这个方法输出的结构可以直接用于模型训练和推理:

from swift.llm.utils import get_template, Template
from modelscope import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("qwen/Qwen-1_8B-Chat", trust_remote_code=True)
template: Template = get_template(
    'qwen',
    tokenizer,
    max_length=256)
resp = template.encode({
   
   'query': 'How are you?', "response": "I am fine"})[0]
print(resp)
#{'input_ids': [151644, 8948, 198, 2610, 525, 264, 10950, 17847, 13, 151645, 198, 151644, 872, 198, 4340, 525, 498, 30, 151645, 198, 151644, 77091, 198, 40, 1079, 6915, 151645], 'labels': [-100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, -100, 40, 1079, 6915, 151645]}

input_ids和labels可以直接输入模型来获取模型的输出:

from modelscope import AutoModelForCausalLM
import torch
model = AutoModelForCausalLM.from_pretrained("qwen/Qwen-1_8B-Chat", trust_remote_code=True).to(0)
resp = {
   
   key: torch.tensor(value).to(0) for key, value in resp.items()}
output = model(**resp)
print(output)

3.方法选型

判断自己的场景需要什么样的方法是使用LLM的第一步。下面我们会对比直接推理(提示词工程)、训练、RAG、Agent方法的具体场景,讲解这几种方式的特点,并给出适用场景、使用难度、准确性、成本、缺点几个方面的总结。

3.1直接推理(提示词工程)

这种方式特指直接使用现有LLM,利用prompt范式激活模型不同的能力完成特定需求。直接推理方式对开发的要求较低,一般可以完成通用类型的任务,如通用知识问答、角色扮演等。使用方式如下:

用户:你是一个经验丰富的导游,请使用导游的话术回答游客的问题。
模型:当然可以!请问你需要问些什么呢?
用户:我想去杭州旅行,请告诉我哪里比较值得去。
模型:当然可以!作为一个导游,我可以为你讲解杭州的风景和美食...
  • 使用难度

    • 较低,只需要调用模型接口,编写对应的prompt即可。但编写好的prompt也是具有一定技巧的,具体可以查看我们的教程中的提示词工程部分。

      提示词工程无论是直接推理或训练后推理都是需要的

  • 适用场景

    • 视模型本身的能力而定,在采用该方式之前需要对现有模型针对自己的业务领域进行较为充分的评估。
  • 准确性

    • 由于是原始模型只接受了通用知识的训练,因此在特定领域的场景下可能存在胡编乱造的可能性(幻觉问题)。使用者需要注意自己的专业场景下是否使用该通用模型能解决所有问题,一般建议直接试用该模型给出模型能力的具体评估。
  • 成本

    • 开发成本较低。如果是开源模型,需要选用合适的硬件及推理方式。这部分在我们教程中的推理章节会有讲解。如果是闭源调用,只需要使用对应模型的接口API即可。
  • 缺点

    • 由于模型没有经过针对特有领域的知识,因此效果会比较不可控。比如,在评测时模型表现尚可,但在实际使用中发现模型出现了严重的幻觉和知识匮乏问题,如果是闭源调用则该问题会比较难以解决(可能涉及到工程架构改变),如果是开源模型可以考虑使用训练和RAG的方式解决。

3.2 训练

全量训练和轻量训练是训练的两种方式,它们的区别在于:

全量训练在给定LLM模型上冻结一定的参数(或不冻结任何参数)进行训练,一般耗费显存较高,训练周期比较长。受限于成本问题,最近出现了轻量微调方式,主要方案是在模型结构上附着一个额外结构,在训练时冻结原模型并训练额外结构,推理时将额外结构加载起来或合并回原来模型(并不是所有的额外结构都支持合并,支持者比如LoRA,不支持者比如Side)。轻量微调目前的最流行结构是LoRA,该结构理解简单,训练成本较低,在部分任务上可以达到全量微调的效果。

轻量微调另一个方式就是量化(请查看另一篇文章),即对模型的float32权重或float16权重进行缩放,使其变成int类型的整形,节省显存或计算时长。

  • 一般情况下建议选择轻量训练,优先使用LoRA等方式
  • 如果效果不好,可以考虑解冻原模型的部分参数,比如normalizer、embedder等进行训练,也就是全量训练+轻量训练的方式
  • 如果显存受限,可以考虑使用量化进行训练。量化和轻量训练并不互斥,比如QLoRA(量化+LoRA),但需要注意量化后训练和推理结果会有所下降

一般来说,预训练或继续训练不建议使用轻量训练,小数据量微调情况下建议优先使用轻量训练。

  • 适用场景
  • 场景存在特殊知识,需要进行知识灌注,可以使用继续训练+全量训练
  • 需要对回复的风格或范式进行定制化,可以使用人类对齐训练或微调+全量/轻量训练
  • 模型原有能力不够,如对读入的doc文件进行理解并进行归纳总结,或特有场景的文本进行分类,但原有模型对该任务的回答存在问题,可以使用微调+全量/轻量训练

简单来说,模型的训练是让模型“找规律”的过程。比如告诉模型1+1=2, 2+2=4,那么让模型分析3+3=?

如果数据是带有规律的,比如文字顺序、逻辑关系、图片元素(比如斑马总是带有黑白色的条纹),那么训练就可以将这些规律抽象出来;如果数据是“无规律的知识”,比如用A解决B问题,用C解决D问题,那么这些数据训练后就几乎不具有泛化性,因为模型无法分析出出现了E问题应该用A解决还是B解决,这时候应当选用RAG或者Agent方式,或者训练的目标改为让模型熟悉使用工具来解决问题。

  • 使用难度

    • 训练需要对模型结构、训练的流程有所了解。其理解成本比RAG高一些。
  • 准确性

    • 准确性依照训练的结果而定,训练后模型会按照训练集的风格和方式回答问题。一般来说训练后模型能力会有较大提升,但仍然可能存在幻觉问题。
  • 成本

    • 可以查看SWIFT的benchmark。我们比较了主要模型的训练显存需求和训练速度,用户可以按需评估。

    | Model Type [LoRA] | Max Length | Training Speed (samples/s) | GPU Memory (GiB) |
    |--------------------------|---------------|----------------------------|------------------|
    | qwen-1_8b-chat | 512 | 9.88 | 6.99 |
    | 1024 | 9.90 | 10.71 |
    | 2048 | 8.77 | 16.35 |
    | 4096 | 5.92 | 23.80 |
    | 8192 | 4.19 | 37.03 |
    | qwen-7b-chat | 512 | 7.43 | 18.01 |
    | 1024 | 6.51 | 21.73 |
    | 2048 | 4.31 | 27.74 |
    | 4096 | 2.05 | 35.31 |
    | 8192 | 1.34 | 48.41 |
    | qwen-14b-chat | 512 | 5.63 | 30.14 |
    | 1024 | 4.36 | 34.43 |
    | 2048 | 2.60 | 40.14 |
    | 4096 | 1.17 | 47.95 |
    | 8192 | 0.79 | 60.74 |
    | qwen-72b-chat (2A100) | 512 | 1.41 | 67.68+73.07 |
    | 1024 | 1.02 | 70.25+77.11 |
    | 2048 | 0.59 | 73.71+78.54 |
    | 4096 | - | OOM |
    | 8192 | - | OOM |
    | chatglm3-6b | 512 | 6.72 | 13.94 |
    | 1024 | 6.16 | 12.99 |
    | 2048 | 4.20 | 17.20 |
    | 4096 | 1.92 | 29.80 |
    | 8192 | 1.24 | 66.82 |
    | yi-6b-chat | 512 | 5.27 | 13.72 |
    | 1024 | 5.07 | 15.44 |
    | 2048 | 3.84 | 16.95 |
    | 4096 | 1.99 | 28.25 |
    | 8192 | 1.35 | 43.81 |
    | yi-34b-chat | 512 | 2.32 | 66.72 |
    | 1024 | 1.76 | 69.10 |
    | 2048 | 1.05 | 71.34 |
    | 4096 | 0.47 | 78.72 |
    | 8192 | 0.31 (2
    A100) | 47.01+65.03 |
    | openbuddy-zephyr-7b-chat | 512 | 5.17 | 14.99 |
    | 1024 | 3.92 | 16.57 |
    | 2048 | 3.08 | 19.89 |
    | 4096 | 1.85 | 23.29 |
    | 8192 | 0.92 | 52.14 |
    | baichuan2-7b-chat | 512 | 6.09 | 18.18 |
    | 1024 | 5.36 | 17.45 |
    | 2048 | 3.43 | 19.18 |
    | 4096 | 1.69 | 34.22 |
    | 8192 | 1.16 | 45.47 |
    | baichuan2-13b-chat | 512 | 5.32 | 31.01 |
    | 1024 | 3.91 | 31.58 |
    | 2048 | 1.77 | 32.40 |
    | 4096 | 0.65 | 49.63 |
    | 8192 | 0.36 | 76.17 |

Model Type [FULL] Max Length Training Speed (samples/s) GPU Memory (GiB)
qwen-1_8b-chat 512 10.77 18.16
1024 10.39 18.62
2048 8.73 35.11
4096 5.45 31.62
8192 3.81 38.93
qwen-7b-chat 512 5.96 73.37
1024 5.00 73.64
2048 3.30 74.26
4096 1.64 78.76
8192 1.11 (2*A100) 61.34+73.00
qwen-14b-chat (2*A100) 512 3.66 60.42+72.31
1024 2.98 60.61+74.37
2048 1.93 60.70+78.22
4096 0.92 75.59+78.64
8192 0.62 76.59+77.68
  • 缺点

    • 相比RAG,输出可解释性不强
    • 存在幻觉问题
    • 在精确问答场景上可能会产出非专业结果(如法律行业)
    • 对知识更新频繁的场景不适用

3.3 RAG

RAG即检索增强生成,也就是通过模型外挂知识库的方式来辅助模型回答。一般来说会将用户问题变为向量,进向量数据库进行查询,并召回符合条件的文档或回答,之后将回答直接返回或输入模型整理后返回。RAG可以查看另一篇教程。

RAG和微调的选型问题一直是被问的较多的问题之一,两种方法的对比可以查看下表:

如果模型本身对专业知识理解不够(比如模型对召回的文档不能进行良好分析的情况),那么使用RAG是不够的,需要进行模型训练,或将模型训练和RAG结合起来使用。

  • 适用场景

    • 需要根据语料精确回答,比如法律或医疗领域
    • 搜索召回场景,比如搜索引擎
    • 知识频繁更新,灵活性较强的场景
  • 使用难度

    • 需要对RAG流程有所了解,选用对应的RAG框架或解决方案
  • 准确性

    • 准确性较高,可解释性也较高
  • 成本

    • 除模型本身的成本外,需要额外的向量数据库和工程端开发成本和维护成本
  • 缺点

    • 比模型直接回答多了查询召回步骤,单请求整体RT高一些
    • 如果场景和知识无关,比如非知识类问答,或API调用,或文档分析,文章总结等,RAG就不能起到作用

3.4 Agent

Agent适合于利用模型进行代码编写运行、API调用的复杂场景。Agent的主要思路是利用模型的CoT(思维链)能力进行复杂场景的流程串接。比如“生成一个具有今天天气特征的海报”,模型会先调用天气预报接口获得天气,之后生成海报文案,然后调用文生图模型生成海报。

  • 适用场景

    • 复杂的应用场景,需要模型产生思维过程,将整体任务拆分为具体任务进行执行,比如包含了运行代码、接口调用等过程
  • 使用难度

    • 需要对Agent和CoT过程有一定了解
    • 熟悉目前的Agent框架的能力上限
    • 需要熟悉模型的提示词工程才能做到较好的效果
  • 准确性

    • 一般来说模型越大准确性越高。比如GPT4(闭源)、Qwen-max(闭源)、Qwen-72b(开源)、ChatGLM4(闭源)等会具有良好的效果,小模型可能需要特殊训练。

    • 在格外复杂的场景下,比如任务复杂、描述含混不清、模型对行业流程不理解的情况下,需要对模型进行额外训练。

  • 成本

    • 一般和模型部署成本相同
  • 缺点

    • 对复杂的业务和人类复杂的行为如博弈、交流->更新的场景支持不好。比如,尚不能用Agent编写复杂的APP如淘宝,也不能模拟股市大盘。

4.模型选型

目前国内外开源模型已经超过了几百个,挑选合适的模型是一个比较关键的问题。在这里可以给出一些泛泛的意见:

  • Agent场景尽量选择较大的模型或者闭源LLM API(如GPT4、Qwen-max)

  • 训练场景中,数据量较大(比如大于10000条)、数据质量较高、专业度较高的训练优先选择base模型,数据量较少优先选择chat模型。在算力允许条件下可以进行对比训练实验

  • 关注国内外的开源可信模型榜单,选择排名较高或口碑较好的模型

具体参考博客:大模型落地实战指南:从选择到训练,深度解析显卡选型、模型训练技、模型选择巧

更多优质内容请关注公号:汀丶人工智能;会提供一些相关的资源和优质文章,免费获取阅读。

相关文章
|
21天前
|
前端开发 机器人 API
前端大模型入门(一):用 js+langchain 构建基于 LLM 的应用
本文介绍了大语言模型(LLM)的HTTP API流式调用机制及其在前端的实现方法。通过流式调用,服务器可以逐步发送生成的文本内容,前端则实时处理并展示这些数据块,从而提升用户体验和实时性。文章详细讲解了如何使用`fetch`发起流式请求、处理响应流数据、逐步更新界面、处理中断和错误,以及优化用户交互。流式调用特别适用于聊天机器人、搜索建议等应用场景,能够显著减少用户的等待时间,增强交互性。
141 2
|
17天前
|
机器学习/深度学习 自然语言处理 PyTorch
LLM-Mixer: 融合多尺度时间序列分解与预训练模型,可以精准捕捉短期波动与长期趋势
近年来,大型语言模型(LLMs)在自然语言处理领域取得显著进展,研究人员开始探索将其应用于时间序列预测。Jin等人提出了LLM-Mixer框架,通过多尺度时间序列分解和预训练的LLMs,有效捕捉时间序列数据中的短期波动和长期趋势,提高了预测精度。实验结果显示,LLM-Mixer在多个基准数据集上优于现有方法,展示了其在时间序列预测任务中的巨大潜力。
41 3
LLM-Mixer: 融合多尺度时间序列分解与预训练模型,可以精准捕捉短期波动与长期趋势
|
15天前
|
机器学习/深度学习 人工智能 运维
企业内训|LLM大模型在服务器和IT网络运维中的应用-某日企IT运维部门
本课程是为某在华日资企业集团的IT运维部门专门定制开发的企业培训课程,本课程旨在深入探讨大型语言模型(LLM)在服务器及IT网络运维中的应用,结合当前技术趋势与行业需求,帮助学员掌握LLM如何为运维工作赋能。通过系统的理论讲解与实践操作,学员将了解LLM的基本知识、模型架构及其在实际运维场景中的应用,如日志分析、故障诊断、网络安全与性能优化等。
40 2
|
19天前
|
机器学习/深度学习 数据采集 人工智能
文档智能 & RAG 让AI大模型更懂业务 —— 阿里云LLM知识库解决方案评测
随着数字化转型的深入,企业对文档管理和知识提取的需求日益增长。阿里云推出的文档智能 & RAG(Retrieval-Augmented Generation)解决方案,通过高效的内容清洗、向量化处理、精准的问答召回和灵活的Prompt设计,帮助企业构建强大的LLM知识库,显著提升企业级文档管理的效率和准确性。
|
2天前
|
人工智能 自然语言处理 算法
政务培训|LLM大模型在政府/公共卫生系统的应用
本课程是TsingtaoAI公司面向某卫生统计部门的政府职员设计的大模型技术应用课程,旨在系统讲解大语言模型(LLM)的前沿应用及其在政府业务中的实践落地。课程涵盖从LLM基础知识到智能化办公、数据处理、报告生成、智能问答系统构建等多个模块,全面解析大模型在卫生统计数据分析、报告撰写和决策支持等环节中的赋能价值。
17 2
|
21天前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
20天前
|
人工智能 前端开发
大模型体验体验报告:OpenAI-O1内置思维链和多个llm组合出的COT有啥区别?传统道家理论+中学生物理奥赛题测试,名不虚传还是名副其实?
一个月前,o1发布时,虽然让人提前体验,但自己并未进行测试。近期终于有机会使用,却仍忘记第一时间测试。本文通过两个测试案例展示了o1的强大能力:一是关于丹田及练气的详细解答,二是解决一道复杂的中学生物理奥赛题。o1的知识面广泛、推理迅速,令人印象深刻。未来,或许可以通过赋予o1更多能力,使其在更多领域发挥作用。如果你有好的测试题,欢迎留言,一起探索o1的潜力。
|
21天前
|
机器学习/深度学习 人工智能 自然语言处理
前端大模型入门(三):编码(Tokenizer)和嵌入(Embedding)解析 - llm的输入
本文介绍了大规模语言模型(LLM)中的两个核心概念:Tokenizer和Embedding。Tokenizer将文本转换为模型可处理的数字ID,而Embedding则将这些ID转化为能捕捉语义关系的稠密向量。文章通过具体示例和代码展示了两者的实现方法,帮助读者理解其基本原理和应用场景。
116 1
|
20天前
|
计算机视觉
Deepseek开源多模态LLM模型框架Janus,魔搭社区最佳实践
deepseek近期推出了简单、统一且灵活的多模态框架Janus,它能够统一处理多模态理解和生成任务。让我们一起来了解一下吧。
|
21天前
|
机器学习/深度学习 人工智能 架构师
Python学习圣经:从入门到精通Python,打好 LLM大模型的基础
Python学习圣经:从0到1精通Python,打好AI基础

热门文章

最新文章