欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

程序员文章站 2022-05-30 18:45:01
...

Github代码地址:https://github.com/HandsomeHans/Tensorflow-preprocessing-training-testing

所有代码去Github上拿吧,文件名对应好。

TF版本至少1.4.0。

MonitoredTrainingSession在网上的资料十分稀少,研究了很久官方API和源码

2018.04.13更新 SSD单机训练+测试代码:https://github.com/HandsomeHans/Tensorflow-SSD

2018.03.16更新 增加可视化代码

2018.03.19更新 增加debug调试代码

2018.03.20更新 增加去均值,归一化代码

2018.03.21更新 增加mobilenet和mobilenet v2网络模型

2018.03.22更新 增加resnet-50, resnet-101, resnet-152, resnet-200网络模型

                           解决了一运行就将GPU内存占满的问题(只在单机好用,分布式环境不行)

2018.03.23更新 选择GPU

2018.03.26更新 添加了validation阶段,可以在tensorboard上同时监控train和val阶段的loss

2018.03.29更新 增加了finetune功能

2018.04.02更新 优化了可视化效果,重新设置了计算step的方法。

2018.04.09更新 在分布式环境下增加了同步异步训练开关,重写了MonitoredTrainingSession

2018.04.10更新 用global step替换了自定义的i或者step,解决了log输出不匹配问题

2018.04.11更新 解决了异步训练记录最后一次event失败的问题

前言

新业务要做分布式集群,以前一直用的caffe,现在得用Tensorflow。

网上几乎全是照搬官方demo,没有详细介绍从数据读取处理到训练到测试的文章。我来写一个。

一、准备数据集

以前一直用的caffe,数据集都分类放到不同目录里面的。我这里放出两个脚本,各自功能看解释。

脚本1(img2bin.py)不建议用这个,没后续更新:

classes是images目录下各类数据集目录名

img=img.resize((227,227)) 要根据网络结构选择resize尺寸

这个脚本和images目录在同一级,images目录下有三个目录“0”,“1”,“2”,分别放了三个类别的所有图片数据集。最后生成名字为“train.tfrecords”的二进制文件。

脚本2(list2bin.py):

最后会打印一组bgr三通道均值,记录训练集的均值,放到arg_parsing.py中,用于去均值操作。

一定要转换成RGB三通道,否则后面数据读取会出问题。

以前用caffe 的时候,习惯先生成一个txt文档(格式如下),然后根据文档生成lmdb数据集。

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

脚本2就是根据这个txt文档生成tfrecords二进制数据集的。

生成txt文档的脚本的博客地址(就是Github中的img2list.sh):http://blog.csdn.net/renhanchi/article/details/72457630

代码是准备数据集里面生成train.txt和val.txt的.sh脚本

我写第二个脚本就是习惯了训练阶段根据val的输出判断训练过程是否正确。不过后来因为一些原因,在训练阶段做不了val。需要继续研究-0-。


二、配置准备阶段

拿到上面生成的.tfrecords二进制数据集,就可以开始布置环境进行训练了。

代码比较多,解释我都放到代码里面吧,这样看起来方便点。说实话很多tf的api我也没搞懂,现在只是跑起来了。后面还要花大量时间去学习研究。

文档1(arg_parsing.py):

这个文档主要用来设置运行输入参数的,很好理解。可以在代码中修改大写字符后面的默认参数,也可以在命令行指定参数。

文档2(dataset.py):

读取数据,去均值,归一化,整合成一batch输入网络

文档3(main.py):

在命令行要执行的文档,内容很简单。

if tf.gfile.Exists(FLAGS.model_dir): #注释的三句话是清空models目录,如果没这个目录就创建。为了防止误操作,我注释了这三句话

文档4(net/squeezenet.py):

网络结构文档,单独写出来,以后换网络结构就方便了。

我的是squeezenet网络,官方demo里只能处理32*32数据集,我给改了,现在这个网络可以处理正常227*227的了。

network.py 看看就好,后续被我抛弃停止更新了。

文档5(test.py):

用于test的文档。

文档6(train.py)

训练文档,里面有三种训练方法。写的最累的文档了,糟心~~~。

train():#单机单卡+单机多卡通用训练方法。
train_dis_():#可以用的分布式多机多卡。

关于train.py我要多说几句。

1.关于session,普遍都用tf.Session()。我这里用的tf.train.MonitoredTrainingSession(),是看的官方api推荐和cifar-10 demo里这么用的。这个接口中hook这一块很方便,可以灵活定义和使用一些功能。在官网API文档中,几乎所有hook都可以用在这里。比如debug,summary等等,值得研究。(2018.03.23 通过这个MTS管理器很难加入validation阶段,如果是通过共享参数来validation,问题主要是global_step冲突。如果通过读取本地ckpt做,保存ckpt的频率和validation频率很难平衡。

2.我不了解为什么一训练起来所有GPU的内存就会马上被占满,设置batch_ size为1还是32还是64结果都一样。所以一运行val就会报GPU内存不足,过一会机器就卡死了 -0-。这个问题以后慢慢解决吧~

3.第三个train_dis()方法,可以控制同步还是异步,不过有点问题,着急跑通流程就没管了,以后有时间再看。

4.第二个train_dis_()是可以使用的分布式多机多卡方法,我判断应该是异步的。

5.可以通过CUDA_VISIBLE_DEVICES=0,1 这句话来控制使用某个GPU。或者在main.py中加入下面一句话设置。


三、布置训练阶段

第一种情况(单机单卡,单机多卡):

设置好main.py中调用的train的方法和路径,直接运行:

python main.py

默认就是训练模式


第二种情况(多机多卡):

只要在命令行指定了--job_name,自动就会运行分布式训练。

先将所有文档和数据集分别分发到各个服务器当中去。

比如我现在只有两台服务器10.100.1.151和10.100.1.120

我现在是要把151服务器同时作为ps和worker

把120服务器作为worker

需要先在arg_parsing.py中设置好ps_hosts和worker_hosts,用逗号间隔开,不要有空格。

然后需要现在151服务器运行:

CUDA_VISIBLE_DEVICES='' python src/main.py --job_name=ps --task_index=0

这里说一下CUDA_VISIBLE_DEVICES=''表示不使用GPU,因为作为参数服务器,可以用CPU处理的。

接下来,继续在151服务器运行:

CUDA_VISIBLE_DEVICES=0 python src/main.py --job_name=worker --task_index=0

最后在120服务器运行:

CUDA_VISIBLE_DEVICES=0 python src/main.py --job_name=worker --task_index=1

可以通过CUDA_VISIBLE_DEVICES这句话来设置需要启用的GPU,序列用逗号隔开。

四、测试

特别提一下多机多卡只会在index为0的主机上保存ckpt。

准备好测试集的.tfrecords,配置好路径,在命令行运行:

python main.py --mode=testing

必须指定测试模式。


后记

命令行参数可以研究一下,虽然很多,但都很简单。

后续我会持续更新。。。

1.同步异步(2018.04.09 搞定)

2.去均值,归一化(2018.03.20搞定)

3.可视化(2018.03.16搞定)

4.debug(2018.03.19搞定)

5.validation (2018.03.26搞定)

6.关于显存一直被占满的问题(2018.03.22 搞定)

7.准备更多网络模型文档 (2018.03.19 mobilenet,2018.03.22 resnet)

8.选GPU(2018.03.19 搞定)

9.优化可视化的网络结构图(2018.04.02 搞定)

10.Finetune(2018.03.29 搞定)

11.新问题,网上没找到解决办法。异步分布式训练完成后,最后一次记录event会失败。是因为当index=0主机run_context.request_stop()时,其他机器可能在validation阶段导致的。(2018.04.11 搞定)

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

12.新问题,分布式同步训练环境下,经过validation阶段后global step和i出现不对应问题。具体看图。

index=0机器:

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

index=1机器(990step卡住,等待0机器validation结束。):

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

我想到的解决办法是把log和validation写成hook加到MonitoredTrainingSession中去,不过尝试后发现问题并没有得到解决。(2018.04.10 解决)

这个也和下面问题有关系:

到validation这一step的时候,性能不同的机器会不同步进行validation。

顺序是:当到达validation step时,性能好的机器先进行validation,等完事后,性能差的机器才会进行validation。

这会增加整体训练的耗时,具体原因我观察是:如果设置validation step为1000的话,当sess run 1001 step 时,1000 step的参数才会传给ps机器更新后传回worker机器然后继续1001step 训练。(不知道你们能读懂不-0-,MonitoredTrainingSession这种会话每次运行时其实都是分三步,begin,before run 和after run。参数传递给ps机器,再返回给worker机器应该都是在before这一步进行的。)(2018.04.02 重写MonitoredTrainingSession后,只在index=0机器上进行validation)

每次同步模式训练完,index 0机器会卡主一会,然后报错:

【Tensorflow】【Python】训练自己的数据集——数据读取、处理、训练、测试、可视化、Debug(单机单卡、单机多卡、多机多卡)

Google搜了一下,没找到解决办法。不过不影响我们整体训练,无视之!

13. 有一个疑惑,在tensorboard中观察发现val_loss是每100 step记录一次。但实际我是每1000 step才跑一次validation。有点懵逼。

14. 同步训练中,性能好的机器会先一步开始训练。如果主机没先开始训练的话,tensorboard中初始step将不是从1开始的。

---------2018.03.16更新-----可视化-------

重写了一个网络结构文档(squeezenet.py),优化了参数计算过程,添加了summary代码进去,可以在tensorboard上查看很多内容了。

相应更新了其他文档。

如果想用回老的网络结构文档(network.py),需要在train.py文档中,改动inference那一句代码就好了。

把index=0服务器上models目录传回自己的主机,在命令行运行:

tensorboard --logdir=models/

在浏览器地址栏输入:

localhost:6006
就可以查看可视化内容了。也可以在服务器上运行tensorboard命令,然后在自己主机浏览器地址栏输入IP:端口号,这样查看可视化内容。

---------2018.03.19更新-----DEBUG-------

在train代码中添加了debug代码,只有一行。在tf.train.MonitoredTrainingSession中hook列表中,在arg_parsing.py中设置是否开启debug模式

在API中还发现了一种在tensorboard上调试的接口tfdbg.TensorBoardDebugHook(),不过我的主机tensorflow版本1.2还没这个接口,就没测试。看个人习惯了,喜欢在命令行调试还是在tensorboard上调试。

同时修改了参数代码,每次运行必须指定训练模式。


---------2018.03.20更新-----去均值、归一化-------
1. 修改了img2bin_list.py,最后会计算并打印bgr三通道均值。

2. 修改了arg_parsing.py,增加了均值参数。

3. 修改了dataset.py,在数据读取的时候增加了去均值和归一化操作。

---------2018.03.21更新-----增加网络模型-------

1.修改了arg_parsing.py, test.py, train.py

2.增加mobilenet和mobilenet v2网络模型

---------2018.03.22更新-----增加网络模型,解决GPU内存问题------- 

1.修改了arg_parsing.py, test.py, train.py

2.增加resnet-50, resnet-101, resnet-152, resnet-200网络模型

3.解决了一运行就将GPU内存占满的问题,但是只在单机上好用,在分布式环境不行。

---------2018.03.26更新-----在训练阶段中增加了验证阶段------- 

对train.py改动比较大,对所有网络结构.py也有改动,要求tensorflow版本至少1.4.0。

原因是tf.variable_scope()中没有reuse=tf.AUTO_REUSE 。

当然如果你能自己一个一个设置reuse,理论上也可以用低版本tensorflow的。

比较麻烦而已,需要判断是train还是val,然后分别设置reuse为False还是True

---------2018.03.29更新-----Finetune------- 

可以进行finetune了

我是在自己之前训练出的模型的基础上finetune的,

还没去找开源的训练好的模型。2018.04.02  在Github上没找到合适的预训练模型,并且即使找到了也有可能面临一些问题。)

在命令行指定模型保存路径就可以自动finetune了

--finetune=path/

---------2018.04.02更新-----优化了可视化效果------- 

1. 把训练阶段和验证阶段summary分别放到了不同namespace中,网络结构图也做了优化。

---------2018.04.09更新-----同步异步训练------- 

1. 在分布式环境中,添加了一个布尔开关(--issync)来控制同步还是异步更新参数训练。

2. worker服务器一定要按index从0开始的机器一个一个运行程序,如果不按顺序运行程序的话,会使各个服务器step差距很大。

3. 重写了MonitoredTrainingSession,将log和validation分别写进两个hook中,并且同步模式下只有index=0的worker机器上会进行validation。

---------2018.04.10更新-----解决log输出step不匹配问题-------

1.  分布式,同步训练环境下,通过在hook中run_context.session.run(global_step)读取全局step来控制log和validation,解决了不同机器之间step不匹配问题。

---------2018.04.11更新-----解决异步训练记录最后一次event失败问题-------

1. 将异步训练也改成通过读取global_step来控制,在ExitHook中强制index=0主机在最后阶段做一次validation,保证其他机器先执行run_context.request_stop()。这样解决了记录最后一次event失败的问题。我理想中解决这个问题的方法是index=0主机发现当前global step达到训练结束次数的时候,先等待其他机器都request stop后,自己才request stop。

---------2018.04.13更新-----添加了SSD代码-------

1. 具体模型保存路径和数据路径要设置好

2. 数据路径下图片和xml文件要分别保存在两个目录中