前言

本次比赛赛题是进行人流密度的估计,因为之前看过很多人体姿态估计和目标检测的论文,隐约感觉到可以用到这次比赛上来,所以趁着现在时间比较多,赶紧报名参加了一下比赛,比赛规定用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说明这条数据是序列格式,但是这里感觉应该不用加,这部分等我做过再说把。具体查看大佬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)来设计的,但是现在看好像不是很像,以后看懂了再来解释。留坑。

对于如何将数据保存成RecordIO文件并读取,这篇会详细解释。

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

这部分我们直接看代码吧,在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

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

  1. 2018百度之星开发者大赛-paddlepaddle学习(二)将数据保存为recordio文件并读取

    paddlepaddle将数据保存为recordio文件并读取 因为有时候一次性将数据加载到内存中有可能太大,所以我们可以选择将数据转换成标准格式recordio文件并读取供我们的网络利用,接下来记录 ...

  2. HDU6383 2018 “百度之星”程序设计大赛 - 初赛(B) 1004-p1m2 (二分)

    原题地址 p1m2 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  3. HDU6380 2018 “百度之星”程序设计大赛 - 初赛(B) A-degree (无环图=树)

    原题地址 degree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Tot ...

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

    1001 $ 1 \leq m \leq 10 $ 像是状压的复杂度. 于是我们(用二进制)枚举留下的问题集合 然后把这个集合和问卷们的答案集合 $ & $ 一下 就可以只留下被选中的问题的答 ...

  5. 2018"百度之星"程序设计大赛 - 资格赛hdu6349三原色(最小生成树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6349 题目: 三原色图 Time Limit: 1500/1000 MS (Java/Others)  ...

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

    第二题还算手稳+手快?最后勉强挤进前五百(期间看着自己从两百多掉到494名) 1001  度度熊拼三角    (hdoj 6374) 链接:http://acm.hdu.edu.cn/showprob ...

  7. 2018"百度之星"程序设计大赛 - 资格赛 A/B/E/F

    调查问卷  Accepts: 505  Submissions: 2436  Time Limit: 6500/6000 MS (Java/Others)  Memory Limit: 262144/ ...

  8. 2018"百度之星"程序设计大赛 - 资格赛 1002 子串查询

    题面又是万能的毒毒熊... 实在不想写了,就只写了这题 记26个前缀和查询枚举最小值直接算 实在是氵的死 而且我忘记输出Case #%d 想了很久 >_< #include<bits ...

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

    c++ list使用 #include <cstdio> #include <cstdlib> #include <cmath> #include <cstr ...

随机推荐

  1. backtype.storm.generated.InvalidTopologyException:null问题的解决

    程序启动报错:backtype.storm.generated.InvalidTopologyException:null 问题解决方法: 这个错误一般都是没有定义输出列造成的 检查Spout和Bol ...

  2. 用JavaScript中jQuery编写放大镜效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 分享cropper剪切单张图片demo

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8& ...

  4. Python中模块

    模块 模块对我来说是什么 模块对我来说,感觉就像亲属或者朋友已经走过的路,他们已经趟过的浑水.掉过的坑.践行过的路线,全部提供给你,在你需要的时候请求帮助,借鉴他们的解决方法一样.都是为了方便走好人生 ...

  5. Java代码生成器CodeX4J介绍

    用代码生成器生成一些固定的或有规律的代码,可以有效的提高工作效率.我写了个开源的,放在了GitHub上,希望能对有需要的朋友有所帮助. GitHub代码地址https://github.com/jac ...

  6. Altium Designer (DXP) 复制粘贴,放器件 出错报异常的原因

    安装好Altium Designer (DXP) 09板和2013后,运行后原理图复制粘贴元件或者放心的器件后出现下面异常, 原因是: 1.未启动 Print Spooler服务 2.没有安装任何打印 ...

  7. Docker集群部署SpringCloud应用

    整体架构 docker环境准备 # linux下的安装,自行百度 # windows docker toolbox下载地址 https://download.docker.com/win/stable ...

  8. Flume(5)-Ganglia监控

    一. 安装Ganglia 1. 安装httpd服务与php sudo yum -y install httpd php 2. 安装其他依赖 sudo yum -y install rrdtool pe ...

  9. python从Excel中提取邮箱

    从各个城市的律师协会去爬取的律师的招聘信息,可是邮箱在招聘简介里面,所有需要写个脚本去提取邮箱 import pandas as pd import re regex = r"([-_a-z ...

  10. HTTP請求

    HTTP[超文本傳輸協議]是因特網上應用最為廣泛的一種網絡傳輸協議,送油的WWW文件都必須遵守這個標準. HTTP是一個基於TCP/IP通信協議來產地數據(html文件,圖片文件,查詢結果等). HT ...