0

所以我有以下情况:

  1. 带3张显卡的电脑
  2. 使用带有 Theano 后端和多线程的 Keras 的 python 脚本

我按照.theanorc文档中的说明指定了要使用的设备。

python 脚本是这种形式(仍然在一个独立的例子中工作):

import theano
from threading import Thread
...
class Test(Thread):

    def run(self):
        #calculations with Keras

test = Test()
test.start()
test.join()

启动脚本 Theano 使用指定的设备,但一段时间后,第二个 python 线程出现在其他显卡之一上(并耗尽资源)。

第二个线程似乎忽略了配置,因为它在错误的 GPU 上运行,并且没有按照CNEM标志指定的分配内存。

根据文档,这应该是不可能的,因为从启动 Theano 计算的线程派生的所有内容都应该在同一设备上运行(通过在开始时正确导入 Theano 来确保)。

经过一番摸索后,我发现当我不在单独的线程中运行我的 Keras 代码时,这种行为就会停止。

所以在我开始创建 Github 问题之前,我想要一些最有可能的指针:

  1. 这是 Theano 中的错误吗?
  2. 这是 Keras 中的错误吗?
  3. 这是我自己代码中的错误吗?

@3。我的整个项目没有创建单独的 Python 进程(通过进程列表确认),也没有更改任何 Theano 配置。

知道什么甚至会导致这种行为吗?

4

1 回答 1

2

一个线程的Device(gpu)设置独立于同一进程中的其他线程。查看以获取更多详细信息。

我还没有找到在 Theano 中为当前线程设置设备的方法。我使用过时cuda_ndarray的后端,没有办法做到这一点,但我不知道gpuarray后端是否有办法做到这一点。

我做了一些解决方法:

import numpy as np
import theano
from theano import Apply
from theano import tensor as T
from theano.scalar import Scalar
from theano.sandbox.cuda import GpuOp, nvcc_compiler

class SetGpu(GpuOp):
    '''
    Set device(gpu) for current thread.
    '''

    def c_compiler(self):
        return nvcc_compiler.NVCC_compiler

    def make_node(self, gpu_id):
        dummy_out = Scalar("int32")()
        return Apply(self, [gpu_id], [dummy_out])

    def __str__(self):
        return "SetGpu"

    def c_support_code_apply(self, node, nodename):
        return ""

    def c_code(self, node, nodename, inps, outs, sub):
        gpu_id, = inps
        dummy_out, = outs
        return """
        int _gpu_id = *((int*)PyArray_DATA(%(gpu_id)s));
        %(dummy_out)s = _gpu_id;
        cudaError_t err = cudaSetDevice(_gpu_id);
        if(err != cudaSuccess){
            PyErr_Format(PyExc_RuntimeError, "Cuda err:\\"%%s\\" when calling cudaSetDevice(%%d).", cudaGetErrorString(err), _gpu_id);
            return 0;
        }
    """ % locals()

def set_gpu(gpu_id):
    if not hasattr(set_gpu, "f"):
        set_gpu_op = SetGpu()
        gpu_id_var = T.iscalar()
        dummy_out = set_gpu_op(gpu_id_var)
        set_gpu.f = theano.function([gpu_id_var], [dummy_out])
    _dummy_out = set_gpu.f(gpu_id)

if __name__ == "__main__":
    def test():
        set_gpu(5)
        print "Test thread is using gpu %d." % theano.sandbox.cuda.active_device_number()
    print "Main thread is using gpu %d." % theano.sandbox.cuda.active_device_number()
    from threading import Thread
    thread = Thread(target=test)
    thread.start()
    thread.join()

所以我们称这个文件为 set_gpu.py

这是我运行它的内容:

python set_gpu.py 
WARNING (theano.sandbox.cuda): The cuda backend is deprecated and will be removed in the next release (v0.10).  Please switch to the gpuarray backend. You can get more information about how to switch at this URL:
 https://github.com/Theano/Theano/wiki/Converting-to-the-new-gpu-back-end%28gpuarray%29

Using gpu device 0: Tesla K80 (CNMeM is enabled with initial size: 95.0% of memory, cuDNN 5110)
Main thread is using gpu 0.
Test thread is using gpu 5.
于 2018-02-01T11:15:13.437 回答