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

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

3天内不再提示

大象转身,TPU-MLIR适配DragGAN模型前向操作

算能开发者社区 2023-10-10 10:17 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

DragGAN

DragGAN是由谷歌、麻省理工学院和马克斯普朗克研究所创建的一种新的人工智能模型。

通过点击、拖动等简单的交互操作就能改变拍摄对象的姿势、形状和表情等。

DragGAN改变了传统的PS操作流程,只需简单拖拽起点和终点,AI就会根据图像的变化自动生成和补全图像。

DragGAN可处理的图像类型丰富多样,无论是人类表情的调整还是自然风景的变化,都可以在瞬息之内轻松实现。

DragGAN的全流程包含一个基于Generator的前向操作和反向传播过程。本文主要介绍在TPU-MLIR上适配DragGAN模型的前向操作的全部过程。

模型移植

推理代码定位与模型导出

适配的模型代码使用 XingangPan/DragGAN: Official Code for DragGAN (SIGGRAPH 2023) (github.com) ,模型的入口在 DragGAN/viz/renderer.py:357,可以在这里直接引入TPU-MLIR提供的 gen_shell 工具,直接 trace 生成 workspace 文件夹,onnx/pt 模型,以及默认的转换脚本:

fromutils.gen_shellimportgenerate
generate(
"DragGan",
G,
dict(
ws=ws,
c=label
),
"../draggan_workspace",
)

运行源码 README.md 中提供的脚本 python visualizer_drag_gradio.py,运行成功后可以在在同级目录下得到如下的目录结构:

draggan_workspace
├──cali_data
│└──data.npz
├──convert.sh
├──DragGan.onnx
├──DragGan.pt
├──data.npz
└──cali_data

模型移植过程中错误的分析和解决

RuntimeError: Op not support:{'RandomNormalLike'}

在 model_transform 阶段,发现存在不支持的算子 RandomNormalLike:

23bff33c-6713-11ee-9788-92fbcf53809c.png

RandomNormalLike(随机数相关)的算子 1684x 无法支持,所以必须尝试在原模型中避开这些算子。定位到模型代码处,发现该算子用于提供一个噪音供下游使用。源码中提供了三种噪音生成方式,分别是 random(随机噪音),const(常量噪音),和 none(不提供噪音),因此可以通过设置 noise_mode = const 避开这一算子的使用。

23d00a6a-6713-11ee-9788-92fbcf53809c.png

对 Conv/DeConv Filter 为动态输入情况的支持

DragGan 的模型结构中,有一部分 Conv 和 DeConv 的输入是固定权重,而 FilterOp 部份是动态的从上游计算得到的输入。这种情况在这之前未做考虑,需要添加支持。这包括在多个地方的代码更改。下面通过具体的报错提示来一步步分析、定位和解决。

model_transform 阶段

在 tpu-mlir 的 Converter 中,权重(weight)和 动态输入(dynamic input)存储在不同的变量中,其中,weight 通过 getWeightOp(name) 获取,input 通过 getOperand(name) 获取。如果不确定 op 是 dynamic input 还是 weight,可以使用 getOp(name) 来获取。而在对 DragGan 的 model_transform.py 脚本的运行过程中,会遇到如下的报错KeyError: '/synthesis/b8/conv0/Transpose_output_0'

23e4a79a-6713-11ee-9788-92fbcf53809c.png

此时对应模型结构,发现该 DeConv 的输入 /synthesis/b8/conv0/Transpose_output_0 是作为一个 Weight 获取的。

23f183c0-6713-11ee-9788-92fbcf53809c.png

因此将ConvTranspose 的 filter_opd 的获取逻辑改为 getOp 即可

2404748a-6713-11ee-9788-92fbcf53809c.png

同理,另外一个 KeyError 中,DeConv 的 filter 来自于动态输入,所以同理,将 DeConv 获取 filter 结点的逻辑同样改为 getOp。

241726d4-6713-11ee-9788-92fbcf53809c.png

在 model_transform 阶段, 模型会首先转换到DragGAN_origin.mlir,再经过--shape-infer--canonicalize 等过程,转换为可以通过model_runner.py做推理的 Top Dialect 描述的 mlir 文件。在对 Top 层做推理验证正确性时,DragGan 模型报出了精度为零的错误。通过观察输出的错误信息,发现是在 DeConv 层之后精度出现问题的,而且仅在 DeConv 的 filter 是动态输入的情况下会有这一问题。

构建了一个 filter 是动态输入的 DeConv 作为单侧,复现该错误成功:

classDeConvCase(nn.Module):
def__init__(self)->None:
super().__init__()
self.deconv=nn.ConvTranspose2d(4,4,[2,2],stride=[1,1],bias=False)
self.deconv.weight.data=weight

defforward(self,x,y):
output_padding=self.deconv._output_padding(
x,
None,
[2,2],
[0,0],
[2,2],
1,
[1,1],
)

out=F.conv_transpose2d(x,y,None,[1,1],0,output_padding,1,1)

returnout,self.deconv(x)

此时通过断点调试,发现错误原因有两个:

  • 正确性验证阶段推理时,在 init() 时设置权重,此时 weight 还没有设置
  • 动态输入时没有做对应的权重重排(WeightReorder)

tpu-mlir 在适配模型的过程会经过多步转换和多次优化,为了保证转换后的正确性,tpu-mlir 会做三次正确性验证,分别针对 Top Dialect,Tpu Dialect 和 bmodel。Top 和 Tpu 层的正确性的核心代码位于 ModuleInterpreter.[h/cpp],该过程会从输入开始,对每一个 Op 分配空间,进行初始化(init),在初始化结束后进行推理(inference),并在最终对每个 Op 进行析构(deinit)。而 DeConv 的精度错误之一则来自于 Inference 阶段时 init 和 inference 的分离。

在 init 时,DeConv 会构造一个 Dnnl 的实例,此时会直接 copy 一份 Weight 在 Dnnl 实例中,但由于该 filter 为动态输入, init 时值还没有传入,所以传入的 filter 的值实质上是全零。导致在 inference 阶段出现错误。定位后该问题比较好改,将 init 过程中对 Dnnl 实例的 setup 移到 inference 阶段即可。Conv 也有同样的问题,修改逻辑相同。

24318ca4-6713-11ee-9788-92fbcf53809c.png

对 onnx 模型,DeConv 的 filter 的权重存储方式是 input channel first(即 shape 为 [ic, oc, kw, kh]),而后端的计算过程大多都需要 output channel first([oc, ic, kw, kh]),可以注意到 OnnxConverter 中,原本对 DeConv 的权重会存在一个转置操作:

24527a72-6713-11ee-9788-92fbcf53809c.png

而动态权重自然没有办法实现这一操作。因此,需要添加一个图优化,当 DeConv 的 filter 是动态时,在其前面添加一个 [oc, ic] 互换的 Permute 操作。在添加 Permute 操作时,需要仔细考虑 DeConv 添加这一 Permute 的先决条件。确保该 Permute 添加是针对 DeConv 的动态权重,且同时不会重复添加。因此考虑在 DeConv 的 Operation 结构中添加 bool 类型的 dynweight_reorderd 参数。当 filter 不是 top.WeightOp (使用动态权重)且 dynweight_reordered 为 false (没有添加对动态 weight 的 Permute)时,添加这一 Permute,同时设置 dynweight_reorderd 参数为 true。

在 TopOps.td 文件对 DeConv 添加 dynweight_reorderd 参数后,对 DeConv 动态权重的图优化逻辑如下:

structReorderDynWeight:publicOpRewritePattern{
usingOpRewritePattern::OpRewritePattern;

LogicalResultmatchAndRewrite(DeconvOpop,
PatternRewriter&rewriter)constoverride{

autofilter_shape=module::getShape(op.getFilter());//or

if(module::isWeight(op.getOperand(1))){
returnfailure();
}
booldyn_weight_reorderd=op.getDynweightReorderd();
if(dyn_weight_reorderd){
returnfailure();
}

if(isa(op.getOperand(1).getDefiningOp())){
autopermute_op=
dyn_cast(op.getOperand(1).getDefiningOp());

//eraseifalreadyhavethispermutebutfromoriginalgraph
std::vector<int64_t>ps={1,0,2,3};
autoorder=module::getI64Array(permute_op.getOrder());
if(*order==ps){
permute_op.replaceAllUsesWith(permute_op.getInput());
rewriter.eraseOp(permute_op);
op.setDynweightReorderd(true);
returnsuccess();
}
}

rewriter.setInsertionPointAfterValue(op.getFilter());
std::stringname=module::getName(op.getOutput()).str();
autoloc=
NameLoc::get(rewriter.getStringAttr(name+"_reorder_permute"));

std::vector<int64_t>order={1,0};
autofilter_dim=filter_shape.size();
for(inti=2;i< filter_dim; i++) {
order.push_back(i);
}

autop_type=
UnrankedTensorType::get(module::getElementType(op.getFilter()));
std::vectorattrs;
attrs.emplace_back(
rewriter.getNamedAttr("order",rewriter.getI64ArrayAttr(order)));

autonew_permute_op=rewriter.create(
loc,p_type,ValueRange{op.getFilter()},attrs);

new_permute_op.shape_inference();
op.setOperand(1,new_permute_op.getOutput());
op.setDynweightReorderd(true);
returnsuccess();
}
};

这里做了一个额外的判断,当 DeConv 的 filter 位置已经是 Permute 且其 order 和要添加的 Permute 一样(1,0,2,3)时,两个 Permute 可以直接融合,所以此时可以直接删除该 Permute 并返回。其他的情况则是插入一个额外的 Permute 操作。Conv 层同样要支持动态 weight 的权重重排,要添加一个相同的图优化。

此外,Top 层的 shape-infer 要早于图优化,因此在做 shape-infer 时动态 weight 的 shape 仍然还是 input channle first,所以 DeConv 的 output_shape 的 dim[1] 应该基于 filter_shape[1] 来判断。对应的修改位于 lib/Dialect/Top/Interfaces/Deconv.cpp:

2461b438-6713-11ee-9788-92fbcf53809c.png

bmodel 运行错误 ASSERT /workspace/nntoolchain/TPU1686/bm1684x/cmodel/src/cmodel_common.cpp: gather_data: 207: dst_offset < (1<<18)

在大模型中定位这一错误较难,因此可以通过 mlir_cut.py 逐步缩小范围,得到了最小可复现的 mlir:

2471cbe8-6713-11ee-9788-92fbcf53809c.png

mlir_cut.py--mlir*tpu.mlir--output_names/synthesis/b64/conv0/Conv_output_0_Conv--input_names/synthesis/b32/conv1/Mul_3_output_0_Mul,/synthesis/b64/conv0/Reshape_3_output_0_Reshape

tpuc-optDragGan_bm1684x_f32_final.mlir--codegen="model_file=DragGan_f32.bmodelembed_debug_info=true"-o/dev/null
model_runner.py--inputfake_data.npz--modelDragGan_f32.bmodel--outputDragGan_bm1684x_f32_model_outputs.npz

进一步构建了能够复现该错误的单元测试:

24822fd8-6713-11ee-9788-92fbcf53809c.png

通过控制变量,得到了以下现象:

  • 关闭 layer-group,模型运行正常不报错:这说明问题基本是出在 tpu-mlir 部份而不是后端算子部份
  • 将上述的代码中 DeConv 的 filter 从动态改为静态,模型运行正常:说明问题仍然是动态 Weight 导致的
  • 构建基本的 DeConv 算子,无论是静态和动态都运行正常,和上面的单侧进行对比,发现区别在单个 DeConv 算子不会进行 LayerGroup:将问题定位到 tpu-mlir 的 LayerGroup 部份的代码

此时进一步对比正常和出错的 final.mlir,发现 dynamic weight 和 weight 的 slice 属性不一致,如下所示:

249748be-6713-11ee-9788-92fbcf53809c.png

top.Weight 的 layer-group 是比较特殊。top.Weight 在整个 layer-group 都保存在 local memory 中(hold_in_lmem = true);同时,weight 也不能切分 slice,每个 slice 都要用到完成的 filter,从而导致结果错误。

所以需要单独针对 dynamic weight 处理,这包括设置其生命周期(hold_in_mem = true),以及将其 slice 设置为长度为 1,元素为其 shape 对应维度值的列表。这一过程可以在 lib/Dialect/Tpu/Transforms/LayerGroup/LayerGroupUtil.cpp 的 backward_update_slice 方法中完成:

24ad9fba-6713-11ee-9788-92fbcf53809c.png

优化后再对比两个单例的 final.mlir,发现此时 dynamic weight 的 slice 信息已经和普通 weight 完全相同:

24c4dd7e-6713-11ee-9788-92fbcf53809c.png

F16 和 int8 精度问题

在解决了 F32 的 bug 后,F16 和 int8 的 tpu 层 mlir 仍然存在精度问题。原本以为是 DeConv 的 F16 适配存在问题,通过使用 mlir_debugger 对每一层用正确数值做推理(也可以直接观察输出的 npz 文件以及 npz_tool 的比对结果),发现出错的是 Active -> Mul 的结构,Active 是 ReduceSum 操作:

24e5685a-6713-11ee-9788-92fbcf53809c.png

因此基本可以确定是普通的 F16 溢出问题。验证 BF16,发现BF16 编译成功,进一步确认是溢出问题。

将这些层添加到 qtable 中,发现还是通过不了比对,值里面仍然会存在 inf。对比发现是在 Active(ReduceSum) -> Sqrt 的结构中间有两个 Cast 导致的:

24f21456-6713-11ee-9788-92fbcf53809c.png

这两个 cast 没有作用,可以被优化掉,于是写图优化将这两个 Cast 直接消除。优化后对应的 mlir 如下:

2504a922-6713-11ee-9788-92fbcf53809c.png

int8 也是相同的精度溢出问题,同样确认两个 cast 融合的操作能够覆盖 int8 的情况即可。

至此,DragGan 适配的模型部份适配完成。

总结

  • 在一些情况下,在不影响结果的情况下直接修改模型的代码结构可以更容易的解决一些算子适配问题
  • 较大的模型测试错误定位到具体算子的情况下,优先考虑构建单侧尝试复现问题
  • 控制变量,设置对照,是缺少解决思路时寻找问题的一个较为通用的方案。

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

    关注

    1821

    文章

    50511

    浏览量

    267728
  • GaN
    GaN
    +关注

    关注

    21

    文章

    2391

    浏览量

    84921
  • 模型
    +关注

    关注

    1

    文章

    3873

    浏览量

    52337
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    FEC纠错技术:让无线传输“自我修复”的通信卫士

    FEC纠错技术:让无线传输“自我修复”的通信卫士 一、什么是纠错(FEC)? 纠错(
    发表于 05-19 13:50

    海光信息DCU产品深度适配商汤科技SenseNova U1系列大模型

    近日,商汤科技推出并开源新一代原生多模态大模型SenseNova U1,海光DCU率先完成适配,是国内首批适配SenseNova U1的国产芯片厂商。
    的头像 发表于 05-14 17:32 730次阅读

    沐曦股份Day 0适配商汤科技日日新SenseNova U1系列大模型

    近日,日日新 SenseNova U1 原生理解生成统一模型发布并开源。沐曦股份旗下曦云C系列 GPU率先完成 Day 0 适配,成为率先完成该模型适配的国产算力平台。
    的头像 发表于 05-07 16:24 1348次阅读
    沐曦股份Day 0<b class='flag-5'>适配</b>商汤科技日日新SenseNova U1系列大<b class='flag-5'>模型</b>

    昆仑芯科技完成商汤日日新SenseNova U1系列大模型极速适配

    近日,商汤正式发布并开源原生理解生成统一模型——商汤日日新SenseNova U1系列。在模型发布当日,昆仑芯即完成对SenseNova U1的极速适配,成为率先完成该模型
    的头像 发表于 05-06 10:55 575次阅读

    昆仑芯科技完成小米MiMo-V2.5-Pro大模型极速适配

    小米正式发布并开源MiMo-V2.5-Pro模型。昆仑芯在发布当日即完成对MiMo-V2.5-Pro的极速适配,成为首批实现适配的国产算力厂商之一,再次验证其在主流大模型生态中的敏捷响
    的头像 发表于 05-06 10:53 605次阅读

    开放原子AtomGit平台首发适配DeepSeek-V4系列模型

    2026年4月24日,DeepSeek-V4系列模型正式发布并同步开源。AtomGit平台为DeepSeek-V4昇腾适配版本首发平台,为开发者提供从模型获取、算力适配到工程部署的一站
    的头像 发表于 04-29 16:12 930次阅读

    昆仑芯科技完成MiniMax M2.7模型极速适配

    今日,MiniMax正式开源MiniMax M2.7模型。昆仑芯同步完成对该模型的Day 0适配与深度优化,成为首批实现适配的国产算力厂商之一,再次验证其在主流大
    的头像 发表于 04-13 17:07 592次阅读

    海光DCU完成Qwen3.5多模态MoE模型全量适配

    近日,海光DCU完成Qwen3.5-397B MoE旗舰多模态模型、Qwen3.5-35B-A3B MoE多模态模型全量适配、精度对齐与推理部署验证。本次适配依托FlagOS专属vLL
    的头像 发表于 03-26 09:35 877次阅读

    AI芯片大单!Anthropic从博通采购100万颗TPU v7p芯片

    电子发烧友网报道(文/李弯弯)近日消息,AI企业Anthropic将直接从博通采购近100万颗TPU v7 pIronwood AI芯片,本地部署在其控制的数据中心中。也就是说,博通将直接
    的头像 发表于 01-06 08:38 1.1w次阅读

    新品 | 成电子XC3576M小体积主板,全面适配国产麒麟操作系统

    在工业自动化与智能制造高速发展的今天,核心硬件的自主可控已成为国家战略与产业升级的关键。成电子隆重推出XC3576M工控主板——专为国产操作系统优化的小体积高性能解决方案,以卓越性能与全面国产化
    的头像 发表于 12-19 14:07 859次阅读
    新品 | <b class='flag-5'>向</b>成电子XC3576M小体积主板,全面<b class='flag-5'>适配</b>国产麒麟<b class='flag-5'>操作</b>系统

    爱芯元智边缘AI芯片AX8850完成CosyVoice2大模型适配

    今年下半年,随着业务推广需求增加,我们的大模型适配工作也有了新方向:不再只追求前沿模型的快速适配,而是更聚焦为销售团队提供“能打”的实战“弹药”——也就是贴近客户刚需的、可快速落地的大
    的头像 发表于 12-11 10:35 5689次阅读
    爱芯元智边缘AI芯片AX8850完成CosyVoice2大<b class='flag-5'>模型</b><b class='flag-5'>适配</b>

    谷歌云发布最强自研TPU,性能比前代提升4倍

    精心设计,能够轻松处理从大型模型训练到实时聊天机器人运行以及AI智能体操作等各类复杂任务。   谷歌在新闻稿中着重强调,“Ironwood”是专为应对最严苛的工作负载而打造的。无论是大规模模型训练、复杂的强化学习(RL),还是高
    的头像 发表于 11-13 07:49 9163次阅读
    谷歌云发布最强自研<b class='flag-5'>TPU</b>,性能比前代提升4倍

    澎峰科技完成OpenAI最新开源推理模型适配

    澎峰科技现已完成 OpenAI 最新开源推理模型 gpt-oss-20b 在 DeepFusion 大模型一体机上的原生适配与优化,用户可一键启用这颗“小而强悍”的新引擎,在本地享受企业级 AI 生产力!
    的头像 发表于 08-14 11:34 1655次阅读

    华为CANN与智谱GLM端侧模型完成适配

    已于7月28日正式开源其新一代基座模型GLM-4.5,其GLM端侧模型已完成与CANN的适配。这标志着国产大模型与计算架构在端云协同方向实现关键突破,国产AI生态正加速迈入深度融合阶段
    的头像 发表于 08-11 11:00 2862次阅读

    硬件与应用同频共振,英特尔Day 0适配腾讯开源混元大模型

    于OpenVINO™ 构建的 AI 软件平台的可扩展性,英特尔助力ISV生态伙伴率先实现应用端Day 0 模型适配,大幅加速了新模型的落地进程,彰显了 “硬件 + 模型 + 生态” 协
    的头像 发表于 08-07 14:42 1624次阅读
    硬件与应用同频共振,英特尔Day 0<b class='flag-5'>适配</b>腾讯开源混元大<b class='flag-5'>模型</b>