zoukankan      html  css  js  c++  java
  • 基于paddlepaddle复现crowdnet的人流密度检测

    https://aistudio.baidu.com/aistudio/projectdetail/402118

    前言(AIstudio学习过程):

    不想看的直接跳下面正文!

    实现这个网络的契机是我参加了aistudio的训练营。那时候才学习深度学习不久,之前一直在啃动手深度学习mxnet版本的原理知识,虽然提供了代码,可是自己这台笔记本实在胜任不了深度学习的任务,经常爆显存。纸上得来终觉浅,绝知此事要Code。所以像找点资源跑一下代码,其实之前就知道了aistudio,但是只能使用paddle这个框架,需要一定的学习成本,顺手网上一搜。。

    主要原因是,

    1.像tf,pytorch之类出现的比较早,使用群体比较广。paddle发展的晚,一开始必然会被大家拿来和各框架对比,我搜了一下早期的评价确实不高,容易劝退新手。

    2.paddle社区活跃度不高,对于新手来说开始出现很多问题都不一定能通过搜索引擎找到问题(这个问题在我学paddle时有深刻体会,虽然有官方答疑qq群,但是及时性和准确性方面则比较低,毕竟程序员还是比较习惯用搜索引擎一些),所以一直不想去尝试。

    作为新手各种百度知乎问哪里有免费资源,最后找到的要么FQ要么自己出钱。后来思来想去,天下哪有免费的午餐,虽然paddle现在比较小众暂时了解的人不多,但是总归依靠百度这个大平台,还是挺可靠的。毕竟资源免费啊,真香!学**的!花了将近1个星期看官方文档,都是看的静态图。开始都不知道有动静态图这个概念,通过看别人的项目和官方文档,最终自己动手封装了一个模型训练类,实现了Lenet,VGG,alexnet,NIN(这个不知道为啥一直不能收敛)。这个过程真的难受,代码一开始封装起来就出现很多问题,开始不知道怎么解决,百度又找不到问题,就去问qq群的大佬们,虽然还是很热心,但是答案基本37开的命中率吧,大部分都是自己一行一行的调试比对别人的项目,查api解决的。

    某天晚上我给我导师写了学习汇报,提到了aistuido,然后我导师居然推荐我看这个aistudio的7天的训练营(真不是广告!),惊了!不过当时真的不想折腾去学这个东西。好吧,既然导师说了就去看一下,然后,卧槽,这代码和我的咋不一样,这是啥dygraph,我没学过,赶紧去看下原来叫动态图,咋这么复杂啊!比静态图还绕一些。后来想了想,反正也是学习,干脆直接就进这个训练营了,跟着课程做作业,作业都有baseline了需要自己实现关键网络,其实大部分都没啥问题,比如VGG这种,已经在静态图实现过了,就是paddle动态图一些使用不太会,得自己一个个去学习,最后算是勉强都通过了。 直到开始了人流密度检测的比赛,才真正让我体会到了深度学习的深度。。。以前我只知道vgg resnet googlenet啥的,最多每个领域就用那么几个经典模型,以为就这些网络用来用去,直到我开始比赛时,读baseline代码翻到:密度图?百度一下:人流密度密度图。真正打开了我的新世界,密度图->crowdnet->论文->原理->代码->CVPR->2016->2017->2018->2019->dilated convolution。。。。,这期间我都阅读了10-20篇博客+2篇论文(略读)+2-3个版本的github源码,纵观时间线,就这一个领域的研究都达到了很深的深度, 真的让我了解了深度学习是如何研究的,真正做出某个领域的成就需要非常大的知识储备,也让我学到了一个领域的前沿知识。

    总结:这次课程真的让我学到了很多知识,深度学习代码编写,模型训练,网络复现,调参,paddlehub,参加比赛等等。作为一个初入深度学习的新手真的收获颇丰。学完之后,初步接触的感受是现在版本的paddle体验挺好的,而且paddle还在一直迭代维护,对于我这个新手来说经历完前期的小问题后使用paddle很顺畅了,后续继续使用,慢慢看后期表现如何吧!关键是这期间所有课程,资源,问答都是免费的!!感激之情,无法言表!

    正文:

    这篇文章只讲实现网络结构不讲具体原理,详情请看论文。新手第一次复现论文的网络,如有问题还请指正。

    crowdnet:

    https://arxiv.org/pdf/1608.06197.pdf

    我复制出来代码的baseline: https://aistudio.baidu.com/aistudio/projectdetail/402118

    这个baseline 是aistuido提供的,是私密的,进 aistudio => 深度学习7日入门-CV疫情特辑 => 课节=》课节06=>paddlehub体验=>06人流密度检测-基础版。里面还有一个训练营的比赛,也可以去试试。
    https://aistudio.baidu.com/aistudio/education/group/info/1149

    这个代码把数据集的配置读取和预处理都做好了,还包括关键的高斯密度图的生成代码!

    一、CrowdNet
    网络结构:


    输入数据是对应尺寸的图像,输出和label都是密度图。

    DeepNetwork:

    原文说了借鉴了的VGG16的结构,说明一下上面的网络结构图 如:2 conv 3X3(64)表示:2层卷积,卷积的大小3*3,输出通道为64,另外卷积层的padding=1,stride=1,这样设置的效果是:不会改变输入图的大小,如:输入图的大小为X*Y, (X+2-3)/1+1计算得到还是X,尺寸不会变化。Pool层是 2*2 ,stride=2,padding=0,使用MAX最大化池化层,这样正好将图片缩小一半,为原来的1/2,(X+0-2)/2+1=X/2 。

    这里和VGG不同的是,移除了第五层所有卷积和pool,修改了第四个pool:卷积大小为3*3,stride=1,padding=1,这样不会改变大小,最后得到的特征图大小为原图大小的1/8.

    Shallow Network:

    同理,这个网络层经过3个AVG池化层的pool缩小为原来的1/8,卷积层使用的是 24通道,卷积尺寸:5*5,仅1个卷积层,它的stride=1,那么padding=2; Pool层是 padding=0,stride=2,size=2*2。

    CONCAT:

    将这两个网络的输出,在通道维上连接起来,如:5*20*80*60 ---- 5*30*80*60=> 5*50*80*60

    再经过一个 1x1size, padding=0,stride=1,输出通道也为1的卷积层,目的是减少通道数,这样最终合并成一个 比如:

    变成1*80*60的特征层。

    INTERP:

    其实就是一个上采样,使用双线性插值将图片放大到label的密度图大小。如果label的大小和这里输出大小一样,这一步就没必要再使用了。

    LOSS:损失函数可以看到使用的l2 loss均方误差计算。

    查阅baseline的代码可以知道,对密度图求和就可以得到具体的人数。

    论文后面还提到了数据增广:(这一步我没有做)

    大意是将数据尺寸缩放为原图的0.5-1.2倍,形成特征 ‘金字塔结构’见下图,在这个金字塔图中裁剪出人流重叠50%以上的区域,每个区域的大小为225*225.

    代码实现:
    class ConvBNLayer(fluid.dygraph.Layer):
    def __init__(self,
    num_channels,
    num_filters,
    filter_size,
    stride=1,
    groups=1,
    padding=0,
    act=None):
    """
    name_scope, 模块的名字
    num_channels, 卷积层的输入通道数
    num_filters, 卷积层的输出通道数
    stride, 卷积层的步幅
    groups, 分组卷积的组数,默认groups=1不使用分组卷积
    act, 激活函数类型,默认act=None不使用激活函数
    """
    super(ConvBNLayer, self).__init__()

    # 创建卷积层
    self._conv = fluid.dygraph.Conv2D(
    num_channels=num_channels,
    num_filters=num_filters,
    filter_size=filter_size,
    stride=stride,
    padding=padding,
    groups=groups,
    act=None,
    bias_attr=False)

    # 创建BatchNorm层
    self._batch_norm =fluid.dygraph.BatchNorm(num_filters, act=act)

    def forward(self, inputs):
    y = self._conv(inputs)
    y = self._batch_norm(y)
    return y

    class crowdnet(fluid.dygraph.Layer):
    '''
    网络
    crowdnet
    '''
    def __init__(self):
    super(crowdnet, self).__init__()
    #定义deepnetwork
    self.conv01_1 = ConvBNLayer(num_channels=3, num_filters=64,filter_size=3,padding=1,act="relu")
    self.conv01_2 = ConvBNLayer(num_channels=64, num_filters=64,filter_size=3,padding=1,act="relu")

    self.pool01=fluid.dygraph.Pool2D(pool_size=2,pool_type='max',pool_stride=2,pool_padding=0)

    self.conv02_1 = ConvBNLayer(num_channels=64, num_filters=128,filter_size=3, padding=1,act="relu")
    self.conv02_2 = ConvBNLayer(num_channels=128, num_filters=128,filter_size=3, padding=1,act="relu")
    self.pool02=fluid.dygraph.Pool2D(pool_size=2,pool_type='max',pool_stride=2,pool_padding=0)

    self.conv03_1 = ConvBNLayer(num_channels=128, num_filters=256,filter_size=3, padding=1,act="relu")
    self.conv03_2 = ConvBNLayer(num_channels=256, num_filters=256,filter_size=3, padding=1,act="relu")
    self.conv03_3 = ConvBNLayer(num_channels=256, num_filters=256,filter_size=3, padding=1,act="relu")
    self.pool03=fluid.dygraph.Pool2D(pool_size=2,pool_type='max',pool_stride=2,pool_padding=0)
    #(x-2/2+1)
    self.conv04_1 = ConvBNLayer(num_channels=256, num_filters=512,filter_size=3, padding=1,act="relu")
    self.conv04_2 = ConvBNLayer(num_channels=512, num_filters=512,filter_size=3, padding=1,act="relu")
    self.conv04_3 = ConvBNLayer(num_channels=512, num_filters=512,filter_size=3, padding=1,act="relu")
    self.pool04=fluid.dygraph.Pool2D(pool_size=3,pool_type='max',pool_stride=1,pool_padding=1)
    #(x-3+2)/1 + 1= x
    self.conv05_1 = ConvBNLayer(num_channels=512, num_filters=512,filter_size=3,padding=1, act="relu")
    self.conv05_2 = ConvBNLayer(num_channels=512, num_filters=512,filter_size=3,padding=1, act="relu")
    self.conv05_3 = ConvBNLayer(num_channels=512, num_filters=512,filter_size=3,padding=1, act="relu")
    #n*512*80*60

    #shallow network
    self.conv_s_1=ConvBNLayer(num_channels=3,num_filters=24,filter_size=5,padding=2,stride=1,act='relu')
    self.pool_s_1=fluid.dygraph.Pool2D(pool_size=2,pool_type='avg',pool_stride=2,pool_padding=0)

    self.conv_s_2=ConvBNLayer(num_channels=24,num_filters=24,filter_size=5,padding=2,stride=1,act='relu')
    self.pool_s_2=fluid.dygraph.Pool2D(pool_size=2,pool_type='avg',pool_stride=2,pool_padding=0)

    self.conv_s_3=ConvBNLayer(num_channels=24,num_filters=24,filter_size=5,padding=2,stride=1,act='relu')
    self.pool_s_3=fluid.dygraph.Pool2D(pool_size=2,pool_type='avg',pool_stride=2,pool_padding=0)
    #n*24*80*60

    #通道维连接
    #input:512+24 *80*60
    self.connect_conv=ConvBNLayer(num_channels=512+24,num_filters=1,filter_size=1,padding=0,stride=1)
    #output:1*80*60
    #上采样,双线性插值生成label密度图的大小的图

    #最后使用L2 loss计算损失
    def forward(self, inputs, label=None):
    """前向计算"""
    #deep net
    out = self.conv01_1(inputs)
    out = self.conv01_2(out)
    out = self.pool01(out)

    out = self.conv02_1(out)
    out = self.conv02_2(out)
    out = self.pool02(out)

    out = self.conv03_1(out)
    out = self.conv03_2(out)
    out = self.conv03_3(out)
    out = self.pool03(out)

    out = self.conv04_1(out)
    out = self.conv04_2(out)
    out = self.conv04_3(out)
    out = self.pool04(out)
    out = self.conv05_1(out)
    out = self.conv05_2(out)
    out = self.conv05_3(out)

    #shadow net
    out1 = self.conv_s_1(inputs)
    out1 = self.pool_s_1(out1)

    out1 = self.conv_s_2(out1)
    out1 = self.pool_s_2(out1)

    out1 = self.conv_s_3(out1)
    out1 = self.pool_s_3(out1)

    #concatenate
    #按通道维连接
    conn=fluid.layers.concat(input=[out,out1],axis=1)
    result=self.connect_conv(conn)
    return result

    参考博客:

    https://www.jianshu.com/p/a1006c4b6fdc

    https://blog.csdn.net/linolzhang/article/details/78838320?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2
    ————————————————
    版权声明:本文为CSDN博主「5jerry」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/shenkunchang1877/article/details/105360963

  • 相关阅读:
    理解 Delphi 的类(十) 深入方法[15] 调用其他单元的函数
    理解 Delphi 的类(十) 深入方法[13] 在 interface 区声明的方法
    理解 Delphi 的类(十) 深入方法[12] implementation 区中的方法
    理解 Delphi 的类(十) 深入方法[6] Result
    什么是B*树倒排索引技术 已解决 搜搜问问
    caoruntao的博客 数据结构及算法分类文章列表 ITeye技术网站
    PForDelta索引压缩算法的实现
    计算机词汇(融合了搜狗所有的计算机词库)_搜狗输入法词库
    一种由B+树实现的倒排索引《电脑知识与技术》2011年08期
    海量数据处理专题(九)——外排序
  • 原文地址:https://www.cnblogs.com/shuimuqingyang/p/15245906.html
Copyright © 2011-2022 走看看