Swintransformer模型的优化

SwinTransformer模型优化

文章目录

  • SwinTransformer模型优化
    • 1.SwinTransformer概述
    • 2.性能瓶颈分析
    • 3.模型优化
      • 3.1.transpose消除
      • 3.2.更好的layergroup
        • 3.1.1.SliceOp
        • 3.1.2.SqueezeOp
        • 3.1.3.weight切分
    • 4.优化效果

1.SwinTransformer概述

自从Transformer在NLP任务上取得突破性的进展之后,业内一直尝试着把Transformer用于CV领域。之前的若干尝试都是将Transformer用在了图像分类领域,但这些方法都面临两个非常严峻的挑战,一是多尺度问题,二是计算复杂度的问题。

基于这两个挑战,swint的作者提出了一种层级式提取的Transformer,并通过移动窗口的方式来学习特征。在窗口内计算自注意力可以带来更高的效率;同时通过移动的操作,让相邻的窗口之间有了交互,变相达到了一种全局建模的能力,进而解决了上面两个问题。
在这里插入图片描述

Swin Transformer将transformer结构与cnn的思想相结合,提出了一个可以广泛应用到各个计算机视觉领域的backbone,在检测、分类和分割等任务的数据集上都呈现出很好的效果,可以应用于很多对精度有较高要求的场景。Swin Transformer之所以能有这么大的影响力主要是因为在 ViT 之后,它通过在一系列视觉任务上的强大表现 ,进一步证明了Transformer是可以在视觉领域取得广泛应用的。

下表中展示了目前swin-t模型在1684X上的性能情况,本文主要针对FP16和INT8模型进行优化部署。

prectime(ms)
FP3241.890
FP167.411
INT85.505

2.性能瓶颈分析

在这里插入图片描述

通过bmprofile工具可视化FP16模型在1684X上的运行状态,这里截取了模型中的一个block。从图中可以看出大量的permute(transpose)层穿插其中,一方面带来较大的数据搬运开销,另一方面使得网络无法layergroup,并行效果较差。

3.模型优化

3.1.transpose消除

在这里插入图片描述

观察图中的attention结构,共有3个transpose层。其中第一个transpose层可以拆解为2个transpose,一是把QKV所在的维度(3)移到了最前面,二是将head所在维度(3)与patch所在维度(49)交换了顺序。由于后面紧跟着split操作是为了将QKV拆分成三个分支,那么此处完全可以不做第一个transpose,而让其直接在原维度上进行split。这样再把第二个transpose的执行改变顺序,让他分别向下移动到三个分支上。这样处理的原因是:在tpu-mlir中是支持transpose与相邻的matmul算子融合的,因此当transpose下移到matmul算子上一层就可以与matmul融合。

细心的读者可能会发现一个问题,QK相乘的matmul其右输入已经有一个transpose了,再叠加另一个transpose在一起还能融合吗?又与哪个transpose融合呢?为了解释这个问题,我们可以从下面这张图来分析。
在这里插入图片描述

这是我们预期图优化后达到的效果,可以看到这里matmul是将49x32和32x49这两个矩阵做乘法,64和3可以看作batch。刚好我们的tpu-mlir中是支持hdim_is_batch这种优化的。因此对于这种情况,优化后左右两个transpose都被消除掉,在matmul的输出位置会再新增一个transpose。之后这个matmul再与右面剩下的transpose进行Rtrans融合就可以了。效果如下图所示:
在这里插入图片描述

这个输出多出来的transpose可以继续被向下移动至下一个matmul之前,此时网络结构如图:

在这里插入图片描述

对于第二个matmul,再次应用hdim_is_batch的优化,消除左右输入的transpose层,之后在输出额外加入的transpose就可以刚好和网络最后的transpose层抵消,至此,所有的transpose都被消除了。

在这里插入图片描述

相关代码:tpu-mlir/lib/Dialect/Top/Canonicalize/MatMul.cpp

MatmulWithPermuteAndSplit这个pattern就是用于识别swint中的attention结构,并将transpose+split+squeeze的结构进行调整,其目的就是为了让整块结构可以成功的利用我们编译器已有的一系列针对transpose+matmul这个组合的优化。

3.2.更好的layergroup

TPU 分为 Local Memory 和 Global Memory,一个独立的计算指令的执行会经过 gdma(global → local),bdc,gdma(local→ global)的过程,在模型的执行过程中,我们希望gdma搬运类的操作越少越好,这样可以更大程度地利用我们的TPU算力。基于这个想法,在tpu-mlir中设计了LayerGroup的功能,LayerGroup经过计算,可以将多个计算指令划分到一个 Group ,在一个 Group 内,每个 Op 直接使用上一个 Op 计算后存放在 Local Memory的数据 ,可以减少每两个Op数据衔接之间的搬出与搬入,从而减少了 io 的时间。因此,layergroup的效果往往也是我们优化一个模型要考虑的因素。

在完成了3.1中的优化工作后,按照运算逻辑,attention应该可以Group到一起,但实际情况并不如此,如图所示,这里截取了final.mlir的一部分attention结构,这里的各个op都是global layer,说明其中仍存在优化点。
在这里插入图片描述

经过在tpu-mlir中的debug,分析其原因有两点,一是SliceOp的local layer不支持5维的情况,二是SqueezeOp没有支持localgen。下面针对这两点进行优化。

3.1.1.SliceOp

代码:tpu-mlir/lib/Dialect/Tpu/Interfaces/Common/Slice.cpp

其中 LogicalResult tpu::SliceOp::LocalGenSupport()用于判断该Op能否支持locallayer,其中

else if (module::isBM1684XFamily()) {if((int)getRunMode(getOperation()) == 1) {return failure();}const auto offset = module::getI64Array(getOffset());const auto steps = module::getI64Array(getSteps());if (num_dims > 2) {if (steps->at(1) != 1)return failure();}if (num_dims > 4) {return failure();}
}

在这段代码中观察到,对于1684X芯片,在num_dims>4时直接认为不支持local layer。这里我们对逻辑做进一步完善,在group3d的情况下,5维的shape会按照[n,c,d,h*w]来处理,所以此时如果仅做slice_d,是不会导致数据有跨npu整理的行为的,那么此时他也是允许local layer的。

if(num_dims == 5){int64_t in_shape[5];int64_t out_shape[5];tpu_mlir::group_type_t group_type = GROUP_3D;module::getNCDHW(getInput(), in_shape[0],in_shape[1],in_shape[2],in_shape[3], in_shape[4],group_type);module::getNCDHW(getOutput(), out_shape[0],out_shape[1],out_shape[2],out_shape[3], out_shape[4], group_type);for(int i=0; i<5; ++i){if(in_shape[i]!=out_shape[i] && (i!=2)){return failure();}}return success();
}

3.1.2.SqueezeOp

SqueezeOp还没有支持local layer的codegen,但是1684X的后端中reshape算子是有local实现的,SqueezeOp刚好可以使用。

首先在TpuOps.td文件中给Tpu_SqueezeOp添加localgen的通用接口定义:DeclareOpInterfaceMethods<LocalGenInterface, [“LocalGenSupport”]>

在这个接口定义的基础上我们需要实现两部分,调用后端算子的接口和判断是否支持local的逻辑。

代码:tpu-mlir/lib/Dialect/Tpu/Interfaces/BM1684X/Squeeze.cpp

这个文件中实现了SqueezeOp调用芯片后端算子的接口,我们为其新增codegen_local_bm1684x的接口。

void tpu::SqueezeOp::codegen_local_bm1684x(int64_t n_step, int64_t c_step,int64_t h_step, int64_t d_step,int64_t w_step,group_type_t group_type,local_sec_info_t &sec_info) {auto op = getOperation();auto input_spec = BM168x::get_input_spec(op, group_type);auto output_spec = BM168x::get_output_spec(op,group_type);if (input_spec->at(0).addr == output_spec->at(0).addr) {return;}auto shape = module::getShape(getOutput());reshape_spec_t spec = {0};spec.dims = shape.size();for (size_t i = 0; i < shape.size(); ++i) {spec.shape[i] = shape[i];}BM168x::call_local_func("backend_api_reshape_local", &spec, sizeof(spec),&sec_info, input_spec->data(), output_spec->data());
}

代码:lib/Dialect/Tpu/Interfaces/Common/Squeeze.cpp

这个文件中实现了SqueezeOp支持localgen的判断逻辑。

LogicalResult tpu::SqueezeOp::LocalGenSupport() {if (module::isCV18xx() || module::isBM1684Family()) {return failure();}auto ishape = module::getShape(getInput());auto oshape = module::getShape(getOutput());if (ishape.size() < 2 || oshape.size() < 2 || ishape[0] != oshape[0] || ishape[1] != oshape[1]) {return failure();}return success();
}

完成上述优化后让我们再来编译模型看一下效果:

在这里插入图片描述

可以看到刚刚几个global layer已经整理到一个group中了。

3.1.3.weight切分

从上面group的效果来看,还存在着一个比较特殊的情况,这里AddOp并没有和其他层group到一起。这里的原因是,add的一个输入为权重,但是tpu-mlir目前对权重的处理是不进行切分,所以在切分遇到weight时,就认为其不支持group。但是像add这种点对点运算的Op,如果输入为权重,理论上也是可以进行切分的。

为了支持这个功能,涉及修改的地方较多,感兴趣的读者可以先了解一下tpu-mlir中layer group的过程实现,相关的讲解视频在开源社区:layer group精讲

此处概括一下支持weight切分的方式:

1.给top层WeightOp增加 allow_split的参数

2.LocalGenSupport支持add sub mul div max min这类点对点操作

3.做layer group之前给符合要求的op配置allow_split

4.完善layer group切分时涉及到输入为weight的分支逻辑

完成上述优化后让我们再来编译模型看一下效果:
在这里插入图片描述

AddOp也成功的合入了group。

4.优化效果

使用bmprofile工具再次观察模型的运行情况,与优化前相比,节省了大量GDMA搬运的时间,BDC计算与GDMA搬运数据的并行效果更好了。

在这里插入图片描述

模型的性能变化情况:

FP16INT8
优化前7.411ms5.505ms
优化后3.522ms2.228ms
优化效果性能提升110%性能提升145%

FP16模型和INT8模型在1684X上的运行速度都得到了大幅度提升。至此,这一阶段的swint优化工作完成。

| 7.411ms | 5.505ms |
| 优化后 | 3.522ms | 2.228ms |
| 优化效果 | 性能提升110% | 性能提升145% |

FP16模型和INT8模型在1684X上的运行速度都得到了大幅度提升。至此,这一阶段的swint优化工作完成。

希望这篇记录文档能为其他类似模型的优化工作提供帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/25675.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20天突破英语四级高频词汇——第②天

2&#xfeff;0天突破英语四级高频词汇~第2天加油(ง •_•)ง&#x1f4aa; &#x1f433;博主&#xff1a;命运之光 &#x1f308;专栏&#xff1a;英语四级高频词汇速记 &#x1f30c;博主的其他文章&#xff1a;点击进入博主的主页 目录 2&#xfeff;0天突破英语四级高…

Bert详细学习及代码实现详解

BERT概述 BERT的全称是Bidirectional Encoder Representation from Transformers&#xff0c;即双向Transformer的Encoder&#xff0c;因为decoder是不能获要预测的信息的。在大型语料库&#xff08;Wikipedia BookCorpus&#xff09;上训练一个大型模型&#xff08;12 层到 …

【基础IO】文件系统 {磁盘的物理结构,存储结构,逻辑结构;CHS 和 LBA 寻址方式;磁盘分区和块组;文件inode;软硬链接}

文件系统 文件分为&#xff1a; 内存文件&#xff1a;被进程打开的文件&#xff0c;文件被加载到内存中供进程快速读写。磁盘文件&#xff1a;没有被打开的文件&#xff0c;保存在磁盘上。磁盘文件被分门别类的存储和管理&#xff0c;用于支持更好的存取。 提示&#xff1a; …

华为发布数字资产继承功能

在华为开发者大会2023&#xff08;HDC.Together&#xff09;上&#xff0c;华为常务董事、终端BG CEO、智能汽车解决方案BU CEO余承东正式发布了数字资产继承功能&#xff0c;HarmonyOS提供了安全便捷的数字资产继承路径。 在鸿蒙世界中&#xff0c;我们每个人在每台设备、应用…

复原 IP 地址——力扣93

文章目录 题目描述回溯题目描述 回溯 class Solution{public:static constexpr int seg_count=4<

第6集丨Vue 江湖 —— Class 与 Style 样式绑定

目录 一、class绑定1.1 字符串1.2 数组1.3 对象1.4 完整案例 二、style绑定2.1 案例2.2 效果 操作元素的 class 列表和内联样式是数据绑定的一个常见需求。因为它们都是 attribute&#xff0c;所以我们可以用 v-bind 处理它们&#xff1a;只需要通过表达式计算出字符串结果即可…

Typescript - 索引签名

目录 1&#xff0c;什么是索引签名1&#xff0c;js 中使用对象的属性2&#xff0c;ts 中的索引签名3&#xff0c;扩展索引签名定义的类型 2&#xff0c;与 Record 对比3&#xff0c;遇到的问题1&#xff0c;索引 key 的类型问题&#xff0c;keyof2&#xff0c;索引 key 的类型问…

uni-app:实现表格多选及数据获取

效果&#xff1a; 代码&#xff1a; <template><view><scroll-view scroll-x"true" style"overflow-x: scroll; white-space: nowrap;"><view class"table"><view class"table-tr"><view class&quo…

mysql高级三:sql性能优化+索引优化+慢查询日志

内容介绍 单表索引失效案例 0、思考题&#xff1a;如果把100万数据插入MYSQL &#xff0c;如何提高插入效率 &#xff08;1&#xff09;关闭自动提交&#xff0c;只手动提交一次 &#xff08;2&#xff09;删除除主键索引外其他索引 &#xff08;3&#xff09;拼写mysql可以执…

Typescript中的元组与数组的区别

Typescript中的元组与数组的区别 元组可以应用在经纬度这样明确固定长度和类型的场景下 //元组和数组类似&#xff0c;但是类型注解时会不一样//元组赋值的类型、位置、个数需要和定义的类型、位置、个数完全一致&#xff0c;不然会报错。 // 数组 某个位置的值可以是注解中的…

新能源电车交流充电桩控制主板的安全性维度

你是否想过&#xff0c;交流充电桩主板的安全性有多重要?它不仅关乎充电设备的寿命&#xff0c;还关乎电网的安全。今天我们就来探讨一下&#xff0c;如何从多个维度保证交流充电桩主板的安全性。 首先&#xff0c;交流充电桩主板采用多重安全保护技术&#xff0c;可以有效地保…

SM2算法的抗侧信道攻击

SM2 算法中底层模块抗侧信道 标量乘 ( [ k ] G [k]G [k]G) 运算过程中需要用到大量的倍点运算与点加运算。传统倍点运算与点加运算之间由于需要的运算次数不同&#xff0c;功耗存在明显区别&#xff0c;攻击者可以通过功耗波形特征分析密钥信息。传统算法如下图所示&#xff1a…

11. 使用tomcat中碰到的一些问题

文章目录 问题一&#xff1a;Tomcat的startup.bat启动后出现乱码问题二&#xff1a;一闪而退之端口占用问题三&#xff1a;非端口问题的一闪而退问题四&#xff1a;服务器的乱码和跨域问题问题五: 在tomcat\webapps\下创建文件夹为什么tomcat重启就会丢失问题六&#xff1a;Tom…

【C++】AVL(平衡二叉搜索树)树的原理及实现

文章目录 一、引言 二、AVL树的概念 三、AVL树的插入 3、1 AVL树的简单插入 3、2 旋转分类 3、2、1 新节点插入较高右子树的右侧&#xff1a;左单旋 3、2、2 新节点插入较高左子树的左侧&#xff1a;右单旋 3、2、3 新节点插入较高左子树的右侧&#xff1a;左右双旋&#xff08…

数据库执行新增时,字段写值错乱/字段值写反了 的问题

今天给表加了个字段&#xff0c;执行新增后查看表&#xff0c;发现数据库执行新增完成后&#xff0c;字段写值错乱了&#xff0c;表现为这两个字段的值写反了↓↓↓↓↓↓ 排查了xml中所有赋值的地方&#xff0c;全都没有问题 字段与属性的通用映射&#xff1a; <resultMap…

【已解决】Java 中使用 ES 高级客户端库 RestHighLevelClient 清理百万级规模历史数据

&#x1f389;工作中遇到这样一个需求场景&#xff1a;由于ES数据库中历史数据过多&#xff0c;占用太多的磁盘空间&#xff0c;需要定期地进行清理&#xff0c;在一定程度上可以释放磁盘空间&#xff0c;减轻磁盘空间压力。 &#x1f388;在经过调研之后发现&#xff0c;某服务…

编织人工智能:机器学习发展历史与关键技术全解析

文章目录 1. 引言1.1 机器学习的定义1.2 重要性和应用场景重要性应用场景 2. 机器学习的早期历史2.1 初期理论与算法感知机决策树 2.2 早期突破支持向量机神经网络初探 3. 21世纪初期的发展3.1 集成学习方法随机森林XGBoost 3.2 深度学习的崛起卷积神经网络&#xff08;CNN&…

css-4:元素水平垂直居中的方法有哪些?如果元素不定宽高呢?

1、背景 在开发中&#xff0c;经常遇到这个问题&#xff0c;即让某个元素的内容在水平和垂直方向上都居中&#xff0c;内容不仅限于文字&#xff0c;可能是图片或其他元素。 居中是一个非常基础但又是非常重要的应用场景&#xff0c;实现居中的方法存在很多&#xff0c;可以将这…

Spring IOC

◆ 传统Javaweb开发的困惑 ◆ IoC、DI和AOP思想提出 ◆ Spring框架的诞生 Spring | Home IOC控制反转&#xff1a;BeanFactory 快速入门 package com.xiaolin.service.Impl;import com.xiaolin.dao.UserDao; import com.xiaolin.service.UserService;public class UserServic…

Intel 4工艺太难了!酷睿Ultra终于突破5GHz

无论是14nm还是10nm&#xff0c;Intel这些年的新工艺都有一个通性&#xff1a;刚诞生的时候性能平平&#xff0c;高频率都上不去&#xff0c;只能用于笔记本移动端(分别对应5代酷睿、10代酷睿)&#xff0c;后期才不断成熟&#xff0c;比如到了13代酷睿就达到史无前例的6GHz。 接…