• [问题求助] bearpi-hm-micro可以做外接摄像头模块吗
    请问各位大佬,bearpi-hm-micro可以做外接摄像头模块吗?可以后面搞深度学习吗?
  • [赋能培训] 【视频回顾】GDE直播公开课 · 第十三期:AI模型预训练技术前瞻——作为迁移学习的应用,预训练大模型又该如何举一反三?
    ❤ AI系列往期直播回顾:【GDE直播公开课·第七期】低门槛AI开发模式:ModelFoundry【GDE直播公开课 · 第十一期】AI如何举一反三——迁移学习技术洞察❤视频回顾videovideovideo❤ 精选问答序号问题回复1大模型在业务上的实践效果怎样,能不能举个例子?以NLP领域中文纠错举例,我们采用MacBERT大模型,在开源的数据集上做了纠错预训练任务(训练1-epoch大约15小时),再在业务数据上做了微调,最后纠错准确率从原来的75%提高到90%,性能大幅提升。2预训练模型的基础训练数据来源渠道有哪些?有什么标准和要求?主要来源是业界开源的数据集,目前开源数据集的规模已经很大,完全适用于科学研究。当然如果是针对特定领域,还是需要通过相关合作来获取,或从网络查找对应词条来收集。本身预训练的目的就是节约标注成本,因此数据而言只要和业务数据类型保证一致即可,当然在此基础上做一些数据处理、清洗、去噪等也是可以的。3这么多预训练方法,我们应该在什么场景下用哪个?还是具体问题具体分析,首先看业务需求的侧重点,如果不考虑资源成本,只追求准确率等性能,那可以选择尝试那些更大的模型;如果资源受限,比如端侧业务,那需要选择更轻量化的模型。4运营商业务结构化数据,后期是否可以尝试大模型?结构化数据的大模型在学术界其实一直有在研究,不过还未有大规模应用,还是需要有更多的突破点。5预训练小模型有前途吗?在大模型快速发展以来,基于预训练小模型的迁移学习一直都是AI领域的中坚力量。这两者是并存关系,在某些领域小模型甚至更优。比如人脸识别领域,对推理时延的实时性要求非常高,这是小模型天然的优势所在。6请问地址补全用的预训练模型是什么?就是基本的BERT-base模型。7构建神经网络模型结构,初始状态下如何确定backbone结构?还是遵循从简到难的过程,可以先尝试经典的ResNet等网络结构,再对比一些transformer-based网络结构,如ViT、Swin-transformer等。8会有细分领域的大模型么?细分领域或者说垂直领域的大模型一直都有,比如电商领域大模型E-BERT、金融领域大模型FinBERT等。9如果用现有的大模型,训练特定的语料,比如中医病历,能否直接给出诊断呢?病历诊断这种生成类任务,目前还有很大的发展空间。个人认为可以作为辅助诊断,暂时还不能用来做直接诊断。10NLP大模型在哪些领域有应用?跨语言应用是NLP大模型最好的发挥场景之一,因为存在样本量很少的语言,比如跨语言机器翻译、跨语言文本分类等;同时NLP大模型在基于知识图谱的推荐、检索、问答等都有很好的应用。另外生成类任务也是NLP大模型发力的方向,能够实现智能创作、人机交互等应用。11请问跨模态的大模型,除了艺术设计类(封面、艺术品等)的文生图还有其他的可落地场景吗?个人看法,要实现强人工智能,跨模态是必须的。就目前而言,如电商领域的图文检索、自动驾驶中的人机交互、语音助手等都是可落地的场景。12想要了解CV大模型在现实生活中具体的应用场景有哪些?人脸识别算不算CV大模型中的场景,他在大模型中是怎么训练数据和提高识别的精度的?业内人脸识别技术应用现状和优劣势是什么,是不是都要用到AI和大模型的能力?人脸识别用了预训练的技术(比如对比学习范式,在无标注情况下怎么学习人脸),但目前不算大模型的场景,因为其对检测速度要求非常高,输出表征向量维度越小越好,不太合适大模型,小模型效果就已经很好很有效。活动说明1.有效盖楼:留言“报名”+“截图”、参与提问/建议或微信朋友圈点赞截图的,均可参与盖楼;2.无效盖楼:复制别人的提问、建议等,以及其他不符合要求的灌水信息皆为无效盖楼。注意:同一用户盖楼不能连续超过3楼,总楼层数不能超过10楼。超过盖楼数将视为无效盖楼。无效盖楼且踩中获奖楼层,也将视为无效,奖品不予发放,该楼层奖项轮空;3.盖楼总数及微信朋友圈点赞量取值仅限活动期间内,即2022年9月15日至9月27日24:00,其余时间不纳入计算范围;4.为保证活动有序进行,一经发现有作弊行为,将取消奖励资格;5.所有获奖用户,请于获奖后3日内完成实名认证,否则视为放弃奖励;6.请务必使用个人账号参与活动。本次活动如一个实名认证对应多个账号,只有一个账号可领取奖励;一个实名认证账号只能对应一个收件人,如同一账号填写多个不同收件人或不同账号填写同一收件人,均不予发放奖励;(举例说明:具备同一证件号(比如身份证号/护照ID/海外驾照ID/企业唯一识别号等)、同一手机号、同一设备、同一IP地址等,均视为同一实名用户)7.所有参加本活动的用户,均视为认可并同意遵守华为云社区的用户协议及隐私政策;8.GDE数智平台可能需要根据活动的实际举办情况对活动规则进行变更;若有变更,将以活动页面告知等方式及时通知;9.活动结束后将在活动帖和【GDE直播交流群】微信群中公布获奖名单,奖品配送范围为中国大陆地区,部分地区或因疫情原因延迟配送;10.GDE数智平台拥有活动解释权。中奖公示(已提供地址的中奖人员,奖品将陆续发出;未提供地址的,请留意私信,工作人员将联系获取地址,请在2022年10月21日前提供地址,过时视为自动放弃礼品)请各位中奖者微信添加:华为GDE官方小助手(gdezhushou),回复:GDE直播公开课提供邮寄地址,不添加不能获奖哦~小助手微信二维码报名有奖楼层昵称奖品5乌龟哥哥GDE定制鼠标垫13linghz666GDE定制鼠标垫20DragonCurryGDE定制鼠标垫27linghz666重复,每人仅一次获盖楼奖34Hello DiggerGDE定制鼠标垫探讨有奖昵称优秀提问奖品Hello DiggerNLP大模型在哪些领域有应用?GDE定制帆布袋madqfrog请问老师跨模态的大模型,除了艺术设计类(封面、艺术品等)的文生图还有其他的可落地场景么?GDE定制帆布袋分享有奖排名昵称奖品1linghz666GDE定制防晒伞2上帝之眼GDE定制防晒伞3乌龟哥哥GDE定制防晒伞直播互动奖轮次昵称奖品第一轮王*GDE定制玩偶第一轮李*宇GDE定制玩偶第一轮黄*国GDE定制玩偶第二轮王*GDE定制T恤视频号幸运福袋幸运福袋昵称奖品1A服装鞋子GDE定制防晒伞2LpcGDE定制防晒伞3Tayu Jonathan 明泽GDE定制防晒伞
  • [其他] 浅谈机器学习必学10 大算法
    1 线性回归线性回归(Linear Regression)可能是最流行的机器学习算法。线性回归就是要找一条直线,并且让这条直线尽可能地拟合散点图中的数据点。它试图通过将直线方程与该数据拟合来表示自变量(x 值)和数值结果(y 值)。然后就可以用这条线来预测未来的值!这种算法最常用的技术是最小二乘法(Least of squares)。这个方法计算出最佳拟合线,以使得与直线上每个数据点的垂直距离最小。总距离是所有数据点的垂直距离(绿线)的平方和。其思想是通过最小化这个平方误差或距离来拟合模型。例如,简单线性回归,它有一个自变量(x 轴)和一个因变量(y 轴)。2 逻辑回归逻辑回归(Logistic regression)与线性回归类似,但它是用于输出为二进制的情况(即,当结果只能有两个可能的值)。对最终输出的预测是一个非线性的 S 型函数,称为 logistic function, g()。这个逻辑函数将中间结果值映射到结果变量 Y,其值范围从 0 到 1。然后,这些值可以解释为 Y 出现的概率。S 型逻辑函数的性质使得逻辑回归更适合用于分类任务。逻辑回归曲线图,显示了通过考试的概率与学习时间的关系。3 决策树决策树(Decision Trees)可用于回归和分类任务。在这一算法中,训练模型通过学习树表示(Tree representation)的决策规则来学习预测目标变量的值。树是由具有相应属性的节点组成的。在每个节点上,我们根据可用的特征询问有关数据的问题。左右分支代表可能的答案。最终节点(即叶节点)对应于一个预测值。每个特征的重要性是通过自顶向下方法确定的。节点越高,其属性就越重要。决定是否在餐厅等候的决策树示例。4 朴素贝叶斯朴素贝叶斯(Naive Bayes)是基于贝叶斯定理。它测量每个类的概率,每个类的条件概率给出 x 的值。这个算法用于分类问题,得到一个二进制“是 / 非”的结果。看看下面的方程式。朴素贝叶斯分类器是一种流行的统计技术,可用于过滤垃圾邮件!5 支持向量机(SVM)支持向量机(Support Vector Machine,SVM)是一种用于分类问题的监督算法。支持向量机试图在数据点之间绘制两条线,它们之间的边距最大。为此,我们将数据项绘制为 n 维空间中的点,其中,n 是输入特征的数量。在此基础上,支持向量机找到一个最优边界,称为超平面(Hyperplane),它通过类标签将可能的输出进行最佳分离。超平面与最近的类点之间的距离称为边距。最优超平面具有最大的边界,可以对点进行分类,从而使最近的数据点与这两个类之间的距离最大化。例如,H1 没有将这两个类分开。但 H2 有,不过只有很小的边距。而 H3 以最大的边距将它们分开了。6 K- 最近邻算法(KNN)K- 最近邻算法(K-Nearest Neighbors,KNN)非常简单。KNN 通过在整个训练集中搜索 K 个最相似的实例,即 K 个邻居,并为所有这些 K 个实例分配一个公共输出变量,来对对象进行分类。K 的选择很关键:较小的值可能会得到大量的噪声和不准确的结果,而较大的值是不可行的。它最常用于分类,但也适用于回归问题。用于评估实例之间相似性的距离可以是欧几里得距离(Euclidean distance)、曼哈顿距离(Manhattan distance)或明氏距离(Minkowski distance)。欧几里得距离是两点之间的普通直线距离。它实际上是点坐标之差平方和的平方根。7 K- 均值K- 均值(K-means)是通过对数据集进行分类来聚类的。例如,这个算法可用于根据购买历史将用户分组。它在数据集中找到 K 个聚类。K- 均值用于无监督学习,因此,我们只需使用训练数据 X,以及我们想要识别的聚类数量 K。该算法根据每个数据点的特征,将每个数据点迭代地分配给 K 个组中的一个组。它为每个 K- 聚类(称为质心)选择 K 个点。基于相似度,将新的数据点添加到具有最近质心的聚类中。这个过程一直持续到质心停止变化为止。8 随机森林随机森林(Random Forest)是一种非常流行的集成机器学习算法。这个算法的基本思想是,许多人的意见要比个人的意见更准确。在随机森林中,我们使用决策树集成(参见决策树)。为了对新对象进行分类,我们从每个决策树中进行投票,并结合结果,然后根据多数投票做出最终决定。在训练过程中,每个决策树都是基于训练集的引导样本来构建的。在分类过程中,输入实例的决定是根据多数投票做出的。9 降维由于我们今天能够捕获的数据量之大,机器学习问题变得更加复杂。这就意味着训练极其缓慢,而且很难找到一个好的解决方案。这一问题,通常被称为“维数灾难”(Curse of dimensionality)。降维(Dimensionality reduction)试图在不丢失最重要信息的情况下,通过将特定的特征组合成更高层次的特征来解决这个问题。主成分分析(Principal Component Analysis,PCA)是最流行的降维技术。主成分分析通过将数据集压缩到低维线或超平面 / 子空间来降低数据集的维数。这尽可能地保留了原始数据的显著特征。可以通过将所有数据点近似到一条直线来实现降维的示例。10 人工神经网络(ANN)人工神经网络(Artificial Neural Networks,ANN)可以处理大型复杂的机器学习任务。神经网络本质上是一组带有权值的边和节点组成的相互连接的层,称为神经元。在输入层和输出层之间,我们可以插入多个隐藏层。人工神经网络使用了两个隐藏层。除此之外,还需要处理深度学习。人工神经网络的工作原理与大脑的结构类似。一组神经元被赋予一个随机权重,以确定神经元如何处理输入数据。通过对输入数据训练神经网络来学习输入和输出之间的关系。在训练阶段,系统可以访问正确的答案。如果网络不能准确识别输入,系统就会调整权重。经过充分的训练后,它将始终如一地识别出正确的模式。每个圆形节点表示一个人工神经元,箭头表示从一个人工神经元的输出到另一个人工神经元的输入的连接。
  • [行业动态] CMU提出首个快速知识蒸馏的视觉框架:ResNet50 80.1%精度,训练加速30%
        介绍一篇来自卡耐基梅隆大学等单位 ECCV 2022 的一篇关于快速知识蒸馏的文章,用基本的训练参数配置就可以把 ResNet-50 在 ImageNet-1K 从头开始 (from scratch) 训练到 80.1% (不使用 mixup,cutmix 等数据增强),训练速度(尤其是数据读取开销)相比传统分类框架节省 16% 以上,比之前 SOTA 算法快 30% 以上,是目前精度和速度双双最优的知识蒸馏策略之一,代码和模型已全部开源!    论文和项目网址:http://zhiqiangshen.com/projects/FKD/index.html    代码:https://github.com/szq0214/FKD知识蒸馏(KD)自从 2015 年由 Geoffrey Hinton 等人提出之后,在模型压缩,视觉分类检测等领域产生了巨大影响,后续产生了无数相关变种和扩展版本,但是大体上可以分为以下几类:vanilla KD,online KD,teacher-free KD 等。最近不少研究表明,一个最简单、朴素的知识蒸馏策略就可以获得巨大的性能提升,精度甚至高于很多复杂的 KD 算法。但是 vanilla KD 有一个不可避免的缺点:每次 iteration 都需要把训练样本输入 teacher 前向传播产生软标签 (soft label),这样就导致很大一部分计算开销花费在了遍历 teacher 模型上面,然而 teacher 的规模通常会比 student 大很多,同时 teacher 的权重在训练过程中都是固定的,这样就导致整个知识蒸馏框架学习效率很低。针对这个问题,本文首先分析了为何没法直接为每张输入图片产生单个软标签向量然后在不同 iterations 训练过程中复用这个标签,其根本原因在于视觉领域模型训练过程数据增强的使用,尤其是 random-resize-cropping 这个图像增强策略,导致不同 iteration 产生的输入样本即使来源于同一张图片也可能来自不同区域的采样,导致该样本跟单个软标签向量在不同 iterations 没法很好的匹配。本文基于此,提出了一个快速知识蒸馏的设计,通过特定的编码方式来处理需要的参数,继而进一步存储复用软标签(soft label),与此同时,使用分配区域坐标的策略来训练目标网络。通过这种策略,整个训练过程可以做到显式的 teacher-free,该方法的特点是既快(16%/30% 以上训练加速,对于集群上数据读取缓慢的缺点尤其友好),又好(使用 ResNet-50 在 ImageNet-1K 上不使用额外数据增强可以达到 80.1% 的精度)。
  • [API使用] 【小白求教】无'as_encoder'属性
    初学者,按照HiQ教程测试了“基于Jupyter Notebook开发量子神经网络对鸢尾花进行分类”部分测试,发生如下错误求教,谢谢!
  • [应用开发] CANN训练营2022年度第二季学习笔记:昇腾 AI 基本架构
     1. 昇腾AI全栈架构 1.1 昇腾AI全栈的四个大部分 应用使能层面,此层面通常包含用于部署模型的软硬件,例如API、SDK、部署平台,模型库等等。 AI框架层面,此层面包含用于构建模型的训练框架,例如华为的MindSpore、TensorFlow、Pytorch等。 异构计算架构,偏底层、偏通用的计算框架,用于针对上层AI框架的调用进行加速,力求向上支持多种AI框架,并在硬件上进行加速。 计算硬件,本层是AI计算的底座,有了强力的芯片及硬件设备,上层的加速才有实施的基础。2. 异构计算架构 CANN 华为公司面向计算机视觉、自然语言处理、推荐系统、类机器人等领域量身打造了基于“达芬奇(DaVinci)架构”的昇腾(Ascend)AI处理器,开启了智能之旅。为提升用户开发效率和释放昇腾AI处理器澎湃算力,同步推出针对AI场景的异构计算架构CANN(Compute Architecture for Neural Networks),CANN通过提供多层次的编程接口,以全场景、低门槛、高性能的优势,支持用户快速构建基于Ascend平台的AI应用和业务。昇腾AI异构计算架构(Compute Architecture for Neural Networks,CANN)被抽象成五层架构,如下图所示。​2.1.  昇腾计算语言接口昇腾计算语言(Ascend Computing Language,AscendCL)接口是昇腾计算开放编程框架,是对低层昇腾计算服务接口的封装。它提供Device(设备)管理、Context(上下文)管理、Stream(流)管理、内存管理、模型加载与执行、算子加载与执行、媒体数据处理、Graph(图)管理等API库,供用户开发人工智能应用调用。2.2.  昇腾计算服务层本层主要提供昇腾计算库,例如神经网络(Neural Network,NN)库、线性代数计算库(Basic Linear Algebra Subprograms,BLAS)等;昇腾计算调优引擎库,例如算子调优、子图调优、梯度调优、模型压缩以及AI框架适配器。2.3.  昇腾计算编译引擎本层主要提供图编译器(Graph Compiler)和TBE(Tensor Boost Engine)算子开发支持。前者将用户输入中间表达(Intermediate Representation,IR)的计算图编译成NPU运行的模型。后者提供用户开发自定义算子所需的工具。2.4.  昇腾计算执行引擎本层负责模型和算子的执行,提供如运行时(Runtime)库(执行内存分配、模型管理、数据收发等)、图执行器(Graph Executor)、数字视觉预处理(Digital Vision Pre-Processing,DVPP)、人工智能预处理(Artificial Intelligence Pre-Processing,AIPP)、华为集合通信库(Huawei Collective Communication Library,HCCL)等功能单元。2.5.  昇腾计算基础层本层主要为其上各层提供基础服务,如共享虚拟内存(Shared Virtual Memory,SVM)、设备虚拟化(Virtual Machine,VM)、主机-设备通信(Host Device Communication,HDC)等。3. 昇腾计算语言接口AscendCLAscendCL(Ascend Computing Language,昇腾计算语言)是昇腾计算开放编程框架,是对底层昇腾计算服务接口的封装,它提供运行时资源(例如设备、内存等)管理、模型加载与执行、算子加载与执行、图片数据编解码/裁剪/缩放处理等API库,实现在昇腾CANN平台上进行深度学习推理计算、图形图像预处理、单算子加速计算等能力。简单来说,就是统一的API框架,实现对所有资源的调用。AscendCL的优势如下:1.  高度抽象:算子编译、加载、执行的API归一,相比每个算子一个API,AscendCL大幅减少API数量,降低复杂度。2.  向后兼容:AscendCL具备向后兼容,确保软件升级后,基于旧版本编译的程序依然可以在新版本上运行。3.  零感知芯片:一套AscendCL接口可以实现应用代码统一,多款昇腾处理器无差异。AscendCL的主要应用场景如下:1.  开发应用:用户可以直接调用AscendCL提供的接口开发图片分类应用、目标识别应用等。2.  供第三方框架调用:用户可以通过第三方框架调用AscendCL接口,以便使用昇腾AI处理器的计算能力。3.  供第三方开发lib库:用户还可以使用AscendCL封装实现第三方lib库,以便提供昇腾AI处理器的运行管理、资源管理等能力。
  • [应用开发] CANN训练营2022年度第二季学习笔记:resnet50_firstapp演示
    首先将resnet50_firstapp放入云主机的/home/HwHiAiUser/sample目录下并su - HwHiAiUser切换至HwHiAiUser账户。在已经将文件赋予运行权限后,运行模型转化,将原始模型转换为昇腾AI处理器能识别的*.om模型文件。设置环境变量说明: 如果执行脚本报错“ModuleNotFoundError: No module named 'PIL'”,则表示缺少Pillow库,请使用 pip3 install Pillow --user 命令安装Pillow库。需要安装python3环境,apt-get install python3-pip编译,然后运行,获得正确推测结果
  • [其他] 使用OpenCV实现偏斜文档校正
    使用OpenCV实现偏斜文档校正纸质文档扫描中经常会发生扫描出来的图像有一定角度的偏斜,对后期的文档信息化OCR提取造成很大的干扰,导致OCR识别准确率下降从而影响文档信息化的结果。这个时候可以使用OpenCV对文档进行纠偏,最常见的文本纠偏算法有两种,分别是基于FFT变换以后频率域梯度基于离散点求最小外接轮廓这两种方法各有千秋,相对来说,第二种方法得到的结果更加准确,第一种基于离散傅立叶变换求振幅的方法有时候各种阈值选择在实际项目中会有很大问题。基于FFT变换以后频率域梯度主要思路是先把图像转换为灰度图像,然后使用离散傅立叶变换得到图像在频率域空间的振幅,对其二值化之后,使用霍夫直线检测得到角度,然后根据角度完成旋转校正。代码实现如下:Mat src = imread("D:/vcprojects/images/rotate_text.png"); Mat gray, binary; cvtColor(src, gray, COLOR_BGR2GRAY); //expand input image to optimal size Mat padded; int m = getOptimalDFTSize(gray.rows); int n = getOptimalDFTSize(gray.cols); // on the border add zero values copyMakeBorder(gray, padded, 0, m - gray.rows, 0, n - gray.cols, BORDER_CONSTANT, Scalar::all(0)); Mat planes[] = { Mat_(padded), Mat::zeros(padded.size(), CV_32F) }; Mat complexI; // Add to the expanded another plane with zeros merge(planes, 2, complexI); // 离散傅立叶变换 dft(complexI, complexI); // 实部与虚部得到梯度图像 // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I)) split(complexI, planes); magnitude(planes[0], planes[1], planes[0]); Mat magI = planes[0]; magI += Scalar::all(1); log(magI, magI); // crop the spectrum, if it has an odd number of rows or columns magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); // rearrange the quadrants of Fourier image so that the origin is at the image center int cx = magI.cols / 2; int cy = magI.rows / 2; Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right Mat tmp; // swap quadrants (Top-Left with Bottom-Right) q0.copyTo(tmp); q3.copyTo(q0); tmp.copyTo(q3); q1.copyTo(tmp); q2.copyTo(q1); tmp.copyTo(q2); // 归一化与阈值化显示 normalize(magI, magI, 0, 1.0, NORM_MINMAX); Mat dst; magI.convertTo(dst, CV_8UC1, 255, 0); threshold(dst, binary, 160, 255, THRESH_BINARY); // 霍夫直线 vector lines; Mat linImg = Mat::zeros(binary.size(), CV_8UC3); HoughLines(binary, lines, 1, (float)CV_PI / 180, 30, 0, 0); int numLines = lines.size(); float degree = 0.0; for (int l = 0; l { float rho = lines[l][0], theta = lines[l][1]; float offset = CV_PI / 12.0; if (abs(theta) > offset && abs(theta)< (CV_PI / 2.0- offset)) { printf("theta : %.2f ", theta); degree = (theta)*180-90; } Point pt1, pt2; double a = cos(theta), b = sin(theta); double x0 = a*rho, y0 = b*rho; pt1.x = cvRound(x0 + 1000 * (-b)); pt1.y = cvRound(y0 + 1000 * (a)); pt2.x = cvRound(x0 - 1000 * (-b)); pt2.y = cvRound(y0 - 1000 * (a)); line(linImg, pt1, pt2, Scalar(0, 255, 0), 3, 8, 0); } imshow("lines", linImg); // 旋转调整 Mat rot_mat = getRotationMatrix2D(Point(binary.cols/2, binary.rows/2), degree, 1); Mat rotated; warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255)); imshow("input", src); imshow("deskew-demo", rotated); imwrite("D:/deskew_text.png", rotated);基于离散点求最小外接轮廓其主要思路是先把图像二值化,得到一系列离散的前景像素点集合,然后利用轮廓的最小外接矩形函数,得到偏斜的矩形大小与角度,通过仿射变换完成校正。代码实现如下:Mat src = imread("D:/vcprojects/images/rotate_text.png"); Mat gray, binary; cvtColor(src, gray, COLOR_BGR2GRAY); threshold(gray, binary, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); imshow("binary", binary); imwrite("D:/binary_text.png", binary); vector points; findNonZero(binary, points); RotatedRect box = minAreaRect(points); double angle = box.angle; if (angle < -45.) angle += 90.; printf("angle : %.2f ", angle); Point2f vertices[4]; box.points(vertices); for (int i = 0; i < 4; ++i) line(src, vertices[i], vertices[(i + 1) % 4], Scalar(0, 0, 255), 2); imshow("box", src); imwrite("D:/box_text.png", src); Mat rot_mat = getRotationMatrix2D(box.center, angle, 1); Mat rotated; warpAffine(src, rotated, rot_mat, src.size(), cv::INTER_CUBIC, 0, Scalar(255, 255, 255)); //bitwise_not(rotated, rotated); imshow("deskew-demo", rotated);运行结果原图最小外接矩形校正之后转自公众号:小白学视觉
  • [其他] 稀疏奖励目标条件强化学习的阶段性自模仿约减
    利用监督学习(SL)的力量开发更有效的强化学习(RL)方法已经成为最近的一种趋势。为了解决稀疏奖励目标条件问题,我们提出了一种新的分阶段方法,即在线反馈学习和离线反馈学习交替进行。在在线阶段,我们执行RL训练并收集上线数据,而在离线阶段,我们对数据集中成功的轨迹执行SL。为了进一步提高样本效率,我们在在线阶段采用了额外的技术,包括减少任务生成更可行的轨迹和基于价值差异的内在奖励来缓解稀疏奖励问题。我们称这种整体算法为PhAsic自拟约简(PAIR)。在稀疏奖励目标条件机器人控制问题(包括具有挑战性的堆叠任务)上,PAIR大大优于非相位RL和相位SL基线。PAIR是第一个RL方法,它学习了从零开始堆叠6个立方体,只有0/1的成功奖励。https://www.zhuanzhi.ai/paper/007d9cb1ce12650d123764621e0b319d
  • [应用实践] 【课程作业经验】基于Mindspore框架和深度哈希的无人机遥感图像检索
    概述本文研究的主要内容主要是针对大规模图像检索问题,提出基于深度哈希的机器学习算法,实现快速高效的图像检索。同时,针对单标签下细粒度相似性缺失的问题,引入多标签下的相似性度量,关注图像对之间细粒度层面的相似情况,提高检索的精度。并且,将设计的算法在华为公司开发的MindSpore框架中实现,应用到无人机遥感图像的检索任务中去。整体的技术路线如图1所示。图1 技术路线项目地址cid:link_1相关配置操作系统Ubuntu Server 18.04 64bitCUDA10.1环境MindSpore-gpu 1.5.1语言Python 3.7MLRSNet数据集本文使用的数据集为公开的多标签数据集MLRSNet,它包含109161个高分辨率遥感图像,这些图像被注释为46个类别,并且该类别中的样本图像数量从1500到3000不等。但是由于使用的服务器等条件限制,最终实验时选取了部分数据进行试验,标签数目不变。图像的固定大小为256×256具有各种像素分辨率的像素。此外,数据集中的每个图像都标记有60个预定义的类别标签中的几个,并且与每个图像相关联的标签的数量从1到13不等,下表中列出了与每个预定义标签关联的数据集中存在的图像数量。图2 MLRSNet数据集数据集下载地址:cid:link_0实现流程记录1.工作流程基于图像检索问题的框架,下图3展示了用于监督哈希码学习的深度哈希网络的流程图。该方法以成对图像标签形式接受输入图像的标签和相似性度量,并通过卷积神经网络来提取图像的高级特征和输出哈希编码。使用的卷积神经网络使用多个卷积池化层来执行图像提取,全连接层来近似最优降维表示,哈希层来生成q位哈希码。在该模型中,引入了一种交叉熵损失和均方误差损失结合在一起的成对相似度损失来保持相似学习,以保持细粒度的成对相似度,并采用一个量化损失对紧凑哈希编码施加约束。图3 基于多标签的软成对相似性的深度哈希图像检索框架2.图像哈希码相似性度量多标签图像检索在一定程度上能够关注到图像对之间细粒度层面上的相似性,返回更为相似的图像。因此,在深度哈希算法的基础上,本文引入了新的相似度定义方法——“软相似性度量”与“硬相似性度量”,“硬相似性”相当于单标签场景,表示完全相似或者完全不相似;“软相似性”用于关注细粒度层面的相似性,定义为连续的实值,数值越大则相似性越低。本文中,成对相似度被量化成百分比,用以表示“软相似性度量”,相似度值定义为成对标签向量的余弦距离,计算公式如下。3.损失函数为了高效的近邻搜索,需要在汉明空间中保持原始图像的语义相似度。针对“软相似性度量”与“硬相似性度量”的不同情况,分别使用两种不同的损失函数,并在最后加上正则项,进行两者的联合学习。4.实验结果
  • [应用实践] 【课程作业经验】基于MindSpore框架的室内场景图像分割方法研究
    基于MindSpore框架的室内场景图像分割方法研究概述本文以华为最新国产深度学习框架Mindspore为基础,研究室内场景语义分割方法。本文基于注意力机制改进U-Net网络,并选取VGG16与ResNet50作为骨干网络,并且利用VGG16与ResNet50的预训练权重进行迁移学习。整体的技术路线如图1所示。 图1(技术路线图)项目地址cid:link_1相关配置名称配置信息NPUAscend910操作系统Ubuntu 20.04编译器Python3.7框架MindSpore1.6NYU-V2数据集本文利用公开数据集NYU-V2作为实验数据集,选取该数据集被标注的RGB图片用于训练和测试。作为常用的语义分割数据集,NYU-V2面向各种类型任务,选取的数据是由微软的 RGB摄像机记录的各种室内场景图片组成,其中共有464个不同的室内场景、1449张图片、894个类别标签。由于在NYU-V2数据集中,接近70%的数据集标签由前10类标签组成,所以本文选取该数据集室内场景的主要语义类别:墙壁(wall)、地板(floor)、橱柜(cabinet)、床(bed)、椅子(chair)、沙发(sofa)、桌子(table)、门(door)、窗户(window)、书柜(bookshelf)作为训练分割的语义类别,NYU-V2数据集中其他类别归为背景(background)类数据集下载地址:NYU Depth V2 « Nathan SilbermanNYU Depth V2 « Nathan Silberman实现流程记录1、基于U-Net网络实现室内场景语义分割模型U-Net是由Ronneberger 等人在2015年构建的一种完全对称的U型结构神经网络。参考华为官方gitee仓库的modelzoo克隆至本地,找到research/cv/unet目录,在此代码基础上进行修改。在原有U-Net模型的基础上,本文将输入图片的大小统一归为512×512,便于网络的卷积计算。本文实现的U-Net网络结构如图2所示。2、模型权重文件转换MindSpore采用ModelCheckpoint对象保存模型参数到CheckPoint文件(简称ckpt文件),由于MindSpore目前没有VGG16和ResNet50的相关预训练模型,导致本文在迁移学习的过程中无法直接使用MindSpore官方提供的预训练权重。PyTorch上采用pth文件保存模型参数且与MindSpore在保存模型参数的机制上不同,无法直接采用PyTorch上的预训练权重加载到MindSpore中。本文在查阅了MindSpore与PyTorch相关文档后,成功编写了将pth模型文件转换为ckpt模型文件的脚本。经过实际训练发现该脚本切实有效的解决了MindSpore中预训练模型缺失的问题。3、优化器的选择优化器运用在神经网络的反向传播中,通过引导损失函数的参数向正确的方向更新适当的大小,使得损失函数的值能够到达全局最优。其中最为重要的两个部分是优化方向和步长。本文选取Adam作为模型训练的优化器,Adam是SGD、AdsGrad等优化器的集大成者,能够有效控制学习率步长和梯度方向。本文由于运用到了迁移学习故将整个训练分为两个阶段。第一阶段冻结骨干网络预训练权重,将主要资源运用在扩张路径上,从而缩短训练时间,节约训练资源。第二阶段解冻骨干网络的参数,让网络中的所有参数参与训练。通过冻结训练后再解冻可以加快训练效率同时防止骨干网络的参数权值被破坏,从而获得更好的训练效果。结果展示图像的预测结果示例定量结果比较
  • [数据加载及处理] 【MindSpore易点通】数据处理经验总结
    多进程转MindRecord背景信息MindRecord数据在MindSpore中读取性能更优,推荐用户将其他格式的数据集转换为MindRecord格式。经验总结利用multiprocessing.Pool接口,实现多进程运行。将Cifar10图片格式数据集,转换成MindRecord格式,并进行性能对比。与单进程方式相比,多进程中需进行如下配置(具体差异详见代码附件):total_data_length = len(os.listdir(os.path.join(argv.data_define_path,                             argv.path)))part_num = math.ceil(total_data_length / argv.multi_num)left = total_data_length % part_numif left == 0:    left = part_numtotal_index_with_length = []for i in range(argv.multi_num - 1):    total_index_with_length.append([i * part_num, part_num])total_index_with_length.append([(argv.multi_num - 1) * part_num, left])pool_list = []for i, index_with_length in enumerate(total_index_with_length):    pool_list.append((argv, index_with_length[0], index_with_length[1], i))with Pool(processes=argv.multi_num) as pool:    pool.map(process_single_writer, pool_list)其中argv.multi_num为进程数;process_single_writer和单进程中的转换方式相同;pool_list为每个进程传入参数。注:当数据集较大时,推荐在训练环境中利用训练环境机器的本地SSD(开发环境中使用EFS会影响数据转换性能),并选用8卡规格进行转换(若选用1卡的规格,CPU/内存/SSD空间(一共3.3T) 都只会被分到1/8 )。需要注意的是8卡任务会起8次脚本导致重复转换,可以通过RANK_ID来控制,使仅有一个脚本正常执行;性能对比:多进程转MindRecord: 8886.35imgs/sec ; 单进程转MindRecord:2133.79imgs/sec一个Epoch最后一个Batch的数据不足背景信息一个Epoch的迭代次数=图片总数/Batch Size,如果不能整除,就会出现最后一个Batch的数据不足。目前如果Batch Size数据不足会报错。经验总结如果迭代一个Epoch的末尾训练报错结束,可以检查是否该问题导致的,可以通过如下配置规避drop_remainder=true代码示例如下:import mindspore.dataset as ds# data is an instance of Dataset object# declare an apply_func function which returns a Dataset objectdef apply_func(ds):    ds = ds.batch(2, drop_remainder=true)    return ds# use apply to call apply_funcdata = data.apply(apply_func)TFRecord数据读取背景信息TFRecord数据文件是一种将图像数据和标签统一存储的二进制文件,能更好的利用内存,在TensorFlow中快速的复制,移动,读取,存储等。经验总结TFRecord的读取FP32图片数据使用tostring保存为TFRecord,若直接使用TFRecordDataset读取为UINT8格式,而MindSpore中暂时缺少tf.decode_raw这样类似功能的算子,需要自己手动进行数据转化,转化代码如下:def trans_dtype(data, target):    trans_to_float32 = lambda x: np.frombuffer(np.ndarray.tobytes(x), dtype=np.float32)    input_size = 128    data = np.reshape(trans_to_float32(data), (input_size, input_size, 10))    target = np.reshape(trans_to_float32(target), (input_size, input_size, 10))    return data, targettfdataset = tfdataset.map(input_columns=['data', 'target'], operations=trans_dtype)自动生成Schema与预先定义Schema训练数据含有两批不同大小的数据(Key值不同),如A中包含{a,b,c}3种Key及其值,B种包含{a,b,c,d}4种Key及其值,目前训练任务中只需要两批数据中{a,b}2种Key及其值即可。 以读取TFRecord为例:DATA #A+Btfdataset = de.TFRecordDataset(dataset_files=DATA) # (1)DATA #B+Atfdataset = de.TFRecordDataset(dataset_files=DATA) # (2)以上两种写法中,(2)写法会报错。其关键在于DATA的构造,在读取数据过程中,如果不进行Schema的定义,MindSpore会在读取第一个数据的时候根据读取到的数据本身自行定义Schema。所以如果先读取B类数据,自动生成的Schema会包含{a,b,c,d}4个Key,而之后读取A类数据的时候得不到key=d的值,此时便会报错。所以较为恰当的做法是事先在程序中定义好Schema,如:DATA # B+A或A+Bschema = de.Schema()schema.add_column('a')schema.add_column('b')tfdataset = de.TFRecordDataset(dataset_files=DATA, schema=schema)NHWC到NCHW的转化数据读入时是NHWC的形式,需转化为NCHW的形式送入网络data = data.transpose(2,0,1)target = target.transpose(2,0,1) # (1)import mindspore.transforms.py_transforms as Ttransforms = T.ComposeOp([T.HWC2CHW()])tfdataset = tfdataset.map(input_columns='target', operations=())tfdataset = tfdataset.map(input_columns='data', operations=transforms()) # (2)得到的数据Shape是正确的,但是数据会被打乱,图片写出不正常;(2)使用T.HWC2CHW()则可以得到Shape正确数据顺序正确的图片,图片写出正常。MindData数据处理流程推荐顺序背景信息MindData包含的数据处理操作包括Repeat、Batch、Shuffle、Map和Zip,一般训练过程中都会用到Repeat、Batch、Shuffle和Map的操作。经验总结在实际使用过程中,需要组合使用这几个操作时,为达到最优性能,推荐按照如下顺序:数据集加载并shuffle -> Map -> Batch -> Repeat。 原因是shuffle操作需要填充足够数据之后才会往下走,如果是先Load和Map的话,Shuffle很容易受到Map的阻塞导致Pipeline无法并行处理。示例代码如下:import mindspore.dataset as dsimport mindspore.dataset.transforms.vision.py_transforms as transformsDATA_DIR = "custom_dataset_dir/"imagefolder_dataset = ds.ImageFolderDatasetV2(dataset_dir, shuffle=True)resize_op = transforms.Resize(size=(500,500))# map()dataset.map(input_columns="image", operations=resize_op)# batch()dataset = dataset.batch(32, drop_remainder=True)# repeat()dataset = dataset.repeat(10)数据分布式方式背景信息PyTorch的数据分布式方式是ddp(distributeddataparallel)或者dp(dataparallel),而MindSpore的数据分布式方式是ddp(distributeddataparallel)。经验总结内容dp和ddp的区别就是数据集是集中在一台机器还是分发到每台机器。差别是用户对batchsize的设置,如果是dp,batchsize=total_batchsize。如果是ddp,batchsize=per_gpu_batch。因此MindSpore的batchsize=per_gpu_batch。
  • [应用实践] 【MindSpore易点通】如何实现MindSpore与PyTorch模型文件相互转换
    MindSpore保存的模型文件转换为PyTorch中的模型文件输入 MindSpore的ckpt文件,以ResNet-18为例,MindSpore的网络结构和PyTorch保持一致,转完之后可直接加载进网络,这边参数只用到bn和conv2d,若有其他层MindSpore和PyTorch名称不一致,需要同样的修改名称。作用:方便和PyTorch训练结果对比如果不确定自己训练的结果是不是正确(MindSpore的前向目前可能存在问题),可转到PyTorch上跑前向看看转换脚本:from mindspore.train.serialization import load_checkpointimport torchdef mindspore2pytorch(ckpt_name='res18_ms.ckpt'):    par_dict = load_checkpoint(ckpt_name)    state_dict = {}    state_dict_useless = ['global_step', 'learning_rate', 'beta1_power', 'beta2_power']    for name in par_dict:        parameter = par_dict[name].data        if name in state_dict_useless or name.startswith('moment1.') or name.startswith('moment2.'):            pass        else:            print('========================ms_name:', name )            if name.endswith('.beta'):                name = name[:name.rfind('.beta')]                name = name + '.bias'            elif name.endswith('.gamma'):                name = name[:name.rfind('.gamma')]                name = name + '.weight'            elif name.endswith('.moving_mean'):                name = name[:name.rfind('.moving_mean')]                name = name + '.running_mean'            elif name.endswith('.moving_variance'):                name = name[:name.rfind('.moving_variance')]                name = name + '.running_var'            print('========================py_name:', name )            state_dict[name] = torch.from_numpy(parameter.asnumpy())  ###torch.save({'state_dict' : state_dict}, 'res18_py.pth')PyTorch保存的模型文件转换为MindSpore中的模型文件输入 PyTorch的pth文件,以ResNet-18为例,MindSpore的网络结构和PyTorch保持一致,转完之后可直接加载进网络,这边参数只用到BN和Conv2D,若有其他层MindSpore和PyTorch名称不一致,需要同样的修改名称。作用:有的网络训练的时候必须加载一些预训练权重,将PyTorch的预训练权重转到MindSpore支持的格式。转换脚本:from mindspore.train.serialization import save_checkpointfrom mindspore import Tensorimport torchdef pytorch2mindspore(ckpt_name='res18_py.pth'):    par_dict = torch.load(ckpt_name, map_location=torch.device('cpu'))    new_params_list = []    for name in par_dict:        param_dict = {}        parameter = par_dict[name]        print('========================py_name',name)        if name.endswith('normalize.bias'):            name = name[:name.rfind('normalize.bias')]            name = name + 'normalize.beta'        elif name.endswith('normalize.weight'):            name = name[:name.rfind('normalize.weight')]            name = name + 'normalize.gamma'        elif name.endswith('.running_mean'):            name = name[:name.rfind('.running_mean')]            name = name + '.moving_mean'        elif name.endswith('.running_var'):            name = name[:name.rfind('.running_var')]            name = name + '.moving_variance'        print('========================ms_name',name)        param_dict['name'] = name        param_dict['data'] = Tensor(parameter.numpy())        new_params_list.append(param_dict)    save_checkpoint(new_params_list,  'res18_ms.ckpt')详细代码内容请见附件
  • [调优经验] 【MindSpore易点通】精度调测经验总结
    问题一开发人员在多张网络使用dropout算子时,dropout算子中seed1值会有变化,可能会导致产生调试精度差异。创建简单示例import numpy as npimport mindspore.ops as opsfrom mindspore import Tensor, contextfrom mindspore.ops import operations as Pimport mindspore.nn as nnimport mindspore#保存数据context.set_context(mode=context.GRAPH_MODE, device_target="Ascend")class PrintDemo1(nn.Cell):        def __init__(self):            super(PrintDemo1, self).__init__()            self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=4, stride=1 ,has_bias=False, weight_init='normal', pad_mode='valid')            self.conv2 = nn.Conv2d(in_channels=6, out_channels=2, kernel_size=2, pad_mode="valid")            self.conv3 = nn.Conv2d(in_channels=2, out_channels=6, kernel_size=2, pad_mode="valid")            self.dropout = nn.Dropout(keep_prob=0.6)                def construct(self, input_data):            x = self.conv1(input_data)            x = self.dropout(x)            x = self.conv2(x)            x = self.conv3(x)             return x class PrintDemo2(nn.Cell):        def __init__(self):            super(PrintDemo2, self).__init__()            self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=4, stride=1 ,has_bias=False, weight_init='normal', pad_mode='valid')            self.conv2 = nn.Conv2d(in_channels=6, out_channels=2, kernel_size=2, pad_mode="valid")            self.conv3 = nn.Conv2d(in_channels=2, out_channels=6, kernel_size=2, pad_mode="valid")         self.dropout = nn.Dropout(keep_prob=0.6)        def construct(self, input_data):            x = self.conv1(input_data)            x = self.dropout(x)            x = self.conv2(x)            x = self.conv3(x)             return xmindspore.set_seed(123)def test():    input_data = Tensor(np.ones([1, 1, 32, 32]), mindspore.float32)    net1 = PrintDemo1()    net2 = PrintDemo2()    net1(input_data)    net2(input_data)    return net1(input_data), net2(input_data)test()代码分析在以上示例代码中我们设置了一个全局seed=123,nn.Dropout源码中打印dropout中seed0与seed1,发现两次打印出seed0一致,而seed1有变化,具体打印结果如下图:问题二BN中的moving_mean和moving_variance不更新。经验总结内容在网络定义之后要加上set_train(),加上之后bn为训练模式才会更新moving_mean和moving_variance。示例如下:backbone = get_backbone(args)criterion = get_loss(args)train_net = BuildTrainNetwork(network, criterion, args)train_net.set_train()问题三MindData数据预处理中有用到c_transforms.Resize,该算子实现与torch_transforms.Resize实现不一致。经验总结内容MindData的第三方库和PyTorch的第三方库不一样(MindData使用的是OpenCV),因此c_transforms.Resize和torch_transforms.Resize的输出相比有点误差是正常的,不影响使用。问题四DUMP_train图没有某些算子的数据,因此网络进行精度调测的时候,经常要查看DUMP图中的算子信息。经验总结内容该问题可能是算子名过长导致的(算子名通过网络的脚本定义类名嵌套组合而成),需要设置如下参数:context.set_context(reserve_class_name_in_scope=False)详细代码信息请参考附件文件。
  • [特性分析] 【MindSpore易点通】如何根据profiler数据查看性能瓶颈
    MindInsight主要功能介绍MindInsight详细功能介绍请参考MindInsight性能调试。MindInsight主页面包括主要功能的概览信息:迭代轨迹、算子耗时统计、数据准备、时间线、调优助手。迭代轨迹:展示了每个迭代各个阶段的性能信息:包括迭代间隙、前向反向、迭代拖尾以及每个all_reduce的信息。下方展示各个阶段的变化趋势。算子耗时统计:通过类型、详细信息两个维度展示AICORE和AICPU算子耗时统计信息。数据准备:性能分析分为两部分:1、迭代间隙数据处理分析;2、数据处理pipeline分析。迭代间隙阶段:下图展示了迭代间隙阶段执行的操作的流程,通过分析队列中数据的情况判断出现性能问题的步骤。数据处理阶段:分析用于已经定位到了该阶段的问题时,定位其中哪个算子存在问题,通过各个算子之间的队列的使用率,判断前面的算子能否提供足够的数据到队列中供下一个算子使用。时间线:展示了算子在各个stream上的起止时刻,执行顺序、算子间隙、allreduce信息,从详细的粒度展示算子执行情况。用户可参考下图,进行算子分析(常用的为MindData阶段分析和算子性能分析)。案例问题分析问题1:迭代间隙过长通过迭代轨迹发现,迭代间隙过长:问题分析1.迭代间隙过长,通常因为数据处理过程导致,进入数据处理阶段分析。2.主机队列几乎为空,判定是数据处理算子问题,进入数据处理pipeline查看具体问题。3.当算子左边连接的Queue使用率都比较高,右边连接的Queue使用率比较低时,该算子可能是性能瓶颈:图中红框内数据可以看出,map操作过程中的队列使用率高,而右边连接的队列使用率较低,判断map中的数据处理过程存在性能瓶颈。4.分析map中数据处理相关代码:发现数据处理进程数为默认值1,可以尝试调整数据处理进程数。5.分析map中数据处理相关代码:发现存在c_transform和py_transform混用的问题,降低了训练性能。措施1:调整数据处理进程数调整数据处理进程数为8:if do_train:    cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home,                         num_parallel_workers=8, shuffle=True, usage='train')else:    cifar_ds = ds.Cifar10Dataset(dataset_dir=data_home,                         num_parallel_workers=8, shuffle=False, usage='test')cifar_ds = cifar_ds.map(operations=transform_label, num_parallel_workers=8, python_multiprocessing=True, input_columns="label")cifar_ds = cifar_ds.map(operations=transform_data, num_parallel_workers=8, python_multiprocessing=True, python_multiprocessing=True, input_columns="image")cifar_ds = cifar_ds.batch(batch_size, num_parallel_workers=8, drop_remainder=True)修改后,重新训练,将训练后代码继续做profiling,发现迭代间隙明显缩短。性能对比: 改进前:1100imgs/sec 改进后: 2150imgs/sec措施2:避免c_transform和py_transform混用数据处理过程中发现存在c_transform和py_transform混用的情况:if do_train:    # Transformation on train datatransform_data = py_trans.Compose([            CV.RandomCrop((32, 32), (4, 4, 4, 4)),            py_vision.ToPIL(),            py_vision.RandomHorizontalFlip(),            CV.Rescale(rescale, shift),            CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),            CV.HWC2CHW()            ])else:    # Transformation on validation data    transform_data = py_trans.Compose([            CV.Rescale(rescale, shift),            CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),            CV.HWC2CHW()            ])          cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")将数据处理过程中代码进行如下修改:if do_train:        # Transformation on train data        transform_data = C.Compose([            CV.RandomCrop((32, 32), (4, 4, 4, 4)),            CV.RandomHorizontalFlip(),            CV.Rescale(rescale, shift),            CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),            CV.HWC2CHW()])    else:        # Transformation on validation data        transform_data = C.Compose([            CV.Rescale(rescale, shift),            CV.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),            CV.HWC2CHW()])cifar_ds = cifar_ds.map(operations=transform_data, input_columns="image")修改后,重新训练,将训练后代码继续做profiling。迭代间隙有所缩短。性能对比: 改进前:2150imgs/sec 改进后: 2250imgs/sec经过这两步优化,迭代间隙由原来的77.5027ms减少到17.0623ms,有明显改善。问题2:数据队列为空继续分析优化后的Profiler数据,发现数据准备中的主机队列几乎为空:问题分析进入数据处理pipeline查看具体问题。2.如红框所示,数据处理过程中的队列使用率高。对于最右侧的算子,如果其左边所有Queue的使用率都比较高,该算子可能是性能瓶颈。而此处最右侧算子为框架自动插入算子,因此判断数据下发存在性能瓶颈,应提升数据从Host传输到Device的速度。措施3:采用数据下沉模式采用数据下沉模式,实现整图下沉到Device执行,避免Host-Device频繁交互,减小了数据传输开销。将Model.train接口中dataset_sink_mode值设为True,即可采用数据下沉模式。model.train(..., dataset_sink_mode=True, sink_size=steps_per_epoch_train)修改后,重新训练,将训练后代码继续做profiling,发现主机队列为空比例大大下降。数据处理过程中的队列使用率明显降低。性能对比: 改进前:2250imgs/sec 改进后: 2350imgs/sec问题3:前向+反向时间较长继续分析优化后的Profiler数据,由迭代轨迹看出,前反向时间相对较长,可能存在优化空间:措施4:使用混合精度使用混合精度可以加速训练,减少前反向时间。修改高阶API代码中的Model接口,将amp_level设置成"O3",网络将采用FP16进行训练。net = Model(net, loss, opt, metrics=metrics, amp_level="O3")修改后,重新训练,将训练后代码继续做profiling。发现前反向时间明显减少。性能对比: 改进前:2350imgs/sec 改进后: 3500imgs/sec经过以上优化,训练性能得到明显提升。由初始的1100imgs/sec,改进到3500imgs/sec。详细代码请参考附件文件。