网站开发的相关技能有哪些积分网站运营建设投标书
news/
2025/9/24 8:50:16/
文章来源:
网站开发的相关技能有哪些,积分网站运营建设投标书,建建设网站的,vx小程序怎么做告别2023#xff0c;迎接2024。大模型技术已成为业界关注焦点#xff0c;你是否也渴望掌握这一领域却又不知从何学起#xff1f;
本篇文章将特别针对入门新手#xff0c;以浅显易懂的方式梳理大模型的发展历程、核心网络结构以及数据微调等关键技术。
如果你在阅读中收获…告别2023迎接2024。大模型技术已成为业界关注焦点你是否也渴望掌握这一领域却又不知从何学起
本篇文章将特别针对入门新手以浅显易懂的方式梳理大模型的发展历程、核心网络结构以及数据微调等关键技术。
如果你在阅读中收获良多期待你能积极地通过点赞、转发与收藏给予支持让更多对此领域感兴趣的朋友能够共享这份学习资源共同踏入大模型技术的广阔天地。
大模型发展历史相关基础知识介绍 该图从左到右 基于 传统的词向量模型以灰色线显示decoder-only 模型在蓝色分支encoder-only 模型在粉色分支encoder-decoder 模型在绿色分支。模型在时间线上的垂直位置表示它们的发布日期。开源模型由实心方块表示而闭源模型由空心方块表示。右下角的堆积条形图显示了各公司和机构的模型数量。
国内开源大模型:清华: chatglm系列; 阿里: Qwen系列; 百川: baichuan 零一万物; vivo: BlueLM-7B; 智源: Aquila2-70B; 上海AI实验室InternLM 昆仑万维: Skywork; meta: llama; google: gemini; openai: chatgpt
通俗易懂讲解大模型系列 用通俗易懂的方式讲解ChatGPT 开放的多模态的DALL-E 3功能好玩到停不下来 用通俗易懂的方式讲解结合检索和重排序模型改善大模型 RAG 效果明显 用通俗易懂的方式讲解基于扩散模型Diffusion,文生图 AnyText 的效果太棒了 用通俗易懂的方式讲解在 CPU 服务器上部署 ChatGLM3-6B 模型 用通俗易懂的方式讲解ChatGLM3-6B 功能原理解析 用通俗易懂的方式讲解使用 LangChain 和大模型生成海报文案 用通俗易懂的方式讲解一个强大的 LLM 微调工具 LLaMA Factory 用通俗易懂的方式讲解ChatGLM3-6B 部署指南 用通俗易懂的方式讲解LangChain Agent 原理解析 用通俗易懂的方式讲解HugggingFace 推理 API、推理端点和推理空间使用详解 用通俗易懂的方式讲解使用 LangChain 封装自定义的 LLM太棒了 用通俗易懂的方式讲解使用 FastChat 部署 LLM 的体验太爽了 用通俗易懂的方式讲解基于 Langchain 和 ChatChat 部署本地知识库问答系统 用通俗易懂的方式讲解使用 Docker 部署大模型的训练环境 用通俗易懂的方式讲解在 Ubuntu 22 上安装 CUDA、Nvidia 显卡驱动、PyTorch等大模型基础环境 用通俗易懂的方式讲解Llama2 部署讲解及试用方式 用通俗易懂的方式讲解LangChain 知识库检索常见问题及解决方案 用通俗易懂的方式讲解基于 LangChain 和 ChatGLM2 打造自有知识库问答系统 用通俗易懂的方式讲解代码大模型盘点及优劣分析 用通俗易懂的方式讲解Prompt 提示词在开发中的使用
技术交流
建了AIGC大模型技术交流群 想要学习、技术交流、获取如下原版资料的同学可以直接加微信号mlc2060。加的时候备注一下研究方向 学校/公司CSDN即可。然后就可以拉你进群了。 方式①、微信搜索公众号机器学习社区后台回复加群 方式②、添加微信号mlc2060备注来自CSDN 技术交流 Transformers网络模型介绍 2017年,Google机器翻译团队发表的《Attention is All You Need》https://arxiv.org/pdf/1706.03762.pdf; 首次提出基于transformers自注意机制来实现seq2seq任务被视为开山鼻祖。
网络结构主要分为下面几块; 位置编码模块 多头注意力机制模块; 前馈网络结构(FFN)模块; 解码器模块;
位置编码总结
绝对位置编码
Sinusoidal位置编码是谷歌在Transformer模型中提出的一种绝对位置编码它的形式如下其中 表示词向量的维度 表示位置索引 和 表示位置向量的分量索引;
例如 和 分别表示位置的位置向量的第 和第 个分量: Sinusoidal位置编码的每个分量都是正弦或余弦函数所有每个分量的数值都具有周期性。Sinusoidal位置编码还具有远程衰减的特点。对于两个相同的词向量如果它们之间的距离越近则他们的内积分数越高反之则越低。如下图所示我们随机初始化两个向量x1和x2pos的位置从0开始逐步变大依次计算x1和x2之间的内积。我们发现随着x1和x2的相对距离的增加它们之间的内积分数震荡衰减。
!pip install -q mplfonts
!pip install -q mpl-font
!mplfonts initfrom mplfonts import use_font
use_font(Noto Sans Mono CJK SC)
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import mpl_font.notoclass SinPositionEncoding(nn.Module):def __init__(self, max_sequence_length, d_model, base10000):super().__init__()self.max_sequence_length max_sequence_lengthself.d_model d_modelself.base basedef forward(self):even_i torch.arange(0, self.d_model, 2).float()odd_i torch.arange(1, self.d_model, 2).float()position torch.arange(self.max_sequence_length, dtypetorch.float).reshape(-1, 1)even_pe torch.sin(position / torch.pow(self.base, even_i/self.d_model))odd_pe torch.cos(position / torch.pow(self.base, (odd_i-1)/self.d_model))stacked torch.stack([even_pe, odd_pe], dim2)return torch.flatten(stacked, start_dim1, end_dim2)
seq_len 80
d_model 128
spe SinPositionEncoding(max_sequence_lengthseq_len, d_modeld_model)()
print(spe.shape)fig,ax plt.subplots(1,1,figsize(6,10),dpi120)
im1 ax.imshow(spe,vminspe.min(), vmaxspe.max(),cmapplt.cm.rainbow)
# add space for colour bar
fig.subplots_adjust(right0.85)
cbar_ax fig.add_axes([0.86, 0.35, 0.04, 0.28])
plt.colorbar(im1, caxcbar_ax)
plt.show()
plt.close(fig)torch.Size([80, 128])fig,axes plt.subplots(1,2,figsize(15,6),dpi120)
out torch.matmul(spe,spe.T)
print(out.shape)
# 不同位置的位置编码点积可视化。
im1 axes[0].imshow(out ,vminout.min(), vmaxout.max(),cmapplt.cm.cool)
fig.subplots_adjust(right0.85)
cbar_ax fig.add_axes([0.45, 0.30, 0.02, 0.5])
fig.colorbar(im1, caxcbar_ax)
axes[0].set_title(序列长度80编码向量128,不同位置的位置编码点积可视化)# 远程位置衰减
base 40
seq_len 80
d_model 128
color_list[#55B7E6,#193E8F,#E53528,#F09739]
for index,dim in enumerate([32, 64,128, 256][::-1]):spe SinPositionEncoding(max_sequence_lengthseq_len, d_modeldim)()k_list [-index for index in range(1, base)][::-1] [index for index in range(base)]value [torch.matmul(spe[base-k],spe[basek].T ).tolist() for k in k_list]axes[1].plot(k_list, value, labeldim_%d%dim,colorcolor_list[index])
axes[1].legend()
axes[1].set_title(两向量内积和向量之间的相对位置趋势图呈现远程位置衰减)
axes[1].set_xlabel(两向量直接的位置距离)
plt.show()
plt.close(fig)torch.Size([80, 80])Sinusoidal位置编码中的正弦余弦函数具备周期性并且具备远程衰减的特性所以理论上也具备一定长度外推的能力。
旋转位置编码RoPE
可以看到RoPE形式上和Sinusoidal位置编码有点相似只不过Sinusoidal位置编码是加性的而RoPE可以视为乘性的。在θi 的选择上我们同样沿用了Sinusoidal位置编码的方案即它可以带来一定的远程衰减性。 Transformer升级之路2、博采众长的旋转式位置编码 https://spaces.ac.cn/archives/8265/comment-page-1
#position_id m-n 相对位置;
import numpy as np
def s(position_id, d128):theta_i lambda i: 10000**(-2*i/d)return np.mean([np.abs(np.sum(np.exp(1j*position_id*theta_i(np.arange(0, j))))) for j in range(0, d//2)])
seq_len np.arange(256) #
ys [s(x) for x in seq_len]
# # # #从图中我们可以可以看到随着相对距离的变大内积结果有衰减趋势的出现
plt.plot(seq_len, ys, c#55B7E6)plt.show()基于attention map的位置编码(Alibi)
使用正弦位置编码的transformer的外推能力非常弱。虽然旋转位置编码比正弦方法有所改进但仍未达到令人满意的结果。
为了解决长度外推的问题作者提出了一种更简单、更有效的位置方法即具有线性偏置的注意力ALiBi。ALiBi不向词嵌入添加位置嵌入相反它通过与距离成比例的惩罚来偏置query-key注意力分数。 import math
import torch
from torch import nndef get_slopes(n_heads: int):n 2 ** math.floor(math.log2(n_heads))m_0 2.0 ** (-8.0 / n)m torch.pow(m_0, torch.arange(1, 1 n))if n n_heads:m_hat_0 2.0 ** (-4.0 / n)m_hat torch.pow(m_hat_0, torch.arange(1, 1 2 * (n_heads - n), 2))m torch.cat([m, m_hat])return mtorch.no_grad()
def get_alibi_biases(n_heads: int, mask: torch.Tensor):m get_slopes(n_heads).to(mask.device)seq_len mask.size(0)distance torch.tril(torch.arange(0, -seq_len, -1).view(-1, 1).expand(seq_len, seq_len))print(distance)return distance[:, :, None] * m[None, None, :]seq_len 10
n_heads 8m get_slopes(n_heads)
print(input shape:, m.shape)alibi_biases torch.zeros(seq_len,seq_len)
for j in range(1,seq_len):for i in range(j, seq_len):alibi_biases[i, i - j] -j
print(alibi_biases)print(alibi_biases[:, :, None].shape, m[None, None, :].shape)
output alibi_biases[:, :, None] * m[None, None, :]
output.shapeinput shape: torch.Size([8])
tensor([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[-1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[-2., -1., 0., 0., 0., 0., 0., 0., 0., 0.],[-3., -2., -1., 0., 0., 0., 0., 0., 0., 0.],[-4., -3., -2., -1., 0., 0., 0., 0., 0., 0.],[-5., -4., -3., -2., -1., 0., 0., 0., 0., 0.],[-6., -5., -4., -3., -2., -1., 0., 0., 0., 0.],[-7., -6., -5., -4., -3., -2., -1., 0., 0., 0.],[-8., -7., -6., -5., -4., -3., -2., -1., 0., 0.],[-9., -8., -7., -6., -5., -4., -3., -2., -1., 0.]])
torch.Size([10, 10, 1]) torch.Size([1, 1, 8])torch.Size([10, 10, 8])位置编码的类型需要指定为float32
a torch.tensor(255,dtypetorch.bfloat16)
b a 1
c a 2
d a 3
e a 4
a,b,c,d,e(tensor(255., dtypetorch.bfloat16),tensor(256., dtypetorch.bfloat16),tensor(256., dtypetorch.bfloat16),tensor(258., dtypetorch.bfloat16),tensor(260., dtypetorch.bfloat16))# self.inv_freq.dtype torch.bfloat16 when bfloat16 is enabled during training
t torch.arange(4096, dtypetorch.float32)
plt.scatter(t[-100:], t[-100:].to(torch.bfloat16).float(),s1,ct[-100:],cmapplt.cm.cool)
plt.xlabel(position in float32)
plt.ylabel(position in bfloat16)Text(0, 0.5, position in bfloat16)从上图可以看出使用bfloat16和float16进行位置编码的时候容易出现位置碰撞因此位置编码需要指定float32类型
注意力机制(MHA,MQA,GQA)
MHAMulti-head Attention是多头注意力机制的标准形式其中包括h个Query、Key和Value矩阵。
MQAMulti-Query Attention是多查询注意力的一种变体专为自回归解码设计。与MHA不同MQA让所有头共享同一份Key和Value矩阵而每个头仅保留独立的Query参数。这种设计显著减少了Key和Value矩阵的参数数量提高了计算效率。
GQAGrouped-Query Attention是另一注意力机制它将查询头分为G组。每组共享一个Key和Value矩阵。GQA-G表示具有G组的GQA而GQA-1相当于一个单一组因此其Key和Value矩阵与MQA相同。相反GQA-H具有与头数相等的组等同于MHA。GQA在MHA和MQA之间提供了一个折衷方案。
总体而言MHA、MQA和GQA在处理输入数据和生成输出时采用不同的策略。MHA注重并行处理以提高表示能力MQA侧重于减少参数数量以增强计算效率而GQA则通过分组查询来平衡这两方面的需求。 GQA:Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints
FlashAttention总结
FlashAttention是解决Transformer计算速度慢和存储占用高问题的关键技术。不同于其他Efficient Transformer仅关注降低FLOPSFlashAttention将优化重心放在降低存储访问开销MAC上。
FLOPS直接决定了模型核心计算的密集程度从而影响计算速度。学术界已经研发出许多技巧来降低Transformer的FLOPS而由这些技巧改进得到的模型被称为Efficient Transformer。
然而大多数Efficient Transformer仅关注FLOPS。FlashAttention的作者们发现尽管这些Efficient Transformer能有效降低FLOPS但计算速度并未显著提升。主要原因是计算速度不仅与FLOPS有关还与MAC紧密相连。尤其在计算效率已很高的情况下MAC的重要性更加凸显。MAC的开销主要来自两个方面从存储中读取数据和向存储中写入数据。在GPU中当需要进行计算时需要从显存中读取数据并由计算单元进行处理。计算完成后再将结果写回到显存中。 FlashAttentionV1: Fast and Memory-Efficient Exact Attention with IO-Awareness FlashAttentionV2: Faster Attention with Better Parallelism and Work Partitioning Feed Forward层
Feed Forward层一般是有2层简单的前馈神经网络层组成。例如chatglm3_6b的ffn层网络定义 MoE介绍
这两天 Mistral 7B /w 8 experts 的 checkpoint 释出彻底引爆了 AI 社区对 MoE 的热情。本质来说MoE 是一种高效的 scaling 技术用较少的 compute 实现更大的模型规模从而获得更好的性能。MoE工作的主要动机保持相同训练和推理资源的同时通过增加模型的体积代价来提升模型学习效果。
Scaling laws for neural language models揭示了模型规模、数据集大小以及所需计算资源之间的紧密联系并指出在数据集容量不变的前提下最大限度地增加模型参数数量是充分利用计算力的高效策略。这里的“规模”主要指模型所包含的参数总量及其所需的计算复杂度通常情况下参数数量的增加会伴随着计算需求的增长。
而MoEMixture of Experts结构则通过引入专家机制实现了一次关键性的解耦操作它能够在保持所需计算量相对稳定的基础上显著提升模型参数的数量。因此采用MoE架构的模型性能提升符合scaling law规律即使在不额外增加计算成本的情况下也能借助更多的参数来提升模型表现。 其中代表作品为Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity
作者观点指出FFN全连接前馈神经网络在某种程度上可以类比为键值对KV对其中K表示文本中的模式信息而V则代表了这些模式的分布情况。随着网络层次的加深模型能够学习到愈发复杂的模式特征但同时也发现越靠近输出层的部分其学习能力往往显得相对不足。
基于这两个观察点可以提出这样一个假设这种学习不充分的现象可能是由于模型容量的局限性所导致的尤其是对于较深层而言对模型参数容量的需求更为显著。为了验证这一假设一个相关的实验现象是当仅使用一个MoE专家混合层时将其置于网络结构的更后位置往往可以获得更好的性能表现。
此外从直观理解上复杂模式的数量级理论上可能远超过简单模式呈现出指数增长的特性这就意味着需要更多的参数来适应和拟合这些多样且复杂的模式组合。
MoE结构介绍
Mixture of Experts (MoE) 模型是一种创新的机器学习架构它通过整合多个专业化“专家”网络以提升模型的整体效能和效率。该模型的基本理念在于将复杂的任务划分为多个细分子任务然后交由各个专门设计的专家网络即小型神经网络来分别处理这些专家网络可能包括全连接层、卷积层等多种类型。
MoE 模型的核心组件主要包括 门控机制作为 MoE 模型的关键组成部分门控机制负责根据输入数据的特征动态决定每个数据应由哪个或哪些专家网络进行处理从而优化模型的学习与预测性能。 专家网络这些是模型中实际执行数据处理的单元。每一个专家网络都经过训练专注于处理特定类型的数据或任务。在 MoE 架构中可配置任意数量的专家网络且每个专家都可以是一个独立构建的神经网络。 融合层融合层的主要职责是集成来自所有专家网络的输出结果。基于门控机制的任务分配及各专家的输出响应融合层综合生成最终的模型输出。
MoE 模型的优势体现在其高度的灵活性与扩展性上。由于能够动态调整专家网络的数量和类型MoE 能够有效应对大规模复杂数据集的挑战。此外借助并行处理不同的专家网络MoE 模型还能显著提升计算效率。在实际应用情境下MoE 模型广泛应用于对计算资源需求较大的任务如自然语言处理、图像识别以及复杂的预测问题等。通过将大型难题拆解为更小、更易管理的部分MoE 模型可以提供更为高效精准的解决方案。
相关参考文档:https://zhuanlan.zhihu.com/p/671873012
解码流程
目前主流的LLM模型都是基于tansformers的decoder网络结构。基于这类的生成式generative模型的推理过程很有特点都采用“Next Token PredictionNTP”方式。我们给一个输入文本模型会输出一个回答长度为N其实该过程中执行了N次推理过程。即GPT类模型一次推理只输出一个token输出token会与输入tokens 拼接在一起然后作为下一次推理的输入这样不断反复直到遇到终止符。其中会涉及解码方式。
解码方法
主要分为三大类;greedy search(贪心搜索), beam search, sample(采样)。
greedy search(贪心搜索);
只考虑当前词对应的最大概率忽略整体的最大概率。
beam search: 在解码过程中它始终坚持存储当前概率最高的num_beams个完整序列候选不仅限于单个词而是充分考虑了词组和短语的整体概率 这种策略尤其适用于诸如句子级机器翻译或短文本生成等任务场景 beam search在实践中存在明显的复读现象即有可能生成重复的n-gram结构尽管直接禁止重复n-gram的方法可以缓解这一问题但这种方法过于简单粗暴可能会影响整体生成效果 本质上beam search通过选取top n的高概率候选结果进行迭代扩展因此在追求高概率路径的同时生成的回复往往缺乏新颖性和意外性难以带给用户惊喜。
sample(采样解码): 可以通过温度(temperate)参赛修改让原本高概率的概率更高低概率的概率更低这样就可以尽量采样出高概率的词在随机性和surprise之间做trade-off。 注意temperate越大越随机如果temperate0就没有随机了就是贪心算法。
如果使用huggingface库的model.generate方法来预测输出内容。则有下面的几种参数配置; 如果num_beams1且do_sampleFalse则使用贪婪搜索调用~generation.GenerationMixin.greedy_search。 如果penalty_alpha0且top_k1则使用对比搜索调用~generation.GenerationMixin.contrastive_search。 如果num_beams1且do_sampleTrue则使用多概率采样调用~generation.GenerationMixin.sample。 如果num_beams1且do_sampleFalse则使用beam搜索调用~generation.GenerationMixin.beam_search。 如果num_beams1且do_sampleTrue则使用beam搜索多概率采样调用~generation.GenerationMixin.beam_sample。 如果num_beams1且num_beam_groups1则使用分群束搜索调用~generation.GenerationMixin.group_beam_search。 如果num_beams1且constraints!None或force_words_ids!None则使用约束束搜索调用~generation.GenerationMixin.constrained_beam_search。
例如用chatglm2_6b采用多概率采样的方式输出
%%time
query 现有鸡兔22只共有48只脚请问鸡比兔多了几只?
history []
gen_kwargs {max_length: 1024, num_beams: 1, do_sample: True, top_p: 0.8,temperature: 0.1, logits_processor: None}
inputs model.build_inputs(tokenizer, query, historyhistory)
print(inputs)
# {input_ids: tensor([[64790, 64792, 790, 30951, 517, 30910, 30939, 30996, 13, 13,
# 54761, 31211, 39701, 13, 13, 55437, 31211]], devicecuda:0),
# attention_mask: tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], devicecuda:0),
# position_ids: tensor([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]], devicecuda:0)}print(model.process_response(tokenizer.decode(inputs[input_ids][0])))outputs model.generate(**inputs, **gen_kwargs)
outputs outputs.tolist()[0][len(inputs[input_ids][0]):]
print(outputs)
# [64790, 64792, 790, 30951, 517, 30910, 30939, 30996, 13, 13, 54761, 31211, 39701, 13, 13, 55437,
# 31211, 36474, 54591, 243, 162, 148, 142, 31404, 33030, 34797, 42481, 22011, 10461, 30944, 30943,
# 30941, 30978, 30949, 31123, 48895, 35214, 54622, 31123, 32616, 39905, 31901, 31639, 31155, 2]response tokenizer.decode(outputs)
response model.process_response(response)
response{input_ids: tensor([[64790, 64792, 790, 30951, 517, 30910, 30939, 30996, 13, 13,54761, 31211, 34470, 55672, 56766, 30943, 30943, 54768, 31123, 33684,30972, 30973, 54768, 55673, 31123, 42693, 55672, 54703, 56766, 33851,55013, 54768, 30987, 13, 13, 55437, 31211]], devicecuda:0), attention_mask: tensor([[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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], devicecuda:0), position_ids: tensor([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,36]], devicecuda:0)}[Round 1]问现有鸡兔22只共有48只脚请问鸡比兔多了几只?答CPU times: user 6.23 s, sys: 478 ms, total: 6.71 sWall time: 6.74 s假设鸡有 x 只兔子有 22 - x 只。\n\n每只鸡有 2 只脚每只兔子有 4 只脚。因此所有鸡和兔子的脚的总数为\n\n2x 4(22 - x) 48\n\n化简得\n\n2x 88 - 4x 48\n\n-2x -40\n\nx 20\n\n因此有 20 只鸡22 - 20 2 只兔子。\n\n所以鸡比兔子多了 20 - 2 18 只。限制采样Trick总结
主要有top_ptop_k等参数 top_p:每个时间步按照字出现的概率由高到底排序当概率之和大于top-p的时候就不取后面的样本了。然后对取到的这些字的概率重新归一化后进行采样。参数top_p (取值范围0-1)。top-P采样方法往往与top-K采样方法结合使用每次选取两者中最小的采样范围进行采样可以减少预测分布过于平缓时采样到极小概率单词的几率。 top_k: 每个时间步会保留topK个字然后对topk个字的概率重新归一化最后在重新归一化后的这K个字中进行采样。缺点在分布陡峭的时候仍会采样到概率小的单词或者在分布平缓的时候只能采样到部分可用单词。 Temperature:通过温度控制每个词的概率分布曲线。温度越低分布曲线越陡峭越容易采样到概率大的字。温度越高分布曲线越平缓增加了低概率字被采样到的机会。参数temperature取值范围0-1设的越高生成文本的自由创作空间越大温度越低生成的文本越偏保守。 限制n-gram在生成结果中出现次数;
kv cache
在预测阶段Transformer模型常采用KV cache技术以提高推理效率。具体而言在Decoder进行逐词解码的过程中若每生成一个token就需将已解码的所有tokens重新拼接为输入并据此预测下一个token则会导致大量的重复计算。
为此在解码过程中Transformer利用KV cache存储先前计算得到的Key和Value这样一来在后续生成步骤中无需反复处理相同部分的输入数据从而有效提升了模型推理速度并降低了计算成本。假如现在有一个任务是要写一首诗
在解码过程中 input: 写一首诗output: 轻 input: 写一首诗轻 output: 舟 input: 写一首诗轻舟 output: 已 input: 写一首诗轻舟已 output: 过 input: 写一首诗轻舟已过 output: 万 input: 写一首诗轻舟已过万 output: 重 input: 写一首诗轻舟已过万重 output: 山
最终完整输出轻舟已过万重山
可以利用缓存的方式把之前的计算结果(“写一首诗轻舟已过万重”的K values V values缓存起来下一次解码的时候直接利用缓存的结果这样就可以大大加快解码的速度。
启用KV Cache后Transformer的推理过程可以细分为两个核心阶段 预填充阶段在生成首个输出token时由于Cache为空系统需要为每个Transformer层分别计算并初始化Key和Value缓存。这个阶段涉及大量的矩阵乘法GEMM操作其FLOPs与未使用KV Cache的情况相仿故推理速度相对较慢。 KV Cache利用阶段自第二个输出token直至最后一个token的生成过程中模型能够复用已填充好的Cache内容。此时每一轮解码仅需读取先前存储的Key和Value并将当前轮次新产生的Key、Value信息更新至Cache中。此阶段的FLOPs有所减少原本的矩阵乘法GEMM操作转换为向量-矩阵乘法GEMV从而显著提升推理效率。这一阶段计算主要受内存访问限制Memory-bound相较于预填充阶段推理速度有明显提升。
实现自定义的new_logits_processor添加违禁词
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, TextStreamer
from transformers.generation.logits_process import LogitsProcessor, LogitsProcessorList
from typing import List
import torchclass new_logits_processor(LogitsProcessor):forbid_token_id_list是不让模型生成词语的id映射列表对于这些抑制生成的词语在自定义logits_processor时将其概率推向负无穷大即可。def __init__(self, forbid_token_id_list: List[int] None):self.forbid_token_id_list forbid_token_id_listdef __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) - torch.FloatTensor:for id_ in self.forbid_token_id_list:scores[:, id_] -float(inf)return scores# model_path THUDM/chatglm2-6b
# tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue)
# model AutoModelForSeq2SeqLM.from_pretrained(model_path, trust_remote_codeTrue).to(mps)def add_forbid_words():添加需要抑制的词语这里简单添加了数字和几个词语进行对比:return:listforbid_words []for i in range(10):forbid_words.append(tokenizer.convert_tokens_to_ids(str(i)))forbid_words.append(tokenizer.convert_tokens_to_ids(首先))forbid_words.append(tokenizer.convert_tokens_to_ids(积极))forbid_words.append(tokenizer.convert_tokens_to_ids(回答))forbid_words.append(tokenizer.convert_tokens_to_ids(勇敢))forbid_words.append(tokenizer.convert_tokens_to_ids(勇气))return forbid_wordslogits_processor LogitsProcessorList()
logits_processor.append(new_logits_processor(add_forbid_words()))streamer TextStreamer(tokenizer, skip_promptTrue, skip_special_tokensTrue)%%timequery 列举出10个积极的词语outputs model.generate(tokenizer(query, return_tensorspt).input_ids.to(cuda),max_new_tokens1024,logits_processorlogits_processor, # 不开启注释即可streamerstreamer
)
decode_text tokenizer.batch_decode(outputs, streamerstreamer)[0]
print(decode_text)- 积极主动
- 乐观向上
- 自信
- 自律
- 诚实守信
- 乐于助人
- 勇于尝试
- 坚韧不拔
- 乐观开朗
- 团结一心
列举出10个积极的词语- 积极主动
- 乐观向上
- 自信
- 自律
- 诚实守信
- 乐于助人
- 勇于尝试
- 坚韧不拔
- 乐观开朗
- 团结一心
CPU times: user 1.67 s, sys: 25.5 ms, total: 1.69 s
Wall time: 1.68 s网络模型微调总结
数据格式
数据集作为驱动大模型效能提升的“三驾马车”之一与模型结构和算力资源并驾齐驱起着至关重要的决定性作用。在深度学习领域丰富的高质量数据集如同基石一般为构建强大、泛化的机器学习模型提供了必不可少的基础支撑。
一个大型的数据集不仅涉及庞大的数据规模更重要的是其内在的多样性和全面性。它涵盖了多种场景、多元特征以及广泛标注的信息能够有效帮助模型理解和学习复杂的规律及模式从而提高模型在实际应用中的准确率和鲁棒性。同时数据集的质量直接影响模型训练的效果高质量的数据集能够显著减少噪声干扰确保模型在训练过程中能更好地挖掘深层次的知识关联。
因此在大模型的研发过程中精心设计和持续优化的数据集构建策略是不可或缺的一环这包括但不限于数据采集的全面性、数据清洗的严谨性、数据增强的有效性以及针对特定任务进行的精细化标注等环节。只有当数据、模型和算力这三者达到高度协同与融合时才能最大程度地发挥出人工智能技术的强大潜力。
多轮对话的数据格式
常见的对话类型带工具调用的类型 Firefly项目训练多轮对话模型时采取了一种更加充分高效的方法。如下图所示我们将一条多轮对话数据拼接之后输入模型并行计算每个位置的loss只有Assistant部分的loss参与权重更新。 这种做法之所以可行关键在于因果语言模型中采用的attention mask机制。以GPT为代表的因果语言模型其核心特点在于其使用的注意力掩码是一个对角形式的矩阵。在该结构下每个token在编码阶段仅能访问和考虑它之前出现的所有token信息而无法获取后续token的内容。因此在处理对话序列时User1部分经过编码后的输出只能依赖于User1本身的文本内容无法预测或参考其后面出现的文本如Assistant1的回答。相应地对于User2部分其编码结果能够基于已知的User1、Assistant1以及自身的文本内容来预测Assistant2的回应以此类推。
通过这样的设计对于整个对话序列只需一次性输入模型即可利用并行计算的优势分别获得每个位置对应的logits值进而用于计算loss及优化模型参数。这样既确保了模型预测的因果一致性也大大提高了训练和推理效率。组成的对话格式如下
suser1/sAssistant1/suser2/sAssistant2/s...chatglm2_6b的数据格式
[gMASK]sop[Round1]问你好答我是chatglm2助手[Round2]问现有鸡兔22只共有48只脚请问鸡比兔多了几只?答chatglm3_6b的数据格式
[gMASK]sop|system|[gMASK]sop
[gMASK]sop你是一位高级python程序员,按照用户输入的任务转换为对应的python代码请以的格式作为开始和结尾。|user|[gMASK]sop
[gMASK]你好|assistant|微调(三步走)
在深度学习中微调是一种重要的技术即通过训练部分参数来提高模型的性能。微调可以分为全微调和部分微调两种方法
• 全微调Full Fine-tuning全微调是指对整个预训练模型进行微调包括所有的模型参数。在这种方法中预训练模型的所有层和参数都会被更新和优化以适应目标任务的需求。这种微调方法通常适用于任务和预训练模型之间存在较大差异的情况或者任务需要模型具有高度灵活性和自适应能力的情况。Full Fine-tuning需要较大的计算资源和时间但可以获得更好的性能。
• 部分微调Repurposing部分微调是指在微调过程中只更新模型的顶层或少数几层而保持预训练模型的底层参数不变。这种方法的目的是在保留预训练模型的通用知识的同时通过微调顶层来适应特定任务。Repurposing通常适用于目标任务与预训练模型之间有一定相似性的情况或者任务数据集较小的情况。由于只更新少数层Repurposing相对于Full Fine-tuning需要较少的计算资源和时间但在某些情况下性能可能会有所降低。
随着LLM模型参数量巨大往往参数量在几十亿的参数甚至更大。在消费级显卡中无法完成全量微调。PEFTParameter-Efficient Fine-Tuning是hugging face开源的一个参数高效微调大模型的工具里面集成了多种微调大模型的方法可以通过微调少量参数就达到接近微调全量参数的效果使得在GPU资源不足的情况下也可以微调大模型。
第一步:预训练微调
大模型首先会在大量的无标签数据上进行无监督的训练其中预训练的最终目的是让模型学习到语言的统计规律和基础知识。得到的预训练模型一般称为基座模型base model.例如;baichuan2_13b_base, chatglm3_6b_base
第二步: 指令监督微调(SFT)
参考论文
当前以 ChatGPT 为代表的预训练语言模型PLM规模变得越来越大在消费级硬件上进行全量微调Full Fine-Tuning变得不可行。此外为每个下游任务单独存储和部署微调模型变得非常昂贵因为微调模型与原始预训练模型的大小相同。参数高效微调方法Parameter-Efficient Fine-TuningPEFT方法被提出来解决这两个问题PEFT 可以使 PLM 高效适应各种下游应用任务而无需微调预训练模型的所有参数。微调大规模 PLM 所需的资源成本通常高得令人望而却步。在这方面PEFT 方法仅微调少量或额外的模型参数固定大部分预训练参数大大降低了计算和存储成本同时最先进的 PEFT 技术也能实现了与全量微调相当的性能。
PEFT 方法可以分为三类不同的方法对 PLM 的不同部分进行下游任务的适配 Prefix/Prompt-Tuning在模型的输入或隐层添加n个额外可训练的前缀 tokens这些前缀是连续的伪 tokens不对应真实的 tokens只训练这些前缀参数 Adapter-Tuning将较小的神经网络层或模块插入预训练模型的每一层这些新插入的神经模块称为 adapter适配器下游任务微调时也只训练这些适配器参数 LoRA通过学习小参数的低秩矩阵来近似模型权重矩阵的参数更新训练时只优化低秩矩阵参数。 下面将依次介绍几种常见的微调方法实现大模型的SFT过程。
LoRa方法介绍
lora论文
LoRA的本质是在原模型的基础上插入若干新的参数称之为adapter。在训练时冻结原始模型的参数只更新adapter的参数。对于不同的基座模型adapter的参数量一般为几百万~几千万。具体的原理如下
假设作者认为参数更新过程中存在一个内在秩对于权重可以通过低秩分解来表示参数更新即
即最终的参数量由 降至 ;假设 , 则参数量为: AdaLoRa方法介绍
AdaLoRA基于SVD的形式参数化增量更新这种基于SVD的参数化形式可以在规避SVD复杂的计算的同时高效裁剪不重要的奇异值从而降低计算量。该方法提出的作者认为在一个模型中不同模块拥有着不同的贡献那么在使用LoRA时如果我们能够根据它们重要性的不同为不同的模块分配不同的秩那么将会带来很多好处。首先我们为重要性更低的模块分配更小的秩那么将有效的减少模型的计算量。其次如果我们能够为更重要的特征分配更大的秩那么将能够更有效的捕捉特征的细节信息。这也就是AdaLoRA的提出动机。
假设
其中,为的左右奇异向量为的奇异矩阵。 QLoRa方法介绍
LoRA的本质是在原模型的基础上插入若干新的参数称之为adapter。在训练时冻结原始模型的参数只更新adapter的参数。对于不同的基座模型adapter的参数量一般为几百万~几千万。LoRA存在的问题: 参与训练的参数量较少解空间较小效果相比全量微调有一定的差距。 微调大模型成本高对于上百亿参数量的模型LoRA微调的成本还是很高。精度损失。
QLoRa相当于Quantization量化LoRa(AdaLoRa)技术具有下面的特点; 4-bit NormalFloat提出一种理论最优的4-bit的量化数据类型优于当前普遍使用的FP4与Int4。 Double Quantization相比于当前的模型量化方法更加节省显存空间。每个参数平均节省0.37bit对于65B的LLaMA模型大约能节省3GB显存空间。Paged Optimizers使用NVIDIA统一内存来避免在处理小批量的长序列时出现的梯度检查点内存峰值。 增加Adapter4-bit的NormalFloat与Double Quantization节省了很多空间但带来了性能损失作者通过插入更多adapter来弥补这种性能损失。在LoRA中一般会选择在query和value的全连接层处插入adapter。 而QLoRA则在所有全连接层处都插入了adapter增加了训练参数弥补精度带来的性能损失。
QLoRA(int8adalora) QLoRa(4bitsAdalora) P-tuningV2方法介绍
P-Tuning v2: Prompt Tuning Can Be Comparable to Finetuning Universally Across Scales and TasksP-tuning v2被设计用于生成和知识探索但最重要的改进之一是将连续提示应用于预训练模型的每个层而不仅仅是输入层。 第三步: 基于RLHF的微调(DPO,PPO)
奖励模型(reward model)
奖励模型 (RM) 微调类似于第一阶段有监督微调 (SFT) 。但是RM 和 SFT 微调之间存在几个关键差异 训练数据差异对于 SFT 微调数据是查询query和答案answer拼接在一起。然而对于 RM 微调每批数据由两个查询-答案对组成即具有高分答案和低分答案的相同查询。这也导致了如下所述的第二个差异。 训练目标差异对于 RW训练目标是 pairwise ranking score即对于两个查询-答案对RM 应该给更好的答案更高的分数。有多种方法可以实现这一目标。在DeepSpeed Chat的实现中使用序列的结束标记或第一个填充标记作为聚合分数并比较它们。当然也可以使用整个答案的平均分数作为替代。
reward模型本质就是一个句子级的分类难点在于如何收集偏好数据具体需要样本高质量足够多:尽可能覆盖各种场景例如不同长度避免在RL阶段出现OOD。 PPO算法介绍
LLM模型微调通常有三个步骤如下图DeepSpeedChat流程 分别为actor model、reference model、critic model、reward modelreward model是为了避免critic model的value变化太大。其中actor model和reference model是同一个模型来源于sft操作。critic model和reward model来源于rw模型训练。
DPO算法介绍 斯坦福大学研究团队Direct Preference Optimization提出了一项名为Direct Preference OptimizationDPO的创新算法旨在探寻更简洁高效的大规模语言模型优化解决方案。与传统的强化学习方法不同DPO能够直接对语言模型行为进行精准调控无需复杂的强化学习过程。该算法巧妙地建立了奖励函数与最优策略之间的内在联系将原本复杂的约束奖励最大化问题简化为一次性策略训练任务。
DPO的独特之处在于其不仅省去了对奖励模型的拟合步骤还在微调过程中免除了从语言模型中采样或精细调整关键超参数的需求。实验结果显示DPO在诸如情感调节、文本摘要和单轮对话等任务上表现出了与现有RLHF方法相当甚至更好的性能成功实现了从人类偏好中有效学习。
作为一种隐式优化策略DPO与当前RLHF方法共享相同的目标导向但具备更高的实现便捷性和训练友好性。针对单纯基于相对概率可能导致模型性能下降的问题DPO引入了动态权重机制来体现每个示例回复的重要性。尽管同样依赖于理论上的偏好模型以评估奖励函数与实际偏好数据的一致性但DPO独树一帜地通过变量变换将偏好损失直接定义为策略函数的一部分。因此DPO能依据给定的偏好数据和模型生成的回复仅利用简单的二进制交叉熵作为目标函数来进行策略优化。
相较于现有的基于人类反馈的方法DPO在大语言模型微调时更加高效且直接。传统方法通常需要先拟合一个奖励模型到包含提示和人类偏好的数据集上再运用对比学习找到最大化所学奖励的策略。而DPO则摒弃了这一复杂流程仅通过直观的分类目标即可直接针对最符合人类偏好的策略进行优化无需明确指定奖励函数或应用强化学习技术。 实战教程
最后给大家介绍2个关于大模型应用的案例分别是推理优化和注入新知识到大模型中。
chatglm2_6b分层加载权重推理(使用3G显存实现推理)
chatglm2_6b按照半精度加载到GPU中大约会占12G左右。通过使用分层加载推理技术(重构chaglm2_6b模型的层权重加载架构使用逐层加载推理释放来实现这一过程)只需要3g左右的内存既可实现6b模型按照半精度类型加载推理。 few_shot examples进行SFT微调
给大模型新增知识通过构造简单的几条样本注入大模型中。下面将展示微调前后的效果对比;
案例1展示; 案例2展示;
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/915402.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!