2017-03-14 1 views
0

J'ai la situation suivante:Théano crée des threads supplémentaires sur les appareils non spécifiés dans la configuration

  1. ordinateur avec 3 cartes graphiques
  2. script python utilisant Keras avec backend Théano et plusieurs threads

J'ai spécifié l'appareil à utiliser dans .theanorc comme décrit dans la documentation.

Le script python est de cette forme (travaille toujours sur un exemple autonome):

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

    def run(self): 
     #calculations with Keras 

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

À partir du script Théano utilise le périphérique spécifié, mais après un certain temps un second fil de python apparaît sur l'un de l'autre graphique cartes (et utilise des ressources).

Le deuxième thread semble ignorer la configuration car il s'exécute sur le mauvais GPU et n'alloue pas de RAM comme spécifié par l'indicateur CNEM. Cela ne devrait pas être possible selon la documentation, car tout ce qui forke depuis le thread qui a commencé le calcul de Theano devrait être exécuté sur le même périphérique (en assurant l'importation de Theano dès le début). Après quelques recherches, j'ai découvert que ce comportement s'arrêtait lorsque je n'exécutais pas mon code Keras dans un thread séparé.

Alors avant que je commence à créer des problèmes Github je voudrais quelques conseils ce qui est le plus probable:

  1. Est-ce un bogue dans Théano?
  2. Est-ce un bug dans Keras?
  3. Est-ce un bug dans mon propre code?

@ 3. Mon projet entier ne crée pas de processus Python séparés (confirmé par la liste de processus) et ne modifie aucune configuration de Theano.

Une idée de ce qui pourrait même provoquer ce genre de comportement?

+0

Comme vous ne partagez pas n'importe quel code c'est difficile à dire ... je peux voir que tu cours un fil ... mais rien de plus ... – PyNico

+0

C'est pourquoi je demande comment cela peut même arriver (je travaille toujours sur un exemple autonome car je n'ai actuellement pas accès à un ordinateur avec plus d'une carte graphique). –

+0

Juste comme ça je dirais que c'est probablement votre code, mais Theano pourrait avoir ce genre de problème, pour Keras ce serait bizarre mais pourquoi pas. – PyNico

Répondre

2

Le réglage du périphérique (gpu) d'un thread est indépendant des autres threads du même processus. Regardez this pour plus de détails.

Je n'ai pas trouvé un moyen de définir le périphérique pour le thread en cours dans Theano. J'utilise obsolète cuda_ndarray back end, il n'y a aucun moyen de le faire, mais je ne sais pas s'il existe un moyen de le faire dans gpuarray back end.

Je fais une solution de contournement:

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() 

Alors Appelons ce fichier set_gpu.py

voici ce que je me exécuter:

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.