TensorFlow 物体检测API 分布式部署测试(上)

更新TensorFlow物体检测API的分布式部署代码测试过程,供大家参考

        近期研究进展较慢,研究物体检测API也跳了很多坑,刚刚完成物体检测API的分布式代码部署与测试,这里记录一下,同时也供大家参考,如有错误,欢迎批评指正

关于TensorFlow的分布式教程网上有很多详细博客,这里就不再重复讲解。这里研究物体检测API中的分布式部署,前期在网上搜索相关的教程只搜到一篇,本人也是参考这篇博客走通了API的分布式流程,博客网址为 https://blog.csdn.net/u013036495/article/details/79484432,大家也可以参考。

API中设置分布式相关参数的代码在train.py文件的124行 :

env = json.loads(os.environ.get('TF_CONFIG', '{}'))

如果需要分布式训练,需要将对应的节点参数写入 ’{ }’ 中,然后进行训练文件的调用即可,一组简单的参数示例如下:

'{"cluster": {"master": ["10.37.2.62:2220"], '
             '"ps": ["10.37.2.62:2224"], '
             '"worker": ["10.37.2.62:3001"]},'
'"task": {"index": 0, "type": "ps"}}'

API中是通过一个字典的形式,定义了两个键值分别为‘cluster’和‘task’供后续取出放入分布式参数测试函数中。

“cluster”义了我们分布式系统的预定义节点,例子中在同一台服务器上定义了 ‘ps’ , ‘master’ , ‘worker’ 三个节点,‘ps’ 节点为参数服务器,‘master’节点和‘worker’节点为计算服务器,其中‘master’节点负责模型的保存。

“task”定义了当前调用文件的分布式节点类型与对应的索引,例子中当前文件调用的是‘ps’节点的第一个端口

按照例子中的分布式参数的定义,我们需要在10.37.2.62服务器上分别启动三个窗口,然后分别运行train.py文件,每次指定不同的节点与对应的索引,分别启动‘ps’, ‘master’ 和‘worker’ 服务器,这个时候物体检测API的分布式流程即走通,三个节点的启动顺序不会影响程序的结果,在训练完成之后,‘worker’计算节点自动终止,‘ps’和‘master’节点由于保持分布式通信需要手动kill对应进程。

上述只是按照教程走通了物体检测API的分布式流程,在单机,多机,单卡,多卡下测试没有问题。下面是对其在单机多卡上进行的一些简单改进。主要有两点:多进程启动分布式,训练结束后自动kill分布式进程。

多进程启动分布式

这一部分的想法是通过python的多进程根据设定的分布式节点参数来启动各个分布式节点。首先定义分布式服务器各个节点,根据例子设置如下:

params = {'ps': ['"10.37.2.62:2224"'],
'master': ['"10.37.2.62:2220"'],
'worker': ['"10.37.2.62:3001"']}
# 若多master,worker,设置格式如下:
# 'worker': ['"10.37.2.62:3001", "10.37.2.62:2221"']

定义变量params保存了分布式的三个节点,然后定义被多进程函数调用的函数,这个函数的主要作用就是根据传入的参数来调用train.py文件,启动不同的分布式节点:

def do_distribute(params, index, type):
    print("%s index %s is called" % (type, index))
    os.system("CUDA_VISIBLE_DEVICES='0' python train.py --ps={} --master={} --worker={} --index={} --type={} " 
              .format(params['ps'], params['master'], params['worker'], index, type))

params参数即为之前定义的节点变量,type参数为当前执行的服务器类型,index为对应的索引,这些参数都需要传入到train.py中函数进行变量值得替换。这里调用train.py的其他参数没有显示,默认已经写好。

接下来即通过多进程函数来一次启动各个节点,首先得到params各个节点的数量:

ps_len = len(params['ps'][0].split(','))
master_len = len(params['master'][0].split(','))
worker_len = len(params['worker'][0].split(','))

然后调用多进程:

# 创建多进程启动分布式各个节点
for index_ps in range(ps_len):
    multiprocessing.Process(target = do_distribute, args = (params, index_ps, 'ps')).start()
            
for index_mas in range(master_len):
    multiprocessing.Process(target = do_distribute, args = (params, index_mas, 'master')).start()
                
for index_wor in range(worker_len):
    multiprocessing.Process(target = do_distribute, args = (params, index_wor, 'worker')).start()

当然,还需要在train.py文件中进行一些改动,首先通过flags获取对应的分布式参数,然后构造API预定义的分布式参数输入格式,代码入下

tf.flags.DEFINE_string('distri_param', '{}', 'Distributed params')
tf.flags.DEFINE_string('ps', '', 'Distributed params_ps')
tf.flags.DEFINE_string('master', '', 'Distributed params_master')
tf.flags.DEFINE_string('worker', '', 'Distributed params_worker')
tf.flags.DEFINE_string('index', '', 'Distributed params_index')
tf.flags.DEFINE_string('type', '', 'Distributed params_type')
FLAGS.distri_param = '{"cluster": {"master": ' + FLAGS.master + ', "ps": ' + FLAGS.ps + ', "worker": ' + FLAGS.worker + '}, "task": {"index": ' + FLAGS.index + ', "type": "' + FLAGS.type + '"}}'

定义好API需要的分布式参数格式,下面将其放到如下语句中,即train.py的124行改动如下:

env = json.loads(os.environ.get('TF_CONFIG', params_dict.distri_param))

至此,通过多进程一个窗口自动启动物体检测API的分布式已经完成,示例中采用的是单机单卡,如果使用单机多卡或者机器内存较小的情况下,为了避免单个分布式进程占满资源,根据前文教程博客,改动train.py的149行代码,将原始代码:

server = tf.train.Server(tf.train.ClusterSpec(cluster), protocol='grpc',job_name=task_info.type,task_index=task_info.index)

修改为:

# 修改设置内存动态增长                         
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
server = tf.train.Server(tf.train.ClusterSpec(cluster), protocol='grpc',job_name=task_info.type,task_index=task_info.index,config=config)

修改完这里,在运行分布式的时候,worker进程的内存占用是动态增长的,仔细研究源码发现,修改这个对master节点的其他工作并没有进行动态增长设置,还要单独对master的其他调用GPU的工作进行一下内存动态增长设置:

# 在 trainer.py 文件中找到下一行代码
session_config = tf.ConfigProto(allow_soft_placement=True,
                                log_device_placement=False)

# 在其后添加如下命令
session_config.gpu_options.allow_growth = True

如果你的master,worker都是运行在单个卡上的话,以上两步内存动态增长的设置可以略过,这样设置是为了方式多个进程(一个master,一个worker或者两个worker等)放在同一块卡上执行导致的内存占用不够的问题。

到此,单机多卡的多进程启动分布式完成,在实际的工程中通过后台的rpc服务隐式开启多个进程。

分布式训练结束后,只有‘worker’节点自动退出,而其他节点仍再通信,需要手动kill,相对麻烦,下一篇简单总结如何在分布式训练结束后自动kill进程。

训练结束后自动kill分布式进程(详见下一篇文章)

给TA买糖
共{{data.count}}人
人已赞赏
文章

Windows TensorFlow object_detection API构造XML直接输入

2018-9-10 22:35:48

tensorflow文章目标检测

TensorFlow 物体检测API 分布式部署测试(下)

2018-11-14 20:30:30

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
搜索