hans

hans

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


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

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

** TF 版本至少 1.4.0。 **

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

** 2018.04.13 更新 SSD 单机训练 + 测试代码: https://github.com/HansRen1024/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 数据集。

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

生成 txt 文档的脚本的博客地址(就是 Github 中的 img2list.sh ):
【Caffe】快速上手训练自己的数据 《很认真的讲讲 Caffe》

代码是准备数据集里面生成 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 里只能处理 3232 数据集,我给改了,现在这个网络可以处理正常 227227 的了。

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 频率很难平衡。

  1. 我不了解为什么一训练起来所有 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
搞定)

1668714987733.jpg

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

index=0 机器:

1668714995590.jpg

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

1668715002213.jpg

我想到的解决办法是把 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 机器会卡主一会,然后报错:

1668715013234.jpg

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

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

  2. 同步训练中,性能好的机器会先一步开始训练。如果主机没先开始训练的话,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

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

  2. 解决了一运行就将 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 文件要分别保存在两个目录中

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.