想要更好地理解大模型架构?从计算参数量快速入手

要理解一种新的机器学习架构(以及其他任何新技术),最有效的方法就是从头开始实现它。 虽然这可能会非常复杂、耗时,并且有时几乎不可能实现,但这是帮助我们理解每个技术细节的最佳方法。例如,如果没有类似的计算资源或数据,我们将无法确保我们的解决方案中没有未被发现的错误。

然而,还有一种更简单的方法——计算参数数量。 这比仅仅阅读论文要困难得多,但可以让我们深入挖掘并检查是否完全理解了新架构的构件(在本文的例子是Transformer的编码器(Encoder)和解码器(Decoder)构件)。

我们可以通过下面这幅图表来思考这个问题,这张图表展示了三种理解新ML架构的方法——圆圈的大小表示对该架构的理解程度。

图片

本文主要研究著名的Transformer架构,并考虑如何计算PyTorch TransformerEncoderLayer[1]和TransformerDecoderLayer[2]类中的参数数量。因此,我们需要确保对于该架构由哪些部分组成不再充满神秘感。

TLDR(总结)

(该文篇幅比较长,如果不想深入探讨或时间有限,可以直接看总结部分)

您可以阅读“结论 Conclusions”部分,所有参数量计算公式都总结在“结论 Conclusions”部分。

本文不仅提供精确的参数量计算公式,还能够提供不太准确的公式近似版本,将使您能够快速估算基于Transformer的任何模型中参数的数量。

01 Transformer架构

著名的Transformer架构于2017年在《Attention Is All You Need[3]》这篇论文中提出,并因其具有能够有效捕捉长距离的依赖关系(long-range dependencies)的能力而成为自然语言处理和计算机视觉任务中的标准架构。

早在2023年初,扩散模型(Diffusion)[4]由于文转图生成模型[5]的大火而变得极其流行。也许,很快扩散模型将成为各种任务的最先进技术,就像Transformer与LSTM和CNN一样。但我们先来看看Transformer……

本文并不试图去解释Transformer架构,因为已经有很多足够好的文章做到了这一点。这篇文章只是让我们能够从不同的角度去看待它,或者讲解一些细节问题。所以如果你正在寻找更多有关此架构的学习资源,我可以向你推荐一些;否则,您可以继续阅读下去。

1.1 了解更多Transformer的资源

如果你正在寻找更加详细的Transformer架构概述,可以阅读以下材料(请注意,互联网上有很多技术内容,我只是个人喜欢这些):

  • 首先,可以阅读官方论文[3]。第一次接触Transformer就阅读论文可能不是最佳方式,但这并不像看起来那么复杂。可以尝试使用Explainpaper来帮助您阅读此论文[6]或其他论文(这是一种基于AI的工具,可以解释用鼠标标记的文本)。
  • Jay Alammar的“Great Illustrated Transformer[7]”。如果您不喜欢阅读文章,可以观看同一作者的YouTube视频[8]。
  • Lukasz Kaiser在Google Brain的 “Awesome Tensor2Tensor” 讲座[9]。
  • 如果想直接进行实操并使用各种Transformer模型构建应用程序,请查看Hugging Face课程[10]。

1.2 Original Transformer

首先,让我们回顾一下Transformer的基础知识。

Transformer的架构由两个组件组成:编码器(在左边)和解码器(在右边)。编码器接受输入token序列并生成隐藏状态序列(sequence of hidden states),而解码器则接受这个隐藏状态序列并生成输出token序列。

图片

Transformer 架构图,来自arxiv.org/pdf/1706.03…

编码器和解码器都由一堆相同的层组成。对于编码器,该层包括多头注意力(multi-head attention)(1——此处及下文中的数字指的是下面的图片中标序号的部分)和一个带有一些层归一化(3)和跳跃连接(skip connections)的前馈神经网络(feed-forward neural network)(2)。

解码器也类似于编码器,但除了第一个多头注意力(4)(在机器翻译任务中被屏蔽,所以解码器不会通过查看未来的tokens进行舞弊)和一个前缀网络(5)之外,它还具有第二个多头注意力机制(6)。它允许解码器在生成输出时使用编码器提供的上下文(context)。与编码器一样,解码器也有一些层归一化(layer normalization)(7)和跳跃连接组件

图片

带有序号标记组件的Transformer架构图

来自arxiv.org/pdf/1706.03…

我不会将输入嵌入层(带有位置编码)和最终输出层(linear+softmax)视为Transformer组件,而只关注编码器和解码器块。这样做是因为这些组件是适用于某些特定任务和嵌入方法的,而编码器和解码器栈是其他体系结构的基础。

这种架构的例子包括用于编码器的基于BERT的模型(BERT、RoBERTa、ALBERT、DeBERTa等),用于解码器的基于GPT的模型(GPT、GPT-2、GPT-3、ChatGPT),以及构建在完整的编码器-解码器框架上的模型(T5、BART等)。

尽管我们在该架构中标记了七个组件,但我们可以看到,其中仅有三个独特的组件:

  • 多头注意力(Multi-head attention);
  • 前馈网络(Feed-forward network);
  • 层的归一化(Layer normalization)。

图片

Transformer构件 来自论文arxiv.org/pdf/1706.03…

02 Transformer构件块

让我们考虑一下每个模块的内部结构以及它需要多少参数。在本节中,我们还将开始使用PyTorch[11]来验证我们的计算结果。

为了检查某个模型块的参数数量,我将使用以下这行函数[12]:

python
复制代码
import torch

# https://discuss.pytorch.org/t/how-do-i-check-the-number-of-parameters-of-a-model/4325/9
def count_parameters(model: torch.nn.Module) -> int:
 """ Returns the number of learnable parameters for a PyTorch model """
 return sum(p.numel() for p in model.parameters() if p.requires_grad)

在我们开始之前,请注意一个事实,即所有构件块都是标准化的,并且使用跳跃连接这意味着所有输入和输出的shape(更确切地说,是其最后一个数字 因为batch size和tokens数量可能会有所不同)必须相同 对于原论文,这个数字(d_model)为512。

2.1 多头注意力

著名的注意力机制是Transformer架构的关键。但是,无论设计动机和技术细节如何,它只涉及几个矩阵乘法。

图片

Transformer多头注意力架构图

来自论文arxiv.org/pdf/1706.03…

计算了每个head的注意力后,我们将所有head连接起来,并通过一个线性层(W_O矩阵)进行传递。反过来,每个head都是用三个独立的矩阵乘以query、key 和 value(分别为W_Q、W_K和W_V矩阵)的Scaled dot-product attention(缩放点积注意力)。这三个矩阵对每个head都是不同的,这就是下标i出现的原因。

最终线性层(final linear layer)(W_O)的shape为d_model到d_model。其余三个矩阵(W_Q、W_K和W_V)的shape相同:d_model到d_qkv。

请注意,在上面的图像中,d_qkv被表示为原论文中的d_k或d_v。我认为这个名称更直观,因为尽管这些矩阵可能具有不同的shape,但几乎总是相同的。

此外,请注意,d_qkv = d_model / num_heads (文中的h)。这就是为什么d_model必须能够被num_heads整除的原因:以确保后面的连接正确。

可以通过检查上图中的所有中间阶段的shape(正确的shape在右下角标出)来自行测试。

因此,我们需要每个head有三个较小的矩阵和一个大的最终矩阵。那么我们需要多少参数(不要忽略偏差)?

图片

用于计算Transformer注意力模块中参数数量的公式。图片由作者提供

我希望这个公式不会太繁琐——我试图让推导的结果尽可能的清晰。不要担心! 未来的公式会更加简短。

参数的大致数量是这样的,因为与4 * d_model相比,我们可以忽略4 * d_model^2。让我们现在用PyTorch进行测试。

python
复制代码
from torch import nn

d_model = 512
n_heads = 8 # must be a divisor of `d_model`

multi_head_attention = nn.MultiheadAttention(embed_dim=d_model, num_heads=n_heads)
print(count_parameters(multi_head_attention)) # 1050624
print(4 * (d_model * d_model + d_model)) # 1050624

数字匹配,这意味着我们做得很好!

2.2 前馈网络

Transformer中的前馈网络由两个全连接层(fully connected layers)组成,其中间有一个ReLU激活函数。该网络的内部部分比输入和输出(input and output)更具表现力(输入和输出必须相同)。

在一般情况下,它是MLP(d_model, d_ff) -> ReLU -> MLP(d_ff, d_model),对于原始论文,d_ff = 2048

图片

前馈神经网络描述 图来自论文arxiv.org/pdf/1706.03…

稍微进行一下可视化不会有坏处。

图片

Transformer中的前馈网络。作者提供的图像。

参数的计算相当容易,主要的还是不要被弄混。

图片

用于计算Transformer前馈网络中参数数量的公式。图像由作者提供。

我们可以使用以下代码描述这样一个简单的网络并检查其参数的数量(请注意,官方的PyTorch实现也使用了dropout,我们将在后面的编码器/解码器代码中看到。但是正如我们所知,dropout层没有可训练的参数,因此为了简单起见,我在这里省略它):

python
复制代码
from torch import nn

class TransformerFeedForward(nn.Module):
 def __init__(self, d_model, d_ff):
 super(TransformerFeedForward, self).__init__()
        self.d_model = d_model
        self.d_ff = d_ff

        self.linear1 = nn.Linear(self.d_model, self.d_ff)
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(self.d_ff, self.d_model)

 def forward(self, x):
        x = self.linear1(x)
        x = self.relu(x)
        x = self.linear2(x)
 return x

d_model = 512
d_ff = 2048

feed_forward = TransformerFeedForward(d_model, d_ff)
print(count_parameters(feed_forward)) # 2099712
print(2 * d_model * d_ff + d_model + d_ff) # 2099712

再次看看图中的数字,仅剩下一个组件没有介绍啦。

2.3 层归一化

Transformer架构的最后一个构件块是层归一化。简单地说,只是一种智能的(即可学习的)归一化方式,具有缩放功能,可以提高训练过程的稳定性。

图片

Transformer的层归一化,图片由作者提供

这里的可训练参数是两个向量gamma和beta,每个向量的维度都是d_model。

图片

用于计算Transformer层归一化模块中参数数量的公式。作者提供的图像。

让我们使用代码来检验我们的假设。

python
复制代码
from torch import nn

d_model = 512

layer_normalization = nn.LayerNorm(d_model)
print(count_parameters(layer_normalization)) # 1024
print(d_model * 2) # 1024

很好! 在近似计算中,这个数字可以忽略不计,因为层归一化的参数大大少于前馈网络或多头注意力块(尽管这个模块出现了几次)。

03 推导出完整的公式

现在我们有了一切,可以计算整个编码器/解码器模块的参数了!

3.1 用PyTorch实现的编码器和解码器

请让我们记住,编码器是由一个注意力块、前馈网络和两个层归一化组成。

图片

Transformer编码器。来源于论文arxiv.org/pdf/1706.03…

我们可以查看PyTorch代码中的细节来验证所有组件是否都已就位。其中多头注意力机制用红色标注(左侧),前馈网络用蓝色标注层归一化用绿色标注(在PyCharm中的Python控制台截图)。

图片

PyTorch TransformerEncoderLayer。图片由作者提供

3.2 最终公式

确认好之后,我们可以编写以下函数来计算参数数量。实际上,这只是三行代码,甚至可以合并为一行。函数的其余部分是文档字符串以作说明。

python
复制代码
def transformer_count_params(d_model=512, d_ff=2048, encoder=True, approx=False):
 """
    Calculate the number of parameters in Transformer Encoder/Decoder.
    Formulas are the following:
        multi-head attention: 4*(d_model^2 + d_model)
            if approx=False, 4*d_model^2 otherwise
        feed-forward: 2*d_model*d_ff + d_model + d_ff 
            if approx=False, 2*d_model*d_ff otherwise
        layer normalization: 2*d_model if approx=False, 0 otherwise
    Encoder block consists of: 
        1 multi-head attention block, 
        1 feed-forward net, and 
        2 layer normalizations.
    Decoder block consists of: 
        2 multi-head attention blocks, 
        1 feed-forward net, and 
        3 layer normalizations.
    :param d_model: (int) model dimensionality
    :param d_ff: (int) internal dimensionality of a feed-forward neural network
    :param encoder: (bool) if True, return the number of parameters of the Encoder, 
        otherwise the Decoder
    :param approx: (bool) if True, result is approximate (see formulas)
    :return: (int) number of learnable parameters in Transformer Encoder/Decoder
    """

    attention = 4 * (d_model ** 2 + d_model) if not approx else 4 * d_model ** 2
    feed_forward = 2 * d_model * d_ff + d_model + d_ff if not approx else 2 * d_model * d_ff
    layer_norm = 2 * d_model if not approx else 0

 return attention + feed_forward + 2 * layer_norm \
 if encoder else 2 * attention + feed_forward + 3 * layer_norm

现在是测试它的时候了。

python
复制代码
from torch import nn

encoder_layer = nn.TransformerEncoderLayer(d_model=512, nhead=8)
print(count_parameters(encoder_layer))  # 3152384
print(transformer_count_params(d_model=512, d_ff=2048, encoder=True, approx=False))  # 3152384
print(transformer_count_params(d_model=512, d_ff=2048, encoder=True, approx=True))   # 3145728
# ~0.21% difference

decoder_layer = nn.TransformerDecoderLayer(d_model=512, nhead=8)
print(count_parameters(decoder_layer))  # 4204032
print(transformer_count_params(d_model=512, d_ff=2048, encoder=False, approx=False))  # 4204032
print(transformer_count_params(d_model=512, d_ff=2048, encoder=False, approx=True))   # 4194304
# ~0.23% difference

准确的公式是正确的,这意味着我们已经正确地确定了所有构件块并将其分解成其各组成部分。有趣的是,由于我们在近似公式中忽略了相对较小的值(与百万相比只有数千个),因此相对于精确结果,误差仅约为0.2%!但是还有一种方法可以使这些公式更简单。

注意力块的近似参数数量为4 * d_model^2。考虑到d_model是一个重要的超参数,这听起来计算会十分简单。但是对于前馈网络,我们需要知道d_ff,因为公式是2 * d_model * d_ff。

d_ff是一个单独的超参数,现在必须在公式中记住它,因此让我们思考如何摆脱它。正如我们上面看到的,当d_model = 512时,d_ff = 2048,因此d_ff = 4 * d_model。

对于许多Transformer模型来说,这样的假设将是有意义的,大大简化了公式,并仍然给出一个大概的参数数量。毕竟,没有人想知道确切的数量,只是了解这个数量是几十万还是几千万。

图片

近似的编码器-解码器公式。由作者提供的图像。

为了了解你正在处理的数量级,你也可以将乘数四舍五入。这样每个编码器/解码器层就会得到10 * d_model ^ 2个参数。

04 Conclusion 结论

下面给我们今天推导出的所有公式做一个总结。

图片

公式总结,由作者提供的图像。

在本文计算了Transformer编码器/解码器块中的参数数量,但是当然,我们并不建议您去计算所有新模型的参数。之所以选择这种方法,是因为当我开始研究Transformers时,我很惊讶没有找到这样的文章。

虽然参数数量可以让我们知道模型的复杂性和训练所需数据量,但这只是更深入地了解模型架构的一种方式。我想鼓励您探索和实验:去查看、实现、运行具有不同超参数的代码等等。因此,请继续学习并enjoy人工智能的乐趣!

如何系统的去学习大模型LLM ?

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的 AI大模型资料 包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来

😝有需要的小伙伴,可以V扫描下方二维码免费领取🆓

在这里插入图片描述

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

img

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

img

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。

img

在这里插入图片描述

四、AI大模型商业化落地方案

img

阶段1:AI大模型时代的基础理解

  • 目标:了解AI大模型的基本概念、发展历程和核心原理。
  • 内容
    • L1.1 人工智能简述与大模型起源
    • L1.2 大模型与通用人工智能
    • L1.3 GPT模型的发展历程
    • L1.4 模型工程
      - L1.4.1 知识大模型
      - L1.4.2 生产大模型
      - L1.4.3 模型工程方法论
      - L1.4.4 模型工程实践
    • L1.5 GPT应用案例

阶段2:AI大模型API应用开发工程

  • 目标:掌握AI大模型API的使用和开发,以及相关的编程技能。
  • 内容
    • L2.1 API接口
      - L2.1.1 OpenAI API接口
      - L2.1.2 Python接口接入
      - L2.1.3 BOT工具类框架
      - L2.1.4 代码示例
    • L2.2 Prompt框架
      - L2.2.1 什么是Prompt
      - L2.2.2 Prompt框架应用现状
      - L2.2.3 基于GPTAS的Prompt框架
      - L2.2.4 Prompt框架与Thought
      - L2.2.5 Prompt框架与提示词
    • L2.3 流水线工程
      - L2.3.1 流水线工程的概念
      - L2.3.2 流水线工程的优点
      - L2.3.3 流水线工程的应用
    • L2.4 总结与展望

阶段3:AI大模型应用架构实践

  • 目标:深入理解AI大模型的应用架构,并能够进行私有化部署。
  • 内容
    • L3.1 Agent模型框架
      - L3.1.1 Agent模型框架的设计理念
      - L3.1.2 Agent模型框架的核心组件
      - L3.1.3 Agent模型框架的实现细节
    • L3.2 MetaGPT
      - L3.2.1 MetaGPT的基本概念
      - L3.2.2 MetaGPT的工作原理
      - L3.2.3 MetaGPT的应用场景
    • L3.3 ChatGLM
      - L3.3.1 ChatGLM的特点
      - L3.3.2 ChatGLM的开发环境
      - L3.3.3 ChatGLM的使用示例
    • L3.4 LLAMA
      - L3.4.1 LLAMA的特点
      - L3.4.2 LLAMA的开发环境
      - L3.4.3 LLAMA的使用示例
    • L3.5 其他大模型介绍

阶段4:AI大模型私有化部署

  • 目标:掌握多种AI大模型的私有化部署,包括多模态和特定领域模型。
  • 内容
    • L4.1 模型私有化部署概述
    • L4.2 模型私有化部署的关键技术
    • L4.3 模型私有化部署的实施步骤
    • L4.4 模型私有化部署的应用场景

学习计划:

  • 阶段1:1-2个月,建立AI大模型的基础知识体系。
  • 阶段2:2-3个月,专注于API应用开发能力的提升。
  • 阶段3:3-4个月,深入实践AI大模型的应用架构和私有化部署。
  • 阶段4:4-5个月,专注于高级模型的应用和部署。
这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值