人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码

JulianaVivien 发布于3月前

现在,AIZOO开源 PyTorch、TensorFlow、MXNet、Keras和Caffe 五大主流深度学习框架的人脸检测模型和代码啦!先附上Github链接。

https://github.com/AIZOOTech/FaceMaskDetection ​ github.com

前两天,AIZOO开源的近8000张人脸口罩数据和模型,得到了很多朋友的积极反馈,也有很多朋友留言赞赏我们的开源精神。其中一位粉丝朋友说:“公开这么多数据,你好无私啊”,一句话,瞬间让元峰标注数据的痛苦烟消云散了。

但是,笔者开源的是Keras和Caffe版本,有更多的朋友发消息告诉我说,如果开源PyTorch版本就好了,毕竟,PyTorch是当今科研圈最流行的深度学习框架了。还有粉丝朋友私信元峰要TensorFlow版本。对此,元峰让明星范伟替我回答一下,请看下面小视频。

人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码 送水工-人脸检测 https://www.zhihu.com/video/1215078014347993088

对于人脸口罩检测模型和数据的基本说明,因为前文已经做了介绍,这里不再额外赘述,有需要的朋友请阅读AIZOO周三发表的这篇文章。

AIZOO开源人脸口罩检测数据+模型+代码+在线网页体验,通通都开源了 ​ mp.weixin.qq.com 人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码

本文,我们重点介绍一下各大深度学习框架之间的转换方法,尤其是目标检测模型如何互转。

一. 模型转换工具介绍

这都2020年了,深度学习也经历了八年的蓬勃发展。这八年,深度学习可以说是人工智能领域最璀璨的一颗明星。过去的近十年,有众多的深度学习框架诞生——Torch、Theao、Caffe、TensorFlow、Keras、MXNet、PyTorch、CNTK、Chainer、Deepleaning4Java以及百度的PaddlePaddle等,可以说这些优秀的框架极大的方便了学者和工程师进行学术研究以及工业实现,也极大的促进了AI领域的发展,对此,我们应该向这些发布框架的作者们说一声致谢。

不过,深度学习经过这几年的发展和沉淀,深度学习框架的头部聚集效应越来越明显。Theano和Caffe在发布1.0版本后便停止了官方更新,Chainer母公司在2019年12月宣布转向PyTorch,MXNet虽然拥有李沐等大神,背靠Amazon大山,但一直不温不火;百度的Paddle最近仍然在顽强的挣扎,疯狂的做推广,大有一副“扶我起来,我还能战”的态势。而曾经一时风头无两的TensorFlow,也在自己的作死中渐失人心(主要是1.x版本的时候API太过混乱,仅一个conv2d,在slim、tf.layers、tf.contrib、tf.nn中参数名字和风格都很不一样)。当然,因为TensoFlow对Linux、Windows、安卓、iOS、嵌入式和JavaScript都有很好的支持,所以还是工业界应用非常广泛的一个框架,我们的官网 http:// AIZOO.com 里面的算法,都是使用TensorFlow.js做的。

目前,学术界越来越倾向于使用小清新PyTorch了。这也是为什么元峰开源Keras和Caffe的模型后,不少学术界的朋友找我要PyTorch模型了。至于为什么当今PyTorch和TensorFlow逐渐成双雄鼎力之势,我想有一大原因是深度学习的基础构成,例如卷积、池化、BatchNorm等基本部件已经基本定型,各大框架都提供基本相同的功能,这时候,就是谁的代码风格和易用性更优,谁就更容易胜出了。基本相同的部件功能,带来一个益处就是我们使用一个框架训练好后,可以较为方便的转为其他框架的模型。元峰是用Keras训练的模型,但是可以无误差的转成了Caffe、TensorFlow、PyTorch、MXNet模型。

模型转换,其实本质上就是从原模型里面读取拓扑结构和权重,使用目标框架构建同样的拓扑结构,并把权重赋值给新构建的网络,这样,使用目标框架构建的模型就可以与原模型具有一样的输出值。

一个非常好用的模型转换工具是微软亚洲研究院开源的MMdnn,其基本的原理是将所有不同的框架,都转为一种叫做“中间表示”(Intermediate和Representation,简称为IR)的拓扑和权重文件,然后使用这个中间表示生成目标框架的模型。其基本原理如下图所示:

人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码

MMdnn转换过程

对于普通的分类和分割网络,一般情况下,使用一条命令,就可以使用MMdnn都可以很方便的进行模型转换。下面是一个实例,可以说非常简单了。

pip install mmdnn # 安装
# 将TensorFlow的resnet152模型转为PyTorch模型
mmconvert -sf tensorflow -in imagenet_resnet_v2_152.ckpt.meta -iw imagenet_resnet_v2_152.ckpt --dstNodeName MMdnn_Output -df pytorch -om tf_resnet_to_pth.pt

二. 目标检测模型转换经验

对于普通的模型,MMdnn可以很方便的转换,但是,如果那么简单,笔者岂不是早就可以开源五大框架的模型了吗。这其中,设计到一个很棘手的地方。

大家应该知道,对于TensorFlow和Keras,其默认的数据表示顺序为NHWC,也就是 [batch, height, width, channel] 格式,但是,对于Caffe、PyTorch和MXNet三兄弟,却都是NCHW格式的,也就是通道在第二个维度。这一点,MMdnn当然知道,所以对于普通的模型,放心转就可以了。但是,对于SSD、Yolo 系列包括Anchor Free的模型,就需要注意了。

熟悉目标检测的朋友们都知道,对于目标检测的一个定位分类层,假设其特征图是4x4大小,一共需要识别两类的话(假设需要检测猫和狗,如下图),而每个特征图上有三组anchor的话,那么定位分类层的分类部分的卷积层输出通道数,为2x3=6个通道,那么使用TensorFlow和Keras,这一个分类层的输出矩阵为[N, 4, 4, 6], 前面的N为batch size大小,而对于其他三大框架,则是通道在第二维度,即为[N,6, 4, 4]。

人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码

4x4

对于SSD和YoloV3等框架,具有多个定位层,一般我们都会在模型内部将其拼接起来,也就是concatanate起来。假设有两个定位层,特征图大小分别为8x8和4x4,则输出分类层特征图为[N, 8, 8, 6]和[N, 4, 4, 6],这样两个矩阵,因为有两个维度的大小都不同,所以无法直接concatanate,因此一般需要reshape,也就是将第二和第三维展开成一个维度,将最后一个维度分裂为以2个一组(就是类别数)的片段,以[N, 8, 8, 6]为例,即将它reshape为[N, 8*8*3, 2],也就是[N, 192, 2]的矩阵,对于[N, 4, 4, 6]这个特征图,reshape为[N, 48,2]的矩阵。这样,两个矩阵[N, 192, 2]、[N, 48,2]就可以通过第二维度进行拼接成为一个[N, 240, 2]的矩阵。

使用TensorFlow和Keras框架,对于多个定位分类层,只需要reshape,然后concatanate就可以了。但是,对于其他三大框架,因为他们通道在第二个维度,为了获得一致的结果,所以一般需要在reshape前,将通道转置到最后一个维度,然后再reshape和concatanate。

但是,MMdnn 并!不!知!道! 在reshape前需要做一个transpose的操作,它在转换模型的时候,还是使用(N, -1, 2)这个reshape参数,结果就是完全错误的了。

这是对于目标检测模型,使用通道在后的TensorFlow、Keras转PyTorch、Cafffe等通道在前的框架时候,需要特别注意的地方。

下面笔者写一下Keras转各个框架的心酸历程。

1)Keras 转TensorFlow

因为Keras的后端一般就是TensorFlow,所以Keras转TensorFlow就很容易了。

加载Keras模型后,可以获取session,然后从session中读取图结构,保存成TensorFlow的图结构就完事了。核心代码如下:

import tensorflow as tf
from keras import backend as K
keras_model = load_keras_model(keras_model_path)
sess = K.get_session()

from tensorflow.python.framework import graph_util
from tensorflow.python.framework import graph_io
constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph.as_graph_def(), ["cls_branch_concat","loc_branch_concat"])
graph_io.write_graph(constant_graph, '.' , graph_output_name, as_text=False)
print('saved the constant graph (ready for inference) at: ', osp.join('.', graph_output_name))

2) Keras转Caffe

因为上面提到的通道的原因,使用MMdnn转换不成功,因此元峰是使用自己写的一个工具转成Caffe的,原理就是读Keras模型的拓扑,构建Caffe的层拓扑结构,然后把权重赋值给新网络,就完事了。这个代码,后面整理好了会开源(主要是代码现在不优雅,对于有强迫症的人是做不到开源丑陋的代码的)。

3)Keras转PyTorch

使用MMdnn,可以生成PyTorch的结构代码文件和权重,但是,不要忘了前面提到的通道问题,笔者在五个定位分类层,需要transpose的地方,手动加入了transpose操作。

以第一组定位分类层为例,请注意其中的permute操作,permute也就是本文提到的transpose。具体可以看我们开源的代码,有完整的网络构建代码。

cls_0_reshape   = torch.reshape(input = cls_0_conv.permute(0,2,3,1) , shape = (cls_0_conv.size(0),-1,2))
loc_0_reshape   = torch.reshape(input = loc_0_conv.permute(0,2,3,1) , shape = (loc_0_conv.size(0),-1,4))

4)Keras转MXNet

这个是元峰花时间最长的一个,花了一天多时间,因为笔者也不太懂MXNet。我尝试了各种方法,使用Keras模型转,使用PyTorch、TensorFlow和Caffe,都不能成功的转成MXNet模型。

中间,我无数次想放弃了,毕竟MXNet用户量并不大。但是,因为我一直觉得只有集齐五大主流框架,才能够召唤神龙,如果只有四个,我怎么召唤呢,我也对不起使用MXNet的朋友啊;另外,我一直觉得,李沐团队写的《动手学深度学习》一书,是非常赞的(请私下给元峰打广告费)。所以,我强迫自己努力实现MXNet的模型。

具体是怎么做的呢? 其实很简单,笔者简单的学了一下MXNet,使用MXNet的Gluon接口,实现了跟Caffe模型一模一样的结构,然后,写个函数,将权重给MXNet模型赋过去,索性没遇到什么大坑,Caffe和MXNet模型输出一模一样,谢天谢地。

至此,元峰终于集齐了五大主流深度学习框架的模型,可以召唤神龙了。

不过玩笑归玩笑,集齐五大框架的模型,还是挺辛苦的,所以,元峰请大家帮忙关注一下我们的公众号AIZOO。毕竟,刚立志创业,遇上这个疫情环境,真是倒了霉了。大门出不去,那就让元峰的AIZOO公众号多积累一些粉丝吧。

三. 开源资料获取

最后,是我们开源的相关资料的获取方式。

  • 数据下载地址:在公众号AIZOO后台回复“ 口罩数据集 ”即可。
  • 开源五大主流深度学习模型和代码链接

https://github.com/AIZOOTech/FaceMaskDetection ​ github.com

  • 在线体验链接

AIZOO.com跑在您浏览器的口罩佩戴检测 ​ aizoo.com

我是元峰,互联网+AI领域的创业者,欢迎扫描下方二维码,或者直接在微信搜索“AIZOO”关注我们的公众号AIZOO。

如果您是有算法需求,例如目标检测、人脸识别、缺陷检测、行人检测的算法需求,欢迎添加我们的微信号AIZOOTech与我们交流,我们团队是一群算法工程师的创业团队,会以高效、稳定、高性价比的产品满足您的需求。

如果您是算法或者开发工程师,也可以添加我们的微信号AIZOOTech,请备注学校or公司名称-研究方向-昵称,例如“浙大-图像算法-元峰”,元峰会拉您进我们的算法交流群,一起交流算法和开发的知识,以及对接项目。

查看原文: 人脸口罩检测开源PyTorch、TensorFlow、MXNet等全部五大主流深度学习框架模型和代码

  • crazyswan
  • blacksnake
  • silvermouse
  • FosterConstance
  • JinLianHui
  • JinLianHui