我的NVIDIA开发者之旅—使用NVIDIA TAO和NEMO开发AI应用的埋坑经验

小梦同学 2022-06-14 14:03:52
加精

"我的NVIDIA开发者之旅” | 征文活动进行中.......

比赛结果

从5月20开始到6月12落下帷幕,持续三周比赛完成了ASR、目标检测、TTS三个部分,最终总成绩第一名。

结果上的第一是机缘巧合,中间收到了其他队伍的无私帮助,也有组内成员的配合,并不是自身能力的突出。

比赛感受

比赛整体侧重于神经网络算法的流程、实际的应用。

从一开始的数据收集、清理、标注,到中期的算法选择、训练,后期的模型部署、使用。体验上来说还上非常好的。

经验总结

这里分成多个内容进行总结

数据收集与处理

数据收集要考虑数来源、数据量大小、数据质量,三个方面

这里按照ASR、TTS、目标检测三个方向进行总结,插入 Nemo 和 Tao 的简单介绍。

ASR部分

对于ASR与TTS,比赛中均被指定使用Nemo作为训练框架,它是Nvidia设计的主要用于NLP方向的一个框架。

其中ASR部分,由于可以在NGC上搜索预训练模型使用,所以数据量大小并不需要很大,在周围人之间进行一些小范围的数据收集即可达到比赛使用要求。(即:数据量小、来源为自行收集,足以)

ASR作为语音识别,应该有较好的鲁棒性,所以在收集到的数据之中,只要保证人耳可以清晰听出指定内容即可作为有效的训练数据,无论预训练模型如何识别。

在比赛过程中,自行收集了大概50条数据,其中30多条来自不同的人,剩余十多条来自队内成员录制。语音内容均为:“你好大白请让我进入小区”。并且和无辑队交换了拥有的数据集,最终使用训练的大概有七十条左右。

TTS部分

TTS部分虽然也是使用Nemo作为训练框架,但是问题在于他并没有提供中文的预训练模型,也就是需要我们进行从头训练。

根据比赛要求,其录制内容为:“您好,xxx,欢迎回家,二维码有效请您通过。”,中间xxx部分表示一个人名。

由于语句内容单一,除人名部分以外均为固定内容,所以考虑数据量依然较小(五十条以内),加上轮次训练足够。所以数据来源依然可以为人工录制。

同时考虑TTS为文本转声音,即让机器提取每个字对应的声音特征频谱,以便于将文字化作对应的频谱,所以数据集内噪声应该尽可能消除、不必要静音片段也应该尽量短、说话内容应该尽量的标准,尽可能的减少模型学习时候的干扰。----与ASR部分相反。

确定如上规则后,寻求播音专业朋友帮忙录音50条,其中包含‘上午好’、‘下午好’、’中午好‘,和五十个不同的人名,发音标准,码率标准,无底噪,人工去除头尾静音片段后尝试用于训练。

但是由于人名和问好并没有和后面的‘欢迎回家,二维码有效请通过’进行分离,导致最终合成的频谱在人名部分产生了极大混乱,结果无效。

这里要提一个同样是人工录制的对比:打鲁班不加班队人工录制了一句话‘你好,小鲁班,欢迎回家,二维码有效请通过’,大概200多条,进行了足量训练。生成之后MOS效果极佳,pesq也还不错。(感谢打鲁班不加班队无私的回复,因为我去求教的时候比赛并没有结束)

同时,除人工录制以外的其他数据来源包括:开源数据集(AIShell2、AIShell3等)、AI开放平台合成TTS(再次感谢无辑队长的帮助)。

开源数据集的问题在于:不够具有针对性,训练面向的是整个中文语言环境,而且存在音色众多、声音质量低下,数据量过大等问题。

这三个问题带来的后果分别是:合成声音过于奇怪、合成之后噪声清晰、训练所需时间大大增加(无论是单轮时间,还是需要的总轮次,都大大增加)。

所以Hackthon比赛中TTS部分应该放弃开源数据集的使用,接下来分析AI开放平台TTS合成。

AI开放平台合成会有两个显而易见的问题:

  • 码率不够,平台提供的采样率最高可达16k,远远不足比赛要求的41.4k
  • 内容单一,虽然模型发声依然带有一定的随机性,但是相比于人工录制而言,随机性大大降低,如果只有一句话,可用数据集极少,仅有三五句。

问题一是用ffmpeg脚本批量转化完成,指定输出码率和声道。下方是比赛中使用的脚本。

import os
from tqdm import tqdm

input_dir = "asr_data_1"
output_dir = "asr_data"

video_list = os.listdir(input_dir)
os.makedirs(output_dir, exist_ok=True)

for video_name in tqdm(video_list):
    os.system("ffmpeg -y -i %s/%s  -ac 1 -ar 44100  %s/%s" % (input_dir, video_name, output_dir, video_name))

问题二是通过分词分句配合多音色采集完成的。

其中分词分句指的是将‘你好,小叮当,欢迎回家,二维码有效请通过’拆解为‘你好’、‘小叮当’,‘欢迎回家’,‘二维码有效请通过’,这样连带本身的句子共有五句话。

同时腾讯拥有多个音色,女性大概29个可用音色,最终可得29*5=145个句子用以训练。

至此TTS数据集完成。

目标检测数据集

关于目标检测,本次比赛要求是否戴口罩,在比赛之前我们想过人工拍照获得数据集,但是考虑人数和实际情况,数据量太小,难以达到训练要求,所以采用网络收集。

主要使用的数据收集网站包括:Baidu、Google、PaperWithCodeRoboflow(这里还要感谢无辑队长,是他分享给我这个网站)。

先后获取大概共计8000张图片的数据和标注信息。主要分类为戴口罩和不戴口罩。

随后使用labelImg对数据集进行重新标注,对第三类(戴口罩不标准)进行标注。标注完成后由于第三类标签过少,所以存在严重的数据标签不均衡的问题,于是在Roboflow上收集到了数据集Mask22,大概一千余张原本数据。

同时使用网站带有的增强功能,对两个数据集均进行相当的效果增强。

另外,比赛提供的原本数据集应该是来自于kaggle的数据集Face Mask Detection

收集的两个数据集均包含该数据集图片。 目标检测部分数据集结束。

模型训练与验证

模型训练不拆分模块,不深入原理,简单讲一些经验or教训。

另外感谢比赛流程,环境顺利的情况下,是可以直接一路Run到结尾的。

Batch_Size

batch_size指的是每次训练要为给模型多少内容,例如batch_size = 4表示全部数据按4个一组喂给模型,batch_size越大,要求的显存越大,但是并非batch_size越大,学习效果越好。

跟李沐学AI中有提到batch_zie小的情况下,可能模型泛化性能越好,因为噪声相对更高。

Epoch

Epoch讲的是全部数据走多少轮,在本次比赛中,ASR模型300epoch,TTS为6000epoch,CV为300epoch,其中TTS为从头训练+提高pesq分数,所以略高。Epoch越高,所需时间越长。

训练常见问题

  • CUDA out of memory 显存溢出

    显存较低的时候会出现的问题,降低batch_size属于常见解决方案,显存过低的时候可能batch_size = 1也无法解决,建议使用云服务或者更换显卡。

  • loss不停震荡,幅度很大

    正常现象,看到某次loss很低可能是在局部最优,加大力度继续训练。

  • loss已经是0啦,担心过拟合

    过拟合不是很容易的事情,几十个Epoch并不会让他过拟合,可以关注准确率有没有继续提高,如果还在提高就继续训练!

  • 其他问题排错思路

    • 定位关键节点

      绝大部分报错信息属于堆栈信息,是告诉你程序在调用执行哪一句的时候产生的问题,找到最关键的那么一两句话,可以提高排错速度,例如 xxxx is not file or dir基本是说文件不存在, Cuda out of memory表明显存溢出。

    • 多用搜索引擎

      你遇到的绝大部分问题,别人也遇到了,所以先搜索一般结果会更快。

    • 加入自己的思考

      一个报错可能是有多个原因的,同样是文件读取,可能是因为文件格式、文件编码、文件路径、文件内容多个方面的读取错误,在搜索的同时,分析他们的解决方案是为了什么,是否适合你当前的情况,多次尝试即可。

    • 该问就问

      自己不能解决的问题,就大胆的去问,讲清楚自己的问题,自己的努力,带上明确的截图和问题的描述,你不能解决的问题对别人而言可能只是一句话的事情,但是一定一定一定把问题描述清楚

验证常见问题

  • TTS合成噪声太大

    检查数据集,采样率是否标准,底噪是否过大,干扰到正常训练,发音是否标准、清晰。数据量是否足够(只有一条是不行的哦)。

    提高训练轮次。

  • 目标检测时loss不提高

    降低 batch_size 的情况下,一定要增加 epoch 来保证训练的效果。

  • mAP指数较低

    提高数据集质量,检查是否有错误标注或者标注不均衡的问题,不均衡的情况下,数量少的标签学习起来更慢,拉低整体mAP。

  • 训练时中断

    TTS目前我不知道恢复训练的方法,只能从头训练,但是如果训练轮次已经差不多了,可以使用restore_from方法加载 ckpt 文件,保存成为 nemo 文件。

    CV训练时官方使用的 Nviia-Tao 提供了继续训练的方法,继续训练即可。使用其他模型,如yolov或者yolo-x都可以加载权重文件继续训练。

关于Nemo

Nemo 是 Nvidia 提供的一个关于 NLP 的神经网络功能包,可以很方便的加载模型、调用算法、进行训练、和部署使用。

可以将 Nemo 视为对 Pytorch 的进一步封装,更多内容可以看 Nemo 的 GitHub:NeMo

目前最新版本是1.8.0,比赛使用1.4.0,可以在 GitHub 中选择1.4.0的 TAG来查看。

同时搭配 NGC 网站选择各种预训练模型。

关于Tao

这个东西其实我并没有用很多,但是在比赛过程中遇到了很多问题,所以这里来重点解释几个常见问题(所有问题答案均来自自己理解,可能存在谬误):

  • Tao

    tao 本身应该是使用 nvidia-docker 来进行一系列的算法模型训练的,在不同的镜像内部存在着不同的算法模型,所以可以看见命令单元格内 tao ssd 表明使用 tao 运行 ssd 算法。同理,可以使用tao yolo_v3来使用 tao 运行 yolov3 算法。

    可以说,tao 极大简化了 nvidia-docker 的使用,简化了开发人员的操作难度,提高了整体的效率。

    • 题外话: docker 与 nvidia-docker

      docker最常被提及的说法是:一个容器,可以按照虚拟机镜像的思路去理解,大家使用 docker image 来管理不同的虚拟机镜像,在镜像的内部自成一套的环境,包括但不限于操作系统版本、 python 版本、 nvidia 驱动版本、 cmake 版本等等。

      关于 nvidia-docker 我知道的并不多,但是应该是更好的支持了 nvidia 的驱动,支持在 docker 内使用显卡。 另外使用的时候可能需要使用指令登陆 ngc。

  • 路径映射

    在上一步的基础上,我们已经知道, tao 就是一个套着皮的 docker 控制器,那么路径映射其实就的 docker 的 -v 参数,使用 -v 参数指定的两个文件夹,可以视为同一个文件夹。对 A 文件夹进行的修改会同步修改到对 B 文件夹,反之依然。

    这是本次比赛在目标检测部分最大的拦路虎,很多报错都是由于路径映射配置出错。

  • NGC

    前面已经说过,使用 nvidia-docker 需要登陆,可使用以下命令登陆 NGC:

    sudo docker login -u '$oauthtoken' --password-stdin nvcr.io <<<"Key"
    

    其中 key 需要登陆 NGC网站。

    但是使用指令登陆之后可能依然会被提示未登录的问题。可能原因有三个:

    • 登陆后的配置文件和运行 tao 时候默认读取的配置文件位置不一

      可以采用强制移动方式解决

    • 配置文件及所在文件夹权限要求较高,无法完成指令

      使用 sudo 运行指令,或者使用 chmod 修改文件夹权限

    • 依然报错权限问题

      sudo chmod 666 /var/run/docker.sock
      

      这个我并不理解为什么,所以这里主要放出解决方案,有问题欢迎讨论。

上述内容基本可以解决对 tao 对理解问题和基本的使用问题。

模型部署

模型部署部分基本上是使用其他人提供的仓库、代码等,纯纯一个快乐调包人。

所以以下均为一家之谈,可能用处不大。

推荐阅读

感谢无辑队长(是的还是他)提供的视频链接,干货满满:详解TensorRT的C++/Python高性能部署,实战应用到项目

一个高星的 GitHub 项目,欢迎大家阅读代码:tensorrtx

官方TRT仓库:TensorRT,内有官方 plugin。

官方 TensorRT 教程视频:TensorRT 教程 | 基于 8.2.3 版本

网络可视化工具:Netron

权重文件->ONNX->engine

再次提醒,以下部分是个人理解,一定存在偏颇,请更关注官方文档内容。

所有算法模型最后都会生成一个模型文件,后缀不一,但是保存的内容可能是比较类似的,那就是执行该算法的流程,和每个流程上的权重,比如卷积之后使用哪个激活函数,又或者每个卷积操作不同的权重,或是对数据切分,整理等等。

其中每个步骤,都可以成为一个算子,不同的文件支持的算子多少,算子内容都是不一样的。

ONNX 作为最常见的导出模型,支持的算子可能并不算很多,但是通过各种组合,能实现基本所有的操作。生成成为 Onnx 文件后,该模型文件就可以在任意平台上使用,实现了通用性的可能。

而 TensorRT 则不同。 TensorRT 支持导入模型文件,并输出 engine 文件( TRT 输出的其实是二进制文件,常见以 .engine .bin .plan 等结尾)。同时该文件只支持在一台,或者说硬件和驱动相同的一类设备上运行,如果使用不同的硬件,则会不可知的错误。模型变成了独一无二的专属情况。

举例来说,读取 Onnx 很简单,可以在任意平台上,而读取 engine 文件,则生成 engine 文件的硬件环境和驱动环境应该与使用 engine 文件的硬件关键和驱动环境完全一致。

为什么?

根据我的理解,首先 Onnx 支持的算子少,为了实现最终的效果, Onnx 生成过程中会出现大量的复杂的算子过程,其中有些可能是不必要的,或者可替代的。这部分可以通过修改 Onnx 的文件,或者修改模型导出时参数来解决。

而另外一个角度来讲,获得通用性必然会有一定牺牲, Onnx支持的算子一直不多,而TRT支持的算子更多,而且随着版本更迭,在不断增加,那么某些低级算子就可以被替换成为更高级的算法块。

另外TRT会根据当前硬件情况和驱动器,组合模型中的算子操作,优化计算逻辑和过程,不同的硬件和驱动下,可以使用的工具也不一而同,所以在不同机器上无法使用 engine 文件也是情有可原的。

比赛情况

比赛过程中,并没有使用 TAO 生成 bin 文件,所以这里简单说一下需要注意的情况,由 Tao 训练的模型,是带有 key 的,所以中生成 bin 文件的时候应该注意 key 是否对的上。

如果一开始 key 输错了,要注意清理缓存。其他我就不知道了。

环境问题

本次比赛出现了大量环境问题,除了双系统以外,Linux操作不熟也是很大问题。在这里对常见命令和简单问题进行一次总结。

常见命令:

  • sudo 提权,将普通用户权限提高至 root 用户
  • cd xxx 进入指定的文件夹
  • ls 展示当前文件夹下所有文件
  • mkdir 创建文件夹
  • chmod 修改文件读写权限
  • mv a b 将a文件移动到b
  • rm 删除文件(在linux中谨慎使用,更多使用mv替代。)
  • top 查看进程、磁盘、cpu的使用情况
  • nvidia-smi 查看 gpu 使用情况
  • kill 杀死进程,搭配 top 命令获取到的 pid 使用。

以上所有命令均有额外参数,自行搜索获取更多指令

常见问题

  • ffmpeg下载失败

    需要更换 ubuntu 的下载镜像,具体可以自行搜索国内阿里源、网易源。

    修改配置文件后执行sudo apt-get update,更新一下源文件即可。

    注意updateupgrade 的区别,前者是更新你的仓库文件列表,告诉系统可以下载哪些文件,可以去哪里下载这些文件;后者表示升级一下 apt-get 软件。

  • from ruamel.yaml import YAML 报错

    使用 import yaml 替换

  • 报错:TypeError:_run_hydra() missing 1 required positional argument:args

    运行pip install hydra_core==1.1.1

  • jupyter长时间没反应,卡住了好像。

    首先检查你运行的 cell 前面的中括号内是 * 还是一个数字,如果是 * 表示程序正在运行,安静等待即可。如果是数字,表示运行结束。

    运行结束和预计反馈不一致,使用 top 查看一下是否存在异常进程, 检查 log 日志是否存在报错, 使用 nvidia-smi 查看显存占用等进行错误排查。

  • jupyter运行缓存

    要注意,juypter运行时会保存之前的结果的,按照你的点击顺序, cell 左侧的数字,表明当前 cell 是第几个运行的,所以应该养成定时重启 kernel 的习惯,避免环境紊乱导致结果不符合预期。

    总结

sky hackthon 的比赛侧重于算法部署的一整个的流程,配合指导老师和活跃的气氛组,整体比赛氛围非常轻松愉快,认真准备克服困难完成比赛是一定可以的!

本次比赛学到了相当多的内容,对于AI的认识了解更进一步,依然有很多地方可以思考,可以进步。

这个总结整体而言是想到哪里写到哪里,所以可能比较乱,也有些地方没写到,欢迎继续讨论。

...全文
659 8 打赏 收藏 举报
写回复
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
kaituozhizzz 2022-06-15
  • 打赏
  • 举报
回复
好文章 三连了
gloomyfish 2022-06-14
  • 打赏
  • 举报
回复

绝对干货!发至肺腑!受益匪浅!

小梦同学 2022-06-14
  • 举报
回复
@gloomyfish 感谢您的肯定!
锌a 2022-06-14
  • 打赏
  • 举报
回复

nbnb

扫地的小何尚 2022-06-14
  • 打赏
  • 举报
回复 4

手动点赞+关注

小梦同学 2022-06-14
  • 举报
回复
@扫地的小何尚 哇!何老师好!感谢何老师和YiPeng老师在比赛当中对我和我的学弟们热情的帮助!
The_Dark_Shark 2022-06-14
  • 打赏
  • 举报
回复 1

小梦写东西好详细。

小梦同学 2022-06-14
  • 举报
回复 1
@The_Dark_Shark 想着给学弟们打打底子,就把想到的都写上去了。有用没用都写了。
发帖
NVIDIA 企业开发者社区

972

社区成员

NVIDIA 开发者技术交流
人工智能 企业社区
社区管理员
  • nvdev
  • GayeZ
  • 活动通知
加入社区
帖子事件
编辑了帖子 (查看)
2022-06-14 15:39
编辑了帖子 (查看)
2022-06-14 14:29
创建了帖子
2022-06-14 14:03