Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

集群训练比单机更慢? #957

Closed
janelu9 opened this issue Dec 20, 2016 · 33 comments
Closed

集群训练比单机更慢? #957

janelu9 opened this issue Dec 20, 2016 · 33 comments

Comments

@janelu9
Copy link

janelu9 commented Dec 20, 2016

连接了两个服务器 测试lstm模型的集群训练时间,结果比单机还慢(单机是2500s左右,集群是11800s) 且cpu占用不高。

@reyoung
Copy link
Collaborator

reyoung commented Dec 20, 2016

请问如何启动两个机器训练的?

  • 一共有几个 paddle train 进程,几个 paddle pserver 进程?
  • Paddle的计算过程大部分都在 paddle train进程中,如果启动两个paddle pserver和一个paddle train进程,其实也是用一个train进程。也就是使用了一台机器计算。

@reyoung reyoung self-assigned this Dec 20, 2016
@janelu9
Copy link
Author

janelu9 commented Dec 20, 2016

@reyoung 每台机器上都各自有一个paddle_pserver和paddle_train进程

@reyoung
Copy link
Collaborator

reyoung commented Dec 20, 2016

每台机器上都各自有一个paddle_pserver和paddle_train进程

可否把启动的方法贴一下?

@janelu9
Copy link
Author

janelu9 commented Dec 20, 2016

HOSTS = [
"root@172.17.0.6",
"root@10.0.0.5",
]
'''
workspace configuration
'''
#root dir for workspace, can be set as any director with real user account
ROOT_DIR = "/mnt/home/paddle"
'''
network configuration
'''
#pserver nics
PADDLE_NIC = "eth0"
#pserver port
PADDLE_PORT = 7164
#pserver ports num
PADDLE_PORTS_NUM = 8
#pserver sparse ports num
PADDLE_PORTS_NUM_FOR_SPARSE = 2

#environments setting for all processes in cluster job
LD_LIBRARY_PATH = "/usr/local/cuda/lib64:/usr/lib64"

@janelu9
Copy link
Author

janelu9 commented Dec 20, 2016

python paddle.py
--job_dispatch_package="/mnt/news-lstm-cluster"
--dot_period=10
--ports_num_for_sparse=2
--log_period=1000
--num_passes=5
--trainer_count=4
--saving_period=1
--local=0
--config=./trainer_config.lstm2.py
--save_dir=./output
--use_gpu=0

看cpu占用率一直也不高 百分之十几
@reyoung

@reyoung
Copy link
Collaborator

reyoung commented Dec 20, 2016

不是特别清楚,可能的原因有

  • 本地和集群,二者训练的数据量是不是不同?比如,如果是两台机器跑同一个训练,那么这两台机器上应该各有一半的数据。
  • 是不是batch size过小,导致网络成为了瓶颈?如果单个batch的计算时间很短的话,多机的瓶颈可能都在网络通信上。
  • 是不是节点间网络连接太差。
  • 是不是在使用NFS之类的文件系统,导致两个训练进程其实都在一个服务器上读数据?

@janelu9
Copy link
Author

janelu9 commented Dec 20, 2016

@reyoung 直接用的实例的脚本 设置基本上都是默认 因该是把数据等量复制到另一台服务器上了
batch_size可能是瓶颈
文件系统 不是nfs

@reyoung
Copy link
Collaborator

reyoung commented Dec 20, 2016

因该是把数据等量复制到另一台服务器上了

等量的复制,那么一个pass过的数据量相当于原来两个pass,时间就至少要乘2了。

batch_size可能是瓶颈

batch size可以调大一些。

另外trainer_count是设置使用多少块CPU/GPU的参数,可以和系统的CPU核数一样或者是核数减一比较好

@backyes
Copy link
Contributor

backyes commented Dec 20, 2016

--job_dispatch_package="/mnt/news-lstm-cluster" 

会把所有数据复制到所有节点, 这个功能主要帮助调试阶段使用,避免到每个节点上手工准备数据。 这个参数使得所有节点利用同样的数据副本进行训练。

多机调试pass过后,建议使用下面参数进行训练:

--job_workspace

这个参数会引用所有节点中 --job_workspace 引用的目录,完成多机训练。 因此, 用户需要手工划分每个节点的训练数据。

@backyes
Copy link
Contributor

backyes commented Dec 20, 2016

@janelu9

至于性能描述,每个节点cpu都比较闲, 应该是其他原因导致的。 @reyoung 已经提供了若干思路。

另外,请尽可能提供更多的数据:

  • cpu 物理core数
  • 网络带宽
  • 请动态观察sar -n DEV 1 输出, 获取粗糙的网络带宽性能
  • 模型总大小(可以通过单机跑完一个pass存储下来,看看模型文件总大小)
  • 单机训练平均一个min-batch 耗时
  • 贴出模型配置中 setting中的batch_size配置
  • 如果上述信息,仍然不够,也请提供dataprovider配置,或者简单描述下是什么数据等等。

上述信息,对预判性能瓶颈比较重要。

@backyes
Copy link
Contributor

backyes commented Dec 20, 2016

@janelu9

另外, Paddle也提供了performance tuning tools, 会动态实时获取运行时,dataprovider数据准备阶段、计算不同阶段、sgd更新、多机参数更新、多机同步效率等工具,甚至该工具能帮你捕获实际每条连接通信阶段的耗时(不包括准备数据)、每条连接耗时分布等等。

打开编译选项: WITH_TIMER 能使能上述功能。

@janelu9
Copy link
Author

janelu9 commented Dec 21, 2016

@backyes batch_size变大(之前是256 现在增大到2048单次训练时间减少了4倍)但等于成倍的减少了训练次数 最后精度会下降 为了达到收敛还也要增大num_passes 总的训练时间 还是增加了 主要cpu占用上不去

@janelu9
Copy link
Author

janelu9 commented Dec 21, 2016

@backyes 训练数据是50万条词id 每个样本大约有10几个id
ef initializer(settings, dictionary, **kwargs):
settings.word_dict = dictionary
settings.input_types = [
integer_value_sequence(dictn),
integer_value(12)]

@Provider(init_hook=initializer, cache=CacheType.CACHE_PASS_IN_MEM)
def process(settings, file_name):
with open(file_name, 'r') as f:
for line in f:
simple = line.strip().split('\t')
words = map(int,simple[0:-1])
label=int(simple[-1])
yield word,label

@reyoung
Copy link
Collaborator

reyoung commented Dec 21, 2016

  • trainer_count设置了多少?
  • 如果data provider设置了CacheType.CACHE_PASS_IN_MEM,那么当第二个pass的时候,数据读取的速度会明显加快。也就是第二个Pass及之后Pass会快很多。
  • 增大batch_size不一定会成比例增大num_passes。例如batch_size扩大两倍,num_passes也许只需要增加1.1倍就能收敛。但是训练速度有很大的提升。
    • 另外,如果真考虑收敛时间,优化算法(Optimizer)的选择也是非常重要的。对于sparse数据的情况,推荐用rmsprop。

@backyes
Copy link
Contributor

backyes commented Dec 21, 2016

@janelu9

@reyoung 给的算法层面的优化建议你可以先试试。

另外如果想我们帮助你分析系统性能低的确切的原因, 麻烦请先回复comment列出的所以量化数据, 否则我们也只能猜测。

从你后续增大batch size训练时间剧减的现象,推断极可能是互联效率低下导致的。 如果是1000Mb网卡互联,做一次迭代运算需要传输2 * model_size的数据量, 你可以推算出理论极限耗时。

@janelu9
Copy link
Author

janelu9 commented Dec 21, 2016

@reyoung trainer_count设置1个 cpu物理核心是两个 mini_batch是什么参数 没有看到啊

@reyoung
Copy link
Collaborator

reyoung commented Dec 21, 2016

trainer_count设置1个 cpu物理核心是两个

推荐直接把trainer_count设置成2

另外,看起来硬件并不给力啊。这么看还是得看一下网卡是什么型号的,网络参数是什么样的。有可能网卡是100M之类的,那就非常不适合深度学习了。

可以直接benchmark一下两台机器的网络情况,最高带宽有多少。

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@backyes -WITH_TIMER是在编译时打开的吧 docker镜像里有么?

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@reyoung cpu物理核心是两个 但有48个线程 网卡是千兆网卡 trainer_count不是设置gpu或者thread个数的么 我看官方文档上说的

@backyes
Copy link
Contributor

backyes commented Dec 22, 2016

经验上来说,对于这种纯浮点运算为主的神经网路,在cpu上,计算单元一般要比访存先成为瓶颈,因此一般不建议开巨多的线程,只会增加切换代价。

另外,两个物理核心对应48个超线程,是什么处理器?方便的话就cat /proc/cpuinfo看看,可能彼此对概念的理解不一样。

另外,我觉得你能提供我上面给出的几个items量化数据,对诊断你的性能问题非常重要。请提供全一点。

另外,前兆网卡的确不太合适做深度学习分布式训练,会让通信成为瓶颈。

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@backyes
cat cpu部分信息:
processor: 47
vendor_id: GenuineIntel
cpu family: 6
model: 63
model name: intel Xeon cpu e5-2670 v3 @2.3g
stepping 2
microcode 0*36
cpu mhz:1298.332
cache size: 30720kb
physical id:1
siblings : 24
core id:13
cpu cores:12
.....
参数总大小 90m左右
batch_size=8192
环境是8cpu的docker镜像
加大了batch_size速度是快了 但是 错误率每次都没有变化了 怎么回事

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

单机上错误率 可以稳定在0.03左右 集群训练成了0.1而且一直不变化

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@backyes 网络监控读写大概160m/s左右

@reyoung
Copy link
Collaborator

reyoung commented Dec 22, 2016

cpu物理核心是两个 但有48个线程 网卡是千兆网卡 trainer_count不是设置gpu或者thread个数的么 我看官方文档上说的

如果是用了8CPU的docker镜像,那trainer_count开到8左右。

加大了batch_size速度是快了 但是 错误率每次都没有变化了 怎么回事

算法不拟合说明学习率之类的东西没调对。。。用RmsProp,学习率设成1e-3左右,一般不会是最差的。单机和多机对于batch_size的概念是不一样的。参考文档

http://www.paddlepaddle.org/doc/ui/api/trainer_config_helpers/optimizers.html#settings

docker镜像里

一来千兆网络带宽确实略少。二来,在docker里面的网络应该是过bridge的吧,可能性能会有一些损失。尝试下直接--host用主机网卡。

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@reyoung 学习率是1e-3配置跟单机上的一样 但好像集群训练没训练一次 都是重新训练

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@reyoung host的话,paddle的IP和端口应该如何配置,直接配置主机IP的话,主机能知道这是发给DOCKER的吗?

@reyoung
Copy link
Collaborator

reyoung commented Dec 22, 2016

学习率是1e-3配置跟单机上的一样 但好像集群训练没训练一次 都是重新训练

确定第二个Pass和第一个Pass的Cost完全一样么?

尝试一下学习率调成 5e-4

host的话,paddle的IP和端口应该如何配置,直接配置主机IP的话,主机能知道这是发给DOCKER的吗?

和怎么使用docker的bridge网络,没区别。

@backyes
Copy link
Contributor

backyes commented Dec 22, 2016

@janelu9

从你提供的信息,我们对齐下各自对概念的理解,然后在讨论系统层面的性能问题:

cat cpu部分信息:
processor: 47
vendor_id: GenuineIntel
cpu family: 6
model: 63
model name: intel Xeon cpu e5-2670 v3 @2.3g
stepping 2
microcode 0*36
cpu mhz:1298.332
cache size: 30720kb
physical id:1
siblings : 24
core id:13
cpu cores:12
.....
参数总大小 90m左右
batch_size=8192
环境是8cpu的docker镜像
加大了batch_size速度是快了 但是 错误率每次都没有变化了 怎么回事

官网查到: e5-2670 v3 处理器(Cpu Socket), 有12个物理核(cpu core)、允许设置24个超线程(HyperThread)


-Performance
# of Cores	12
# of Threads	24

另外,

processor: 47
physical id:1

一般来说,从上面的信息确定, 你的单节点(node,就是一个服务器)配备2颗e5-2670 v3 cpu(一般叫cpu socket), 每个socket cpu拥有12个物理核(cpu core),每个物理核能开启2个超线程(对应到cat /proc/cpuinfo中的processor)。 所以, 你说的两个核,是指两个cpu socket, 而不是理解的2个cpu core。

所以,建议trainer_count的设置要参照cpu core的数目,所以建议配置成48。(也可以考虑对比下关闭超线程,然后使用24个trainer_count来对比下性能,一般这种浮点运算量大的任务,超线程作用不大,反而会污染cache,降低数据访存效率,但是最终取决于你的模型特点)。

上面是你如果在裸机下跑的配置建议。 你用的是docker, 具体参照上述方法,根据docker配置自行调整。

网络监控读写大概160m/s左右

你是千兆网卡,所以这里160m/s 具体应该是160Mb/s (因此160MB/s 就不止千兆理论峰值了)? 如果是这样的话, 那么实际你每秒只能传输20MB数据。

90m 模型 ( 我理解应该是90MB,因为是磁盘文件)

推断, 90MB/20MB ~=4.5s, 所以完成一次迭代需要的传输时间最短要4.5 *2 = 9s 。 (这个严格参照了你提供的网络流量均值数据)

环境是8cpu的docker镜像

docker 默认会通过linux kernel的tcp/ip stack 来做network 的virtualization,所以你的传输代价可能会收到linux kenrel 的iptables等的性能影响。 但是你160m/s 的传输速度本身应该不会触发到tcp/ip 的performance bottelneck。

你可以尝试通过,增加--port_num, 来增加网络通信的并发度,尝试驾驭1G网络的带宽。 记得,千兆网卡应该也是多核多队列支持的,所以,--port_num 间接增加的连接数,不仅能提高网络带宽的利用效率,提高tcp性能, 同时也能提高paddle pserver的parameter update并行度,优化整体的pserver性能。 (因为你的计算节点只有2个,但是如果计算节点数量与单节点的cpu core相当,那么你就不要考虑增加--port_num) 。

综上, 尝试优化方法:

  • 增加--port_num

  • 调整好cpu core和trainer_count的对应关系

  • 有条件,请使用更高效的互联方案,否则多机是很难成功的。

@janelu9
Copy link
Author

janelu9 commented Dec 22, 2016

@backyes 物理网卡传输速率是130mb/s ,刚才说的160mb/s
是算上了docker的传输速率(nmon监控时候重复统计了)

@backyes
Copy link
Contributor

backyes commented Dec 22, 2016

@janelu9

试试 @reyoung 和 我上面给的优化建议吧。 网络带宽也有瞬间突发,你提供的130Mb或者160Mb也都是仅能用于参考估算。

另外, 与其两台机器,每个机器跑8个核的docker(48个线程)运行分布式任务,不如一台机器跑48个线程跑单机任务。

@janelu9
Copy link
Author

janelu9 commented Dec 23, 2016

@backyes 额 这个主要是为了测试paddle和其他平台的集群训练效率 将来会选择一个做长远使用

@backyes
Copy link
Contributor

backyes commented Dec 25, 2016

@janelu9

感谢您的关注。另外, https://github.com/PaddlePaddle/Paddle/tree/develop/benchmark 这里有一些公开的benchmark测试数据,包括评测代码。

另外,多机的性能与system level的优化至关紧要,因此从你目前的多机互联配置来看,可能所有平台都不会获取较好的性能。

另外, 从目前的讨论来看,您的多机互联网络的瓶颈是制约多机性能的主要因素。 另外也欢迎您share使用上述优化建议后的进一步性能数据。

综上, 尝试优化方法:

增加--port_num

调整好cpu core和trainer_count的对应关系

有条件,请使用更高效的互联方案,否则多机是很难成功的。

如果此处的讨论解决了你的问题,请关闭此issue :-)

@typhoonzero
Copy link
Contributor

Closing this issue due to inactivity, feel free to reopen it.

zhhsplendid pushed a commit to zhhsplendid/Paddle that referenced this issue Sep 25, 2019
* update mobile according to paddle-mobile repo

* Update mobile_readme_en.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants