我想在张量流会话中并行运行多个train_op.答案在这里说,tensorflow sess.run()可以释放python的GIL.我在anwser中尝试了这个例子,但似乎我们仍然有一个GIL.我有8个GPU可用.当num_threads为4时,需要24秒.当num_threads为8时,需要54秒.
这是代码:
from threading import Thread
import tensorflow as tf
import time
num_threads = 8
a = []
for i in range(num_threads):
with tf.device('/cpu:0'):
a.append(tf.get_variable(name='a_%d'%i, shape=[5000, 50, 5, 5, 5, 5], initializer=tf.truncated_normal_initializer()))
b = []
for i in range(num_threads):
with tf.device('/cpu:0'):
b.append(tf.get_variable(name='b_%d'%i, shape=[5000, 50, 5, 5, 5, 5], initializer=tf.truncated_normal_initializer()))
train_ops = []
for i in range(num_threads):
with tf.device('gpu:%d'%i):
loss = tf.multiply(a[i], b[i], name='loss_%d'%i)
train_ops.append(tf.train.GradientDescentOptimizer(0.01).minimize(loss))
sess = tf.Session()
sess.run(tf.initialize_all_variables())
def train_function(train_op):
for i in range(20):
sess.run(train_op)
train_threads = []
for train_op in train_ops:
train_threads.append(Thread(target=train_function, args=(train_op,)))
start = time.time()
for t in train_threads:
t.start()
for t in train_threads:
t.join()
end = time.time()
print('elapsed time is:', end-start)
Run Code Online (Sandbox Code Playgroud)
我的问题是,是否因为我没有正确实施该方法.如果这种方式无法释放GIL,那么如何释放GIL?
我知道通过gRPC的分布式张量流可以释放GIL,但是与多线程(如C中的pthread)相比,gRPC是昂贵的.我希望每个线程相互通信,我希望尽可能减少通信开销.任何答案或提示都会非常感激!
如果无法释放GIL,是否可以编写c ++扩展来进行多线程处理.如果没有,是否可以使用除python之外没有GIL的其他语言.谢谢!
Tensorflow 仅在sess.run
被调用时才会释放 GIL (请参阅此评论)。您sess.run
从受 GIL 限制的代码中调用;因此,sess.run
按顺序调用每个训练操作。我相信 GIL 的发布是为了与tf.py_func
.
你想要完成的事情已经由 tensorflow 实现,几乎没有任何额外的代码。Tensorflow 已经在不同的设备上同时启动内核。
您的代码也非常低效,您将权重存储在 CPU 上。这是一个巨大的瓶颈。每次迭代,权重都被复制到每个 GPU,梯度被复制回 CPU,在那里更新它们(即更新发生在 CPU 上!)。当您增加所涉及的 GPU 数量时,副本数量会成倍增加,CPU 更新时间会线性增长。
我修复了您的代码以遵循最佳实践:
import tensorflow as tf
import time
num_threads = 1
n = 5000
a = []
for i in range(num_threads):
#store each variable one the device that it will be used on
with tf.device('gpu:%d'%i):
a.append(tf.get_variable(name='a_%d'%i, shape=[n, 50, 5, 5, 5, 5], initializer=tf.truncated_normal_initializer()))
b = []
for i in range(num_threads):
with tf.device('gpu:%d'%i):
b.append(tf.get_variable(name='b_%d'%i, shape=[n, 50, 5, 5, 5, 5], initializer=tf.truncated_normal_initializer()))
train_ops = []
for i in range(num_threads):
#now when a and b are accessed when the graph is executed
#the variables will already be in VRAM
with tf.device('gpu:%d'%i):
loss = tf.multiply(a[i], b[i], name='loss_%d'%i)
train_ops.append(tf.train.GradientDescentOptimizer(0.01).minimize(loss))
sess = tf.Session()
sess.run(tf.initialize_all_variables())
#dry run
sess.run(train_ops)
start = time.time()
for i in range(200):
sess.run(train_ops)
end = time.time()
print('elapsed time is:', end-start)
Run Code Online (Sandbox Code Playgroud)
在运行时我现在得到的是3.67962
与3.64852
1个2的GPU与200次迭代,而20运行我只能获得2个GPU,所以我不能在4个测试,但结果应该是一样的。
你可以在他们的网站上阅读更多关于如何在多个 GPU 上使用 tensorflow的信息。请注意,我还包括了一个试运行。这在 tensorflow 中是必需的,因为第一次调用sess.run
在每个 GPU 上分配内存。这意味着您拥有的 GPU 越多,第一次调用的时间就越多,因此应该忽略它。
归档时间: |
|
查看次数: |
759 次 |
最近记录: |