用通俗易懂的方式讲解:万字长文带你入门大模型
告别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和x2,pos的位置从0开始逐步变大,依次计算x1和x2之间的内积。我们发现随着x1和x2的相对距离的增加,它们之间的内积分数震荡衰减。
!pip install -q mplfonts
!pip install -q mpl-font
!mplfonts init
from 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, base=10000):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, dtype=torch.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], dim=2)return torch.flatten(stacked, start_dim=1, end_dim=2)
seq_len = 80
d_model = 128
spe = SinPositionEncoding(max_sequence_length=seq_len, d_model=d_model)()
print(spe.shape)fig,ax =plt.subplots(1,1,figsize=(6,10),dpi=120)
im1= ax.imshow(spe,vmin=spe.min(), vmax=spe.max(),cmap=plt.cm.rainbow)
# add space for colour bar
fig.subplots_adjust(right=0.85)
cbar_ax = fig.add_axes([0.86, 0.35, 0.04, 0.28])
plt.colorbar(im1, cax=cbar_ax)
plt.show()
plt.close(fig)
torch.Size([80, 128])

fig,axes =plt.subplots(1,2,figsize=(15,6),dpi=120)
out = torch.matmul(spe,spe.T)
print(out.shape)
# 不同位置的位置编码点积可视化。
im1 = axes[0].imshow(out ,vmin=out.min(), vmax=out.max(),cmap=plt.cm.cool)
fig.subplots_adjust(right=0.85)
cbar_ax = fig.add_axes([0.45, 0.30, 0.02, 0.5])
fig.colorbar(im1, cax=cbar_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_length=seq_len, d_model=dim)()k_list = [-index for index in range(1, base)][::-1] + [index for index in range(base)]value = [torch.matmul(spe[base-k],spe[base+k].T ).tolist() for k in k_list]axes[1].plot(k_list, value, label='dim_%d'%dim,color=color_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, d=128):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 m@torch.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.shape
input 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,dtype=torch.bfloat16)
b = a + 1
c = a + 2
d = a + 3
e = a + 4
a,b,c,d,e
(tensor(255., dtype=torch.bfloat16),tensor(256., dtype=torch.bfloat16),tensor(256., dtype=torch.bfloat16),tensor(258., dtype=torch.bfloat16),tensor(260., dtype=torch.bfloat16))
# self.inv_freq.dtype == torch.bfloat16 when bfloat16 is enabled during training
t = torch.arange(4096, dtype=torch.float32)
plt.scatter(t[-100:], t[-100:].to(torch.bfloat16).float(),s=1,c=t[-100:],cmap=plt.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)
MHA(Multi-head Attention)是多头注意力机制的标准形式,其中包括h个Query、Key和Value矩阵。
MQA(Multi-Query Attention)是多查询注意力的一种变体,专为自回归解码设计。与MHA不同,MQA让所有头共享同一份Key和Value矩阵,而每个头仅保留独立的Query参数。这种设计显著减少了Key和Value矩阵的参数数量,提高了计算效率。
GQA(Grouped-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仅关注降低FLOPS,FlashAttention将优化重心放在降低存储访问开销(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揭示了模型规模、数据集大小以及所需计算资源之间的紧密联系,并指出在数据集容量不变的前提下,最大限度地增加模型参数数量是充分利用计算力的高效策略。这里的“规模”主要指模型所包含的参数总量及其所需的计算复杂度,通常情况下,参数数量的增加会伴随着计算需求的增长。
而MoE(Mixture 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 Prediction,NTP”方式。我们给一个输入文本,模型会输出一个回答(长度为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越大越随机,如果temperate=0,就没有随机了,就是贪心算法。
如果使用huggingface库的model.generate方法来预测输出内容。则有下面的几种参数配置;
-
如果num_beams=1且do_sample=False,则使用贪婪搜索,调用~generation.GenerationMixin.greedy_search。
-
如果penalty_alpha>0且top_k>1,则使用对比搜索,调用~generation.GenerationMixin.contrastive_search。
-
如果num_beams=1且do_sample=True,则使用多概率采样,调用~generation.GenerationMixin.sample。
-
如果num_beams>1且do_sample=False,则使用beam搜索,调用~generation.GenerationMixin.beam_search。
-
如果num_beams>1且do_sample=True,则使用beam搜索多概率采样,调用~generation.GenerationMixin.beam_sample。
-
如果num_beams>1且num_beam_groups>1,则使用分群束搜索,调用~generation.GenerationMixin.group_beam_search。
-
如果num_beams>1且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, history=history)
print(inputs)
# {'input_ids': tensor([[64790, 64792, 790, 30951, 517, 30910, 30939, 30996, 13, 13,
# 54761, 31211, 39701, 13, 13, 55437, 31211]], device='cuda:0'),
# 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], device='cuda:0'),
# 'position_ids': tensor([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]], device='cuda: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]], device='cuda: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]], device='cuda: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]], device='cuda: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_p&&top_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_code=True)
# model = AutoModelForSeq2SeqLM.from_pretrained(model_path, trust_remote_code=True).to('mps')def add_forbid_words():'''添加需要抑制的词语,这里简单添加了数字和几个词语进行对比:return:list'''forbid_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_prompt=True, skip_special_tokens=True)
%%timequery = "列举出10个积极的词语:"outputs = model.generate(tokenizer(query, return_tensors='pt').input_ids.to("cuda"),max_new_tokens=1024,logits_processor=logits_processor, # 不开启注释即可streamer=streamer
)
decode_text = tokenizer.batch_decode(outputs, streamer=streamer)[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及优化模型参数。这样既确保了模型预测的因果一致性,也大大提高了训练和推理效率。组成的对话格式如下
<s>user1</s>Assistant1</s>user2</s>Assistant2</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模型参数量巨大,往往参数量在几十亿的参数,甚至更大。在消费级显卡中无法完成全量微调。PEFT(Parameter-Efficient Fine-Tuning)是hugging face开源的一个参数高效微调大模型的工具,里面集成了多种微调大模型的方法,可以通过微调少量参数就达到接近微调全量参数的效果,使得在GPU资源不足的情况下也可以微调大模型。
第一步:预训练微调
大模型首先会在大量的无标签数据上进行无监督的训练,其中预训练的最终目的是让模型学习到语言的统计规律和基础知识。得到的预训练模型一般称为基座模型base model.例如;baichuan2_13b_base, chatglm3_6b_base
第二步: 指令监督微调(SFT)
- 参考论文
当前以 ChatGPT 为代表的预训练语言模型(PLM)规模变得越来越大,在消费级硬件上进行全量微调(Full Fine-Tuning)变得不可行。此外,为每个下游任务单独存储和部署微调模型变得非常昂贵,因为微调模型与原始预训练模型的大小相同。参数高效微调方法(Parameter-Efficient Fine-Tuning,PEFT)方法被提出来解决这两个问题,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统一内存来避免在处理小批量的长序列时出现的梯度检查点内存峰值。
-
增加Adapter:4-bit的NormalFloat与Double Quantization,节省了很多空间,但带来了性能损失,作者通过插入更多adapter来弥补这种性能损失。在LoRA中,一般会选择在query和value的全连接层处插入adapter。
-
而QLoRA则在所有全连接层处都插入了adapter,增加了训练参数,弥补精度带来的性能损失。
QLoRA(int8+adalora)



QLoRa(4bits+Adalora)



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 model(reward model是为了避免critic model的value变化太大)。其中actor model和reference model是同一个模型,来源于sft操作。critic model和reward model来源于rw模型训练。
DPO算法介绍

斯坦福大学研究团队Direct Preference Optimization提出了一项名为Direct Preference Optimization(DPO)的创新算法,旨在探寻更简洁高效的大规模语言模型优化解决方案。与传统的强化学习方法不同,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展示;

相关文章:
用通俗易懂的方式讲解:万字长文带你入门大模型
告别2023,迎接2024。大模型技术已成为业界关注焦点,你是否也渴望掌握这一领域却又不知从何学起? 本篇文章将特别针对入门新手,以浅显易懂的方式梳理大模型的发展历程、核心网络结构以及数据微调等关键技术。 如果你在阅读中收获…...
Invalid options in vue.config.js: “plugins“ is not allowed
项目场景: 安装并配置elementPlus报错。 问题描述 "plugins" is not allowed. plugins不被允许。参考官网修改配置文件vue.config.js。 解决方案: const AutoImport require(unplugin-auto-import/webpack) const Components require(un…...
四、C语言中的数组:数组的创建与初始化
其实在之前的学习中我们已经或多或少接触到了数组,有关scanf()的安全用法中我们提到了如何避免数组溢出的问题,详情可以查看二、C语言数据类型与变量(scanf和printf (4)完) 这一章我们将详细学习数组在C语言中的应用 1.数组的概…...
html5中各标签的语法格式总结以及属性值说明
有关闭标签的元素 a元素 <a href"" target"" title""></a>表格相关元素 table元素:表格标签caption元素:表头thead元素tbody元素:表格主体元素tfoot元素th元素tr元素:行标签td元素&…...
力扣(leetcode)第412题Fizz Buzz(Python)
412.Fizz Buzz 题目链接:412.Fizz Buzz 给你一个整数 n ,找出从 1 到 n 各个整数的 Fizz Buzz 表示,并用字符串数组 answer(下标从 1 开始)返回结果,其中: answer[i] “FizzBuzz” 如果 i 同…...
苦学golang半年,写了一款web服务器
苦学golang半年,写了一款web服务器 文章目录 苦学golang半年,写了一款web服务器example 项目地址:https://github.com/fengyuan-liang/jet-web-fasthttp 可以的话,请star支持一下🙂 苦学golang半年,写了一款…...
uniapp vue2 车牌号输入组件记录
uniapp vue2 车牌号输入案例记录 组件如图 直接上代码 1.html <template><view><view class"plate" :class"{show: show}"><view class"itemFirst flex-d"><view class"item item1" click"handl…...
Unity 点击对话系统(含Demo)
点击对话系统 可实现点击物体后自动移动到物体附近,然后弹出对话框进行对话。 基于Unity 简单角色对话UI脚本的编写(新版UI组件)和Unity 关于点击不同物品移动并触发不同事件的结合体,有兴趣可以看一下之前文章。 下边代码为U…...
vue接入高德地图
使用 JSAPI 安全模式,代理服务请以_AMapService 作为一级路由 index.html <script type"text/javascript">window._AMapSecurityConfig {serviceHost: "http://xx.xx.xx.xx:8223/_AMapService"};</script><script type"text/javascr…...
Linux的基本指令(5)
目录 bc指令 uname指令 压缩解压相关的指令 zip指令 unzip指令 tar打包压缩指令 tar解压解包指令 传输指令sz&rz 热键 关机命令 安装:yum install -y 指令 bc指令 bc命令可以很方便的进行浮点运算 Linux中的计算器 uname指令 语法:unam…...
华为商城秒杀时加密验证 device_data 的算法研究
前言 之前华为商城放出 Mate60 手机时, 想给自己和家人抢购一两台,手动刷了好几天无果后,决定尝试编写程序,直接发送 POST 请求来抢。通过抓包和简单重放发送后,始终不成功。仔细研究,发现 Cookie 中有一个名为 devic…...
Wrk压测发送Post请求的正确姿势
一、Wrk简介 wrk 是一个能够在单个多核 CPU 上产生显著负载的现代 HTTP 基准测试工具。它采用了多线程设计,并使用了像 epoll 和 kqueue 这样的可扩展事件通知机制。此外,用户可以指定 LuaJIT 脚本来完成 HTTP 请求生成、响应处理和自定义报告等功能。 …...
【管理篇 / 登录】❀ 06. macOS下使用USB配置线登录 ❀ FortiGate 防火墙
【简介】飞塔防火墙上都会配有CONSOLE接口,包装里都会配置一根USB配置线,通过这个接口和这根线,我们可以用命令的方式登录飞塔防火墙。随着苹果电脑的普及,我们来学习如何在macOS中使用USB配置线登录飞塔防火墙。 早期飞塔防火墙包…...
linux系统shell语言的自动化交互
自动化交互 自动化交互expect交互expect用法 sshpass概念shhpass的脚本批量拷贝文件批量传递秘钥批量修改密码 自动化交互 expect交互 yum -y install expect tcl tcl-devel //安装expect交互工具expect用法 用法: 1)#!/usr/bin/expect //定义脚本执行的shell 2)set …...
HarmonyOS ArkTS 三方库的基本使用(十六)
如何获取三方库 目前提供了两种途径获取开源三方库: 1、通过访问Gitee网站开源社区获取 在Gitee中,搜索OpenHarmony-TPC仓库,在tpc_resource中对三方库进行了资源汇总,可以供开发者参考。 2、通过OpenHarmony三方库中心仓获取 …...
Spring boot封装rocket mq 教程
1、rocket mq版本 5.1.3 2、pom引入rocket mq依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client-java</artifactId><version>5.0.4</version></dependency> 3、发送MQ消息工具类 impor…...
Java Swing手搓童年坦克大战游戏(I)
前言 业余偶尔对游戏有些兴趣,不过这样的时代,硬件软件飞速进步,2D游戏画面都无比精美,之前的8bit像素游戏时代早就过去了,不过那时候有许多让人印象深刻的游戏比如魂斗罗、超级玛丽、坦克大战(Battle City)等等。 学…...
【DevOps-04]】Operate阶段工具
一、简要说明 安装Docker安装Docker-compose二、安装Docker 官网地址:https://www.docker.com文档地址:Docker Docs仓库地址:https://hub.docker.com1、Docker相关网站 官方网站Get Docker | Docker Docs...
力扣2807.在链表中插入最大公约数
思路:遍历链表,对于每一个结点求出它与下一个结点的最大公约数并插入到俩个结点之间 代码: /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}…...
开始刷Leetcode之前你需要知道的 - The basic is all you need
数据结构:列表,哈希表,集合,栈,堆,链表,二叉树,图 入门算法:递归,排序算法,二分法,bfs,dfs list/array 列表常见操作&am…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...
视觉slam--框架
视觉里程计的框架 传感器 VO--front end VO的缺点 后端--back end 后端对什么数据进行优化 利用什么数据进行优化的 后端是怎么进行优化的 回环检测 建图 建图是指构建地图的过程。 构建的地图是点云地图还是什么信息的地图? 建图并没有一个固定的形式和算法…...
