2018百度之星开发者大赛-paddlepaddle学习

前言

本次比赛赛题是进行人流密度的估计,因为之前看过很多人体姿态估计和目标检测的论文,隐约感觉到可以用到这次比赛上来,所以趁着现在时间比较多,赶紧报名参加了一下比赛,比赛规定用paddlepaddle来进行开发,所以最近几天先学习一下paddlepaddle的相关流程,在这里记录一下,也好让自己真正的能够学到东西。

流程前瞻

在我看来,设计一个深度学习网络(主要是基于CNN的,其他的没怎么接触),主要有以下几方面:

  1. 数据的读取(这里主要是图片数据和它的“标签”)。
  2. 数据的预处理(包含数据集增强和你需要的操作)。
  3. 如何将你的数据送入网络。
  4. 网络结构的设计(layer的使用)。
  5. 损失函数的计算(这部分是根据你的任务决定的)。
  6. 优化器的选择(我想一般是adam吧)这里有一篇博客分享了各种优化算法的不同。
  7. 模型的存储以及加载(加载这部分其实挺重要的,之前看过一篇论文说应用ImageNet上预训练的模型进行迁移学习,往往能在新的任务上取得更好的效果,当然也不是绝对的)。
  8. 如何进行测试(可以说就是如何进行前向传播)。
  9. 可选:可视化。

接下来就以上几部分进行学习,在次非常感谢Charlotte77夜雨飘零1。他们的博文给予了我莫大的帮助,向大佬叩首。

一、数据的读取

对于本次比赛来说,我的数据是图片(各种监控的图片,大小不同),标注是json格式的文件,所以接下来要讨论一下在paddlepaddle中如何以图片为输入。

参见大佬Charlotte77的博文,paddlepaddle主要是通过reader来进行数据的输入,这里我参考了paddlepaddle github 上的SSD的例子的例子,先看他们的代码:

train_reader = paddle.batch(
    reader.train(data_args, train_file_list), batch_size=batch_size)
test_reader = paddle.batch(
    reader.test(data_args, val_file_list), batch_size=batch_size)

其中reader是import来的,我们以reader.train来看一下:

def train(settings, file_list, shuffle=True):
    file_list = os.path.join(settings.data_dir, file_list)
    if ‘coco‘ in settings.dataset:
        train_settings = copy.copy(settings)
        if ‘2014‘ in file_list:
            sub_dir = "train2014"
        elif ‘2017‘ in file_list:
            sub_dir = "train2017"
        train_settings.data_dir = os.path.join(settings.data_dir, sub_dir)
        return coco(train_settings, file_list, ‘train‘, shuffle)
    else:
        return pascalvoc(settings, file_list, ‘train‘, shuffle)

这里看得出来,是利用了之前定义的coco函数或者pascalvoc函数,就是从不同的数据集读取数据,以coco为例,看一下,到底返回了什么,这里代码有点长,我们主要看返回的是什么:

...
            if ‘cocoMAP‘ in settings.ap_version:
                yield im, boxes, lbls, iscrowd,                     [im_id, im_width, im_height]
            else:
                yield im, boxes, lbls, iscrowd

    return reader

balabala一大堆,终于发现,返回的是一个生成器reader,可见,主要就在于生成这个生成器,下面来总结一下padlepaddle输入数据的生成:

  1. 把你的数据(图片,标签)搞出来,然后用yield来产生一个生成器:reader。
  2. 将此reader生成batch,也就是train_reader = paddle.batch(reader, batch_size=batch_size)这样子。
  3. 接下来就是送入网络了。

二、如何将数据送入网络

上面第三步就是将数据送入网络,这是如何办到的呢,用过tensorflow的童鞋们可能知道,我们可以用一个palceholder(占位符)来链接我们的原始数据和我们的网络,在这里,也是同样的方法:

image = fluid.layers.data(name=‘image‘, shape=image_shape, dtype=‘float32‘)
gt_box = fluid.layers.data(name=‘gt_box‘, shape=[4], dtype=‘float32‘, lod_level=1)
gt_label = fluid.layers.data(name=‘gt_label‘, shape=[1], dtype=‘int32‘, lod_level=1)

用的是fluid.layers.data,等一下,lod_level是啥,这里paddlepaddle有个序列输入格式,这里lod_level为1说明这条数据是序列格式,那为啥我们的图片不是序列格式?这里图片的size第一维应该就是batch_size,我们注意到后面的gt_box和gt_label没有制定第一维,他们就是一个向量或者整数,为啥不像tensorflow里面直接就指定第一维为batch_size?因为paddlepaddle输入数据格式里面没有QAQ!具体查看大佬Charlotte77的博文吧,这部分我在官网没找到...

有了这个“占位符”之后,只需将我们之前的那个batch_size的train_reader feed进去就好了,具体如下:

feeder = fluid.DataFeeder(place=place, feed_list=[image, gt_box, gt_label])
if args.parallel:
    loss_v, = train_exe.run(fetch_list=[loss.name],feed=feeder.feed(data))#这里的data就是之前train_reader的数据,fetch_list就是要执行的operation的名称,feed的顺序就是上面feed_list指定的
else:
    loss_v, = exe.run(fluid.default_main_program(),
                      feed=feeder.feed(data),
                      fetch_list=[loss])
#train_exe和exe是之前定义的,类似与tensorflow的session(个人感觉,实际上还是不一样的)如下:
#exe = fluid.Executor(place)
#train_exe = fluid.ParallelExecutor(use_cuda=args.use_gpu, loss_name=loss.name)
#其中place为指定设备(CPU GPU)

好了,总结一下,如何将数据送入网络(在有了reader的前提下):

  1. 定义一个“占位符”,也就是fluid.layers.data。
  2. 定义一个feeder(fluid.DataFeeder),来指定设备和feed顺序。
  3. 运用执行器(这个后面再说)的run,指定你需要运行的operation,然后feed数据。

看到这里,我总是感觉paddlepaddle的fluid和tensorflow很像,先定义图模型,然后运行,但是看到官方说fluid是和TensorFlow Eager Execution很像,据我了解(没有用过,所以有可能是错误的,望批评指正)TensorFlow Eager Execution是针对之前tensoflow不能实时出结果(必须sess.run)来设计的,但是现在看好像不是很像,以后看懂了再来解释。留坑。

三、网络结构的设计(包含损失函数和优化器)

这部分我们直接看代码吧,在SSD的例子中:

locs, confs, box, box_var = mobile_net(num_classes, image, image_shape)

调用了mobile_net模型,这个有兴趣自己看吧,主要是fluid.layers中各种层的应用,这个估计各个深度学习框架都差不多,这部分实现的还是挺全的。

loss = fluid.layers.ssd_loss(locs, confs, gt_box, gt_label, box,box_var)
loss = fluid.layers.reduce_sum(loss)
...
optimizer = fluid.optimizer.RMSProp(
    learning_rate=fluid.layers.piecewise_decay(boundaries, values),
    regularization=fluid.regularizer.L2Decay(0.00005), )
optimizer.minimize(loss)
place = fluid.CUDAPlace(0) if args.use_gpu else fluid.CPUPlace()
exe = fluid.Executor(place)
exe.run(fluid.default_startup_program())

我们来看这一部分,定义了loss,然后指定了优化器,然后最小化loss,指定设备,然后启动我们的程序。我感觉这里是个大坑!有没有发现有些文档里面不是这么个流程,而是这样子的(来源paddlepaddle 03.image_classification):

place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer(
    train_func=train_program, optimizer_func=optimizer_program, place=place)
trainer.train(
    reader=train_reader,
    num_epochs=EPOCH_NUM,
    event_handler=event_handler,
    feed_order=[‘pixel‘, ‘label‘])

指定了一个trainer然后调用train。

还有一种

parameters = paddle.parameters.create(cost)
trainer = paddle.trainer.SGD(cost=cost,
                             parameters=parameters,update_equation=momentum_optimizer)

先根据cost(loss)产生要优化的参数,然后指定这些参数进行优化。

这到底用哪一种呢?幸好有大佬夜雨飘零1的经验,是因为新版本Fluid的原因,现在大部分都是用executor来进行编写的。所以以后也不用烦恼了,这里吐槽一下官方文档,感觉维护人员要少吃一个鸡腿,不同版本变化太大,然而官方只给最新的示例,但是对于之前的代码并没有进行版本的说明,导致我们学习起来有点混乱,希望能够重新写一下book。

四、模型的存储和加载

这部分官方文档资料挺全的,当然对于大家比较关心的如何加载ImageNet 预训练模型,也是有的,这里有例子,但是说实话这里有点问题,大佬在这里也做了讨论,本来想参考官方文档进行resnet的加载,但是一方面官方脚本执行时连接不上,再看模型加载会出现各种问题,所以暂时放弃了这种想法,等一下官方的优化。

这部分的主要代码:

exe = fluid.Executor(fluid.CPUPlace())
param_path = "./my_paddle_model"
prog = fluid.default_main_program()
fluid.io.save_params(executor=exe, dirname=param_path, main_program=None)
...
exe = fluid.Executor(fluid.CPUPlace())
param_path = "./my_paddle_model"
prog = fluid.default_main_program()
fluid.io.load_params(executor=exe, dirname=param_path,
                     main_program=prog)

可见是通过fluid.io来实现的。

五、如何进行测试

这部分应该是paddlepaddle的优势了,一方面我们训练的过程中希望能够进行测试,一方面当我们的模型训练完以后我们也希望能够利用前向传播进行预测。paddlepaddle都有这两方面实现:第一种官方给了很好的示例,这里就不赘述了。对于第二种,paddlepaddle也进行了很好的封装:

inferencer = fluid.Inferencer(
# infer_func=softmax_regression, # uncomment for softmax regression
# infer_func=multilayer_perceptron, # uncomment for MLP
infer_func=convolutional_neural_network,  # uncomment for LeNet5
param_path=params_dirname,
place=place)
results = inferencer.infer({‘img‘: img})

convolutional_neural_network就是你的模型里面生成predict的那个函数,params_dirname是保存参数的路径,可见,用paddlepaddle来进行前向传播十分简单,定义好数据之后,加载参数,然后调用infer就可以预测了。

总结

paddlepaddle还有很好的部署能力,但是局限于我现在用的功能,这部分并没有研究,这篇博客主要是串一下如何用paddlepadle搭建深度学习模型,其中有很多细节没有注意,而且有很多地方也不一定准确,希望各位多批评指正。

参考:

https://blog.csdn.net/u010089444/article/details/76725843

https://www.cnblogs.com/charlotte77/p/7802226.html

http://www.cnblogs.com/charlotte77/p/7906363.html

https://github.com/PaddlePaddle/models/tree/develop/fluid/object_detection

https://github.com/PaddlePaddle/book/blob/high-level-api-branch/03.image_classification/train.py

https://blog.csdn.net/qq_33200967/article/details/79126897

http://paddlepaddle.org/docs/0.14.0/documentation/fluid/zh/new_docs/user_guides/howto/training/save_load_variables.html

原文地址:https://www.cnblogs.com/bobxxxl/p/9320751.html

时间: 2024-10-07 06:59:37

2018百度之星开发者大赛-paddlepaddle学习的相关文章

2018"百度之星"程序设计大赛 - 资格赛 - 题集

1001 $ 1 \leq m \leq 10 $ 像是状压的复杂度. 于是我们(用二进制)枚举留下的问题集合 然后把这个集合和问卷们的答案集合 $ & $ 一下 就可以只留下被选中的问题的答案了. 之后扫一遍随便判一下重. 1002 非空子串中字典序最小的子串长度一定是 $ 1 $ . 咱们就记录一下每一个字母出现次数的前缀和, 每次询问就找到出现过的最先的那个字符就星了. 1003 整数规划好像是个NPC问题, 所以我们肯定不能直接上整数规划. 咱们来尝试把问题转换一下. n=2 x1---

2018“百度之星”程序设计大赛 - 复赛

没有兄弟的舞会 Accepts: 928 Submissions: 2446 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description 度度熊.光羽.带劲三个人是好朋友. 度度熊有一棵nn个点的有根树,其中1号点为树根.除根节点之外,每个点都有父节点,记ii号点的父节点为fa[i]fa[i]. 度度熊称点ii和点jj是兄弟(其中i \neq ji≠j)当

2018 “百度之星”程序设计大赛 - 初赛(A)

第二题还算手稳+手快?最后勉强挤进前五百(期间看着自己从两百多掉到494名) 1001  度度熊拼三角    (hdoj 6374) 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6374 签到题 题意:给n根木棒 求可以拼出的周长最长的三角形 可以用贪心的思想做 对所有的木棒长度进行排序 取最长的三根进行判断是否可以组成三角形 若不能 舍去最长的一根 每次都选择相邻的三根 for一遍就好 复杂度为O(nlogn) 代码如下 #include <ios

2018 “百度之星”程序设计大赛 - 初赛(A)1004 / hdu6377 度度熊看球赛 dp递推

度度熊看球赛 Problem Description 世界杯正如火如荼地开展!度度熊来到了一家酒吧. 有 N 对情侣相约一起看世界杯,荧幕前正好有 2×N 个横排的位置. 所有人都会随机坐在某个位置上. 当然,如果某一对情侣正好挨着坐,他们就会有说不完的话,影响世界杯的观看. 一般地,对于一个就座方案,如果正好有 K 对情侣正好是挨着坐的,就会产生 DK 的喧闹值. 度度熊想知道随机就座方案的期望喧闹值. 为了避免输出实数,设答案为 ans,请输出 ans×(2N)! mod P 的值.其中 P

2018&quot;百度之星&quot;程序设计大赛 - 资格赛

调查问卷 Accepts: 1546 Submissions: 6596 Time Limit: 6500/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Problem Description 度度熊为了完成毕业论文,需要收集一些数据来支撑他的论据,于是设计了一份包含 mm 个问题的调查问卷,每个问题只有 'A' 和 'B' 两种选项. 将问卷散发出去之后,度度熊收到了 nn 份互不相同的问卷,在整理结果的时候

2018 “百度之星”程序设计大赛 - 初赛(B)

degree Accepts: 1581 Submissions: 3494 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Problem Description 度度熊最近似乎在研究图论.给定一个有 NN 个点 (vertex) 以及 MM 条边 (edge) 的无向简单图 (undirected simple graph),此图中保证没有任何圈 (cycle) 存在. 现在

2018 “百度之星”程序设计大赛 - 初赛(A)度度熊学队列 list rope

c++ list使用 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <time.h> 6 #include <string> 7 #include <set> 8 #include <map> 9 #include <list> 10 #include <e

2018 “百度之星”程序设计大赛 - 复赛

1001 没有兄弟的舞会 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100005; int t,n; int a[maxn],fa[maxn]; struct node { int to,w; node(){} node(int _to,int _w) { to=_to;w=_w; } bool operator < (const node & _nod

2017&quot;百度之星&quot;程序设计大赛 - 复赛1001&amp;&amp;HDU 6144 Arithmetic of Bomb【java大模拟】

Arithmetic of Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 129    Accepted Submission(s): 94 Problem Description 众所周知,度度熊非常喜欢数字. 它最近在学习小学算术,第一次发现这个世界上居然存在两位数,三位数……甚至N位数! 但是这回的算术题可并不简单,由于