0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

SwinTransformer模型优化

jf_pJlTbmA9 来源:jf_pJlTbmA9 作者:jf_pJlTbmA9 2023-08-18 11:26 次阅读

1.SwinTransformer概述#

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

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

wKgaomTeyVuAYSV-AAH_nvsIKe8575.png

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

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

prec time(ms)
FP32 41.890
FP16 7.411
INT8 5.505

2.性能瓶颈分析#

wKgaomTeyWOAedB_AA5Cv1hBSNo224.png

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

3.模型优化#

3.1.transpose消除#

wKgZomTeyWSAEGPIAAFthu7vLEc860.png

观察图中的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融合呢?为了解释这个问题,我们可以从下面这张图来分析。

wKgZomTeyWaAWzrtAAEfINRn8eE361.png

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

wKgaomTeyWiAIHH0AAFAV5zgcT0282.png

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

wKgaomTeyWqAMO94AAKtg8z74FU208.png

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

wKgZomTeyWuAFJIjAACBkWs2ibU087.png

相关代码: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,说明其中仍存在优化点。

wKgZomTeyW-AAHnFAAhosqHDhI8276.png

经过在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,其中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的。

1
2
3
4
5
6
7
8
9
10
11
12
13
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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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的判断逻辑。

1
2
3
4
5
6
7
8
9
10
11
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();
}

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

wKgZomTeyXaAFfrSAAla61AYaeI924.png

可以看到刚刚几个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的分支逻辑

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

wKgaomTeyXmAdmgMAAVdVXLUGbI555.png

AddOp也成功的合入了group。

4.优化效果#

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

wKgaomTeyYSAYLA7ABDv1AzYFys702.png

模型的性能变化情况:

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

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

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 计算机
    +关注

    关注

    19

    文章

    7492

    浏览量

    87902
  • 模型
    +关注

    关注

    1

    文章

    3238

    浏览量

    48824
  • 计算机视觉
    +关注

    关注

    8

    文章

    1698

    浏览量

    45987
收藏 人收藏

    评论

    相关推荐

    优化模型与Lindo/Lingo优化软件

    优化模型与Lindo/Lingo优化软件 优化模型简介 LINDO公司的主要软件产品及功能简介 LINDO软件
    发表于 09-15 12:22

    模型优化器中张量流保存模型运行失败

    嗨,我试图为我的tensorflow保存的模型运行模型优化器,但失败了。以下是我保存的模型。(基数)D:\ tmp \ export \ 1536028618> saved_model
    发表于 11-12 14:13

    MNIST数据集训练手写数字识别模型优化

    TensorFlow笔记(4)——优化手写数字识别模型之代价函数和拟合
    发表于 10-21 10:39

    Flair的优化模型教程

    工具篇Flair之优化模型教程
    发表于 04-29 10:09

    Lite Actor:方舟Actor并发模型的轻量级优化

    设备的不断增多,并发模型显得举足轻重,本期我们将为大家带来方舟编译器对传统Actor并发模型的轻量级优化。 一、什么是并发模型?在操作系统中,并发是任务在不影响最终执行结果的情况下无序
    发表于 07-18 12:00

    基于移动代理的层次优化挖掘模型

    对于大规模分布式数据挖掘问题,提出一种基于移动代理的层次结构挖掘模型,该模型对OIKI DDM模型进行扩展,利用层次设计思想,基于移动代理和增量优化技术进行挖掘和增量集
    发表于 05-11 20:28 19次下载

    优化模型与LINDO/LINGO优化软件

    优化模型与LINDO/LINGO优化软件: 优化模型简介LINDO公司的主要软件产品及功能简介LINDO软件的使用简介LINGO软件的使用简
    发表于 09-24 09:04 23次下载

    cs优化灰色预测模型

    cs优化灰色预测模型,布谷鸟搜索算法,灰色预测模型
    发表于 08-05 18:37 5次下载

    基于船舶备件费效分析备件优化模型分析

    舰船备件优化是保证舰船系统各装备高任务可靠性的一个重要手段。为了权衡备件供应保障中的经费与备件需求的矛盾,针对不可修复系统,建立了定可靠度备件优化和定费用备件优化的两个模型,并对启发式
    发表于 11-08 11:50 11次下载

    基于Kriging模型天线优化设计

    传统的天线优化设计需要对大量的参数组合进行电磁仿真后才能得到最优结果,使得天线高维优化设计效率普遍较低。针对该问题,使用在参数空间均匀分布的少量样本及其仿真结果构建初始Kriging模型优化
    发表于 11-20 09:49 6次下载
    基于Kriging<b class='flag-5'>模型</b>天线<b class='flag-5'>优化</b>设计

    单步电压控制优化模型

    针对中长期电压不稳定问题,提出一种在线滚动的单步电压控制优化模型。该模型基于轨迹灵敏度,在每次滚动优化过程中仅预测求取当前时刻应投入的动作,并使用一种随滚动
    发表于 01-18 16:14 2次下载
    单步电压控制<b class='flag-5'>优化</b><b class='flag-5'>模型</b>

    深度模型中的优化与学习课件下载

    深度模型中的优化与学习课件下载
    发表于 04-07 16:21 3次下载
    深度<b class='flag-5'>模型</b>中的<b class='flag-5'>优化</b>与学习课件下载

    深度学习的模型优化与调试方法

    深度学习模型在训练过程中,往往会遇到各种问题和挑战,如过拟合、欠拟合、梯度消失或爆炸等。因此,对深度学习模型进行优化与调试是确保其性能优越的关键步骤。本文将从数据预处理、模型设计、超参
    的头像 发表于 07-01 11:41 820次阅读

    AI大模型的性能优化方法

    AI大模型的性能优化是一个复杂而关键的任务,涉及多个方面和策略。以下是一些主要的性能优化方法: 一、模型压缩与优化
    的头像 发表于 10-23 15:01 658次阅读

    如何优化自然语言处理模型的性能

    优化自然语言处理(NLP)模型的性能是一个多方面的任务,涉及数据预处理、特征工程、模型选择、模型调参、模型集成与融合等多个环节。以下是一些具
    的头像 发表于 12-05 15:30 374次阅读