从Transformer到ViT:多模态编码器算法原理解析与实现

本文涉及的产品
NLP自然语言处理_基础版,每接口每天50万次
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 从Transformer到ViT:多模态编码器算法原理解析与实现

Transformer架构是一种使用自注意力机制的神经网络,最初是由谷歌提出的,被广泛应用于自然语言处理和图像处理任务中。它是一种基于注意力机制的深度学习模型,适用于序列到序列的学习任务,例如机器翻译、语音识别、文本摘要等。


多模态Transformer前部分encoder算法是近年来在计算机视觉领域备受瞩目的研究方向之一。它的出现极大地推动了多模态信息的融合与处理,被广泛应用于图像、文本等多种数据类型的处理。


其中,Vision Transformer(ViT)是一种以Transformer为基础的视觉编码器,已经在各种视觉任务中取得了极佳的效果。本篇博客将介绍多模态Transformer前部分encoder算法的原理,重点讲解其在ViT中的实现,同时附带完整的ViT代码实现。如果您对多模态Transformer前部分encoder算法感兴趣,或是对ViT的实现方式想要深入了解,本文或许能为您提供帮助。


下面是vit模型核心架构图,下文是对模型架构各部分做了详细的介绍。


1e3f79cb9f364ab4b38a43e1a231449b.png


模型架构与算法原理


Image Token Embedding


1687315902568.png


Multi-head Self-attention流程


1687315924829.png

线性变换


1687315958723.png

cbe9a9d814054d0e87b94a7cb5e5f3d3.png


1687315980310.png


aa928b5eba8d43b08855645c94cac81c.png


Scale和softmax


1687316018248.png


MatMul


1687316043373.png

aa928b5eba8d43b08855645c94cac81c.png


1b8152baab2744c3b79a02570b2b774a.png5ee616b28da347ec9c96622bafe732c4.png


上面这种是对于自注意力的,还有一种多注意力

多注意力实现其实就是多个自注意力这样的结构结合起来,如下图所示

f03ce78ceabb4217b28c321f4226c220.png

1687316100418.png

多头只是从计算上来说,每一个自注意的q不仅要与自己的k和v计算,还要结合其他的自注意的k和v计算。


最简单的例子来理解注意力,举例一个生活的例子来说


当我们将自注意力算法类比为一个学生学习一门学科的过程时,可以将q qq看作是学生的注意力,k kk看作是这门学科的大纲,v vv则代表着这个学科的教材的内容。通过计算q qq与k kk的相似度,可以得到学生消耗注意力与大纲中不同知识点之间的分配权重,从而确定学生应该集中注意力去学习哪些知识点。最后,通过将这些权重乘以v vv,可以得到学生学习到的知识内容。


多头注意力算法可以被类比为一个学生在学习多门学科的情况。在这种情况下,不同的学科可能具有不同的难度、内容和格式。因此,学生的注意力在不同的学科中可能有所不同。通过多头注意力算法,我们可以将学生的注意力q qq与不同学科大纲中的知识点k kk以及学科的教材内容v vv相乘,从而得到不同学科下的学习成果。这样做的好处是,可以更好地利用不同学科中的优势,进一步提高学生的学习效果。


前向层模块


1687316182822.png


ADD NORM模块


1687316196437.png


思考


搞懂了算法各结构的原理,如下是我个人的几个思考


为什么这种transformer结构,将原始特征向量通过与上下文(或者上下图像)的相似度计算,得出的新的特征向量能够更准确的代表这个数据的特征向量呢?

Transformer 结构在自然语言处理和计算机视觉等领域广泛应用,主要原因是它具有以下优点:


上下文信息丰富。相比于传统的基于手工设计特征的方法,Transformer能够利用上下文信息对特征向量进行更加准确的表示。在自然语言处理中,上下文可以是当前单词所处的句子或段落,而在计算机视觉中,上下文可以是当前像素所处的图像区域。

处理长序列能力强。由于使用了自注意力机制,Transformer 能够对长序列进行有效的处理。在自然语言处理中,这使得Transformer 能够处理长文本,而在计算机视觉中,这使得 Transformer 能够对高分辨率的图像进行处理。

端到端的学习。Transformer结构能够直接从原始数据中学习特征表示,而无需手工设计特征。这使得模型能够从原始数据中学习到更加准确的特征表示,从而提高了模型的性能。


为什么多头注意力,比自注意力效果更好呢


多头注意力是一种在 Transformer 模型中使用的注意力机制,相比于单独使用自注意力机制,它能够提高模型的表现。这主要是由于以下几个原因:


多头注意力能够并行处理不同信息。在多头注意力中,模型使用多个注意力头同时学习不同的信息。这意味着模型能够并行处理多个不同的信息,从而加速模型的训练和推断过程。

多头注意力能够学习更加复杂的特征表示。由于多头注意力能够并行处理多个信息,模型能够学习更加复杂的特征表示。这能够帮助模型捕捉更加丰富和多样化的特征,从而提高模型的表现。

多头注意力能够提高模型的泛化能力。在多头注意力中,每个注意力头都能够学习不同的特征表示,这使得模型更加鲁棒并能够更好地泛化到新的数据。

总的来说,多头注意力能够并行处理多个信息,学习更加复杂的特征表示,并提高模型的泛化能力,这使得它比单独使用自注意力机制效果更好。


在transformer中encoder叠加了多个,它的作用是什么呢,是不断更精细化的求出图像与图像相似度之间的关系吗


在 Transformer 模型中,encoder 叠加了多个层,每个层都包含了多头注意力和前馈神经网络。encoder 叠加多层的作用是逐渐提取和组合输入序列中的信息,并生成更加准确的特征表示。这些特征表示最终被用于后续的任务,如机器翻译、语言模型、文本分类等。


具体来说,encoder 中的每一层都能够进一步优化模型的特征表示。通过多层叠加,模型能够逐渐捕捉输入序列中的更多信息,从而生成更加准确的特征表示。这些特征表示能够反映输入序列中的重要信息,并能够被用于后续的任务。


因此,encoder 叠加多层的作用并不是仅仅更精细地求出图像与图像之间的相似度,而是逐渐提取和组合输入序列中的信息,生成更加准确的特征表示,从而提高模型的性能。在计算机视觉任务中,输入序列可能是图像的像素值序列或者是图像的特征表示序列,而不仅仅是图像与图像之间的相似度。


多模态模型应用的感想


掌握了transformer就是前半部分,就算是知道了,我们现在有的数据图像、语音、文本是如何转为模型的特征向量了,


能获取到这些特征向量,应该说就可以输出任何标签类的任务,从实现原理熵也就是在transformer结构下游,增加全连接层实现输出。(这也是在大模型中使用预训练模型微调的一种方法)。

Paddle实现vit模型


# ViT Online Class
# Author: Dr. Zhu
# Project: PaddleViT (https://github.com/BR-IDL/PaddleViT)
# 2021.11
import paddle
import paddle.nn as nn
import numpy as np
from PIL import Image
paddle.set_device('cpu')
class Identity(nn.Layer):
    def __init__(self):
        super().__init__()
    def forward(self, x):
        return x
class Mlp(nn.Layer):
    def __init__(self, embed_dim, mlp_ratio=4.0, dropout=0.):
        super().__init__()
        self.fc1 = nn.Linear(embed_dim, int(embed_dim * mlp_ratio))
        self.fc2 = nn.Linear(int(embed_dim * mlp_ratio), embed_dim)
        self.act = nn.GELU()
        self.dropout = nn.Dropout(dropout)
    def forward(self, x):
        x = self.fc1(x)
        x = self.act(x)
        x = self.dropout(x)
        x = self.fc2(x)
        return x
class PatchEmbedding(nn.Layer):
    def __init__(self, image_size, patch_size, in_channels, embed_dim, dropout=0.):
        super().__init__()
        self.patch_embedding = nn.Conv2D(in_channels, embed_dim, patch_size, patch_size)
        self.dropout = nn.Dropout(dropout)
    def forward(self, x):
        # [n, c, h, w]
        x = self.patch_embedding(x) # [n, c', h', w']
        x = x.flatten(2) # [n, c', h'*w']
        x = x.transpose([0, 2, 1]) # [n, h'*w', c']
        x = self.dropout(x)
        return x
class Attention(nn.Layer):
    # TODO: 补全时,删除pass
    def __init__(self, embed_dim, num_heads, qkv_bias=False, qk_scale=None, dropout=0., attention_dropout=0.):
        super().__init__()
        self.num_heads = num_heads 
        self.attn_head_size = int(embed_dim / self.num_heads)
        self.all_head_size = self.attn_head_size * self.num_heads
        self.qkv = nn.Linear(embed_dim, self.all_head_size*3)
        if qk_scale == None:
            self.scales = self.attn_head_size ** -0.5
        else:
            self.scales = qk_scale
        self.proj = nn.Linear(self.all_head_size, embed_dim)
        self.attn_dropout = nn.Dropout(attention_dropout)
        self.proj_dropout = nn.Dropout(dropout)
        self.softmax = nn.Softmax(axis=-1)
    def transpose_multihead(self, x):
        new_shape = x.shape[:-1] + [self.num_heads, self.attn_head_size]
        x = x.reshape(new_shape)
        x = x.transpose([0, 2, 1, 3])
        return x
    def forward(self, x):
        qkv = self.qkv(x).chunk(3, axis=-1)
        q, k, v = map(self.transpose_multihead, qkv)
        attn = paddle.matmul(q, k, transpose_y=True)
        attn = attn * self.scales
        attn = self.softmax(attn)
        attn_weights = attn
        attn = self.attn_dropout(attn)
        z = paddle.matmul(attn, v)
        z = z.transpose([0, 2, 1, 3])
        new_shape = z.shape[:-2] + [self.all_head_size]
        z = z.reshape(new_shape)
        z = self.proj(z)
        z = self.proj_dropout(z)
        return z, attn_weights
class EncoderLayer(nn.Layer):
    def __init__(self, embed_dim):
        super().__init__()
        self.attn_norm = nn.LayerNorm(embed_dim)
        self.attn = Attention()
        self.mlp_norm = nn.LayerNorm(embed_dim)
        self.mlp = Mlp(embed_dim)
    def forward(self, x):
        h = x 
        x = self.attn_norm(x)
        x = self.attn(x)
        x = x + h
        h = x
        x = self.mlp_norm(x)
        x = self.mlp(x)
        x = x + h
        return x
class ViT(nn.Layer):
    def __init__(self):
        super().__init__()
        self.patch_embed = PatchEmbedding(224, 7, 3, 16)
        layer_list = [EncoderLayer(16) for i in range(5)]
        self.encoders = nn.LayerList(layer_list)
        self.head = nn.Linear(16, 10)
        self.avgpool = nn.AdaptiveAvgPool1D(1)
        self.norm = nn.LayerNorm(16)
    def forward(self, x):
        x = self.patch_embed(x) # [n, h*w, c]: 4, 1024, 16
        for encoder in self.encoders:
            x = encoder(x)
        # avg
        x = self.norm(x)
        x = x.transpose([0, 2, 1])
        x = self.avgpool(x)
        x = x.flatten(1)
        x = self.head(x)
        return x
def main():
    t = paddle.randn([4, 16, 96])
    print('input shape = ', t.shape)
    model = Attention(embed_dim=96, num_heads=8, 
                      qkv_bias=False, qk_scale=None, dropout=0., attention_dropout=0.)
    print(model)
    out, attn_weights = model(t)
    print(out.shape)
    print(attn_weights.shape)
if __name__ == "__main__":
    main()
相关文章
|
18天前
|
存储 算法 安全
.NET 平台 SM2 国密算法 License 证书生成深度解析
授权证书文件的后缀通常取决于其编码格式和具体用途。本文档通过一个示例程序展示了如何在 .NET 平台上使用国密 SM2 算法生成和验证许可证(License)文件。该示例不仅详细演示了 SM2 国密算法的实际应用场景,还提供了关于如何高效处理大规模许可证文件生成任务的技术参考。通过对不同并发策略的性能测试,开发者可以更好地理解如何优化许可证生成流程,以满足高并发和大数据量的需求。 希望这段描述更清晰地传达了程序的功能和技术亮点。
89 13
.NET 平台 SM2 国密算法 License 证书生成深度解析
|
14天前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
6天前
|
机器学习/深度学习 数据可视化 PyTorch
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
148 7
深入解析图神经网络注意力机制:数学原理与可视化实现
|
7天前
|
机器学习/深度学习 缓存 自然语言处理
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
Tiktokenizer 是一款现代分词工具,旨在高效、智能地将文本转换为机器可处理的离散单元(token)。它不仅超越了传统的空格分割和正则表达式匹配方法,还结合了上下文感知能力,适应复杂语言结构。Tiktokenizer 的核心特性包括自适应 token 分割、高效编码能力和出色的可扩展性,使其适用于从聊天机器人到大规模文本分析等多种应用场景。通过模块化设计,Tiktokenizer 确保了代码的可重用性和维护性,并在分词精度、处理效率和灵活性方面表现出色。此外,它支持多语言处理、表情符号识别和领域特定文本处理,能够应对各种复杂的文本输入需求。
38 6
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
|
7天前
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
23 7
|
11天前
|
数据采集 人工智能 编解码
算法系统协同优化,vivo与港中文推出BlueLM-V-3B,手机秒变多模态AI专家
BlueLM-V-3B是由vivo与香港中文大学共同研发的多模态大型语言模型,专为移动设备优化。它通过算法和系统协同优化,实现了高效部署和快速生成速度(24.4 token/s),并在OpenCompass基准测试中取得优异成绩(66.1分)。模型小巧,语言部分含27亿参数,视觉编码器含4000万参数,适合移动设备使用。尽管如此,低端设备可能仍面临资源压力,实际应用效果需进一步验证。论文链接:https://arxiv.org/abs/2411.10640。
31 9
|
17天前
|
Java 数据库 开发者
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
63 12
|
15天前
|
开发框架 监控 JavaScript
解锁鸿蒙装饰器:应用、原理与优势全解析
ArkTS提供了多维度的状态管理机制。在UI开发框架中,与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,还可以在应用全局范围内传递或跨设备传递。
34 2
|
25天前
|
存储 监控 算法
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
|
13天前
|
机器学习/深度学习 自然语言处理 算法
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
113 0

热门文章

最新文章

推荐镜像

更多