web-dev-qa-db-fra.com

Effacement de la mémoire du GPU Tensorflow après l'exécution du modèle

J'ai formé 3 modèles et exécute maintenant un code qui charge chacun des 3 points de contrôle en séquence et exécute les prédictions à l'aide de ceux-ci. J'utilise le GPU.

Lorsque le premier modèle est chargé, il préaffecte la totalité de la mémoire du processeur graphique (ce que je souhaite pour traiter le premier lot de données). Mais cela ne décharge pas la mémoire quand c'est fini. Lorsque le deuxième modèle est chargé, en utilisant à la fois tf.reset_default_graph() et with tf.Graph().as_default(), la mémoire du processeur graphique est toujours entièrement utilisée par le premier modèle et le second modèle est alors privé de mémoire.

Existe-t-il un moyen de résoudre ce problème, mis à part l’utilisation de sous-processus Python ou de multitraitement pour contourner le problème (la seule solution que j'ai trouvée via des recherches Google)?

12
David Parks

Un numéro de git datant de juin 2016 ( https://github.com/tensorflow/tensorflow/issues/1727 ) indique qu'il existe le problème suivant:

actuellement, l’allocateur dans GPUDevice appartient à ProcessState, qui est essentiellement un singleton global. La première session utilisant GPU l'initialise et se libère lorsque le processus s'arrête.

Ainsi, la seule solution de contournement serait d'utiliser des processus et de les fermer après le calcul.

Exemple de code:

import tensorflow as tf
import multiprocessing
import numpy as np

def run_tensorflow():

    n_input = 10000
    n_classes = 1000

    # Create model
    def multilayer_perceptron(x, weight):
        # Hidden layer with RELU activation
        layer_1 = tf.matmul(x, weight)
        return layer_1

    # Store layers weight & bias
    weights = tf.Variable(tf.random_normal([n_input, n_classes]))


    x = tf.placeholder("float", [None, n_input])
    y = tf.placeholder("float", [None, n_classes])
    pred = multilayer_perceptron(x, weights)

    cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
    optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)

    init = tf.global_variables_initializer()

    with tf.Session() as sess:
        sess.run(init)

        for i in range(100):
            batch_x = np.random.Rand(10, 10000)
            batch_y = np.random.Rand(10, 1000)
            sess.run([optimizer, cost], feed_dict={x: batch_x, y: batch_y})

    print "finished doing stuff with tensorflow!"


if __== "__main__":

    # option 1: execute code with extra process
    p = multiprocessing.Process(target=run_tensorflow)
    p.start()
    p.join()

    # wait until user presses enter key
    raw_input()

    # option 2: just execute the function
    run_tensorflow()

    # wait until user presses enter key
    raw_input()

Donc, si vous appelez la fonction run_tensorflow() dans un processus que vous avez créé et fermez le processus (option 1), la mémoire est libérée. Si vous exécutez simplement run_tensorflow() (option 2), la mémoire n'est pas libérée après l'appel de la fonction.

10
Oli Blum

La mémoire GPU allouée par les tenseurs est libérée (de nouveau dans le pool de mémoire TensorFlow) dès que le tenseur n'est plus utilisé (avant la fin de l'appel .run). La mémoire GPU allouée aux variables est libérée lorsque les conteneurs de variables sont détruits. Dans le cas de DirectSession (c'est-à-dire, sess = tf.Session ("")), c'est quand la session est fermée ou explicitement réinitialisée (ajouté dans 62c159ff )

2
Yaroslav Bulatov

Il semble maintenant y avoir deux façons de résoudre le modèle de formation itératif ou si vous utilisez un futur pool de plusieurs processus pour servir la formation de modèle, le processus du pool ne sera pas tué si le futur est terminé. Vous pouvez appliquer deux méthodes dans le processus de formation pour libérer de la mémoire GPU tout en conservant le processus principal.

  1. appelez un sous-processus pour exécuter la formation de modèle. Quand une phase de formation est terminée, le sous-processus se termine et libère de la mémoire. Il est facile d'obtenir la valeur de retour.
  2. appelez multiprocessing.Process (p) pour exécuter la formation de modèle (p.start), et p.join indiquera la sortie du processus et la mémoire disponible.

Voici une fonction d'assistance utilisant multiprocess.Process qui peut ouvrir un nouveau processus pour exécuter votre fonction écrite python et returer une valeur au lieu d'utiliser Subprocess.

# open a new process to run function
def process_run(func, *args):
    def wrapper_func(queue, *args):
        try:
            logger.info('run with process id: {}'.format(os.getpid()))
            result = func(*args)
            error = None
        except Exception:
            result = None
            ex_type, ex_value, tb = sys.exc_info()
            error = ex_type, ex_value,''.join(traceback.format_tb(tb))
        queue.put((result, error))

    def process(*args):
        queue = Queue()
        p = Process(target = wrapper_func, args = [queue] + list(args))
        p.start()
        result, error = queue.get()
        p.join()
        return result, error  

    result, error = process(*args)
    return result, error
0
liviaerxin

J'utilise numpy pour libérer gpu, avec tensorflow je ne trouve pas de méthode d'effet.

import tensorflow as tf
from numba import cuda

a = tf.constant([1.0,2.0,3.0],shape=[3],name='a')
b = tf.constant([1.0,2.0,3.0],shape=[3],name='b')
with tf.device('/gpu:1'):
    c = a+b

TF_CONFIG = tf.ConfigProto(
gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.1),
  allow_soft_placement=True)

sess = tf.Session(config=TF_CONFIG)
sess.run(tf.global_variables_initializer())
i=1
while(i<1000):
        i=i+1
        print(sess.run(c))

sess.close() # if don't use numba,the gpu can't be released
cuda.select_device(1)
cuda.close()
with tf.device('/gpu:1'):
    c = a+b

TF_CONFIG = tf.ConfigProto(
gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.5),
  allow_soft_placement=True)

sess = tf.Session(config=TF_CONFIG)

sess.run(tf.global_variables_initializer())
while(1):
        print(sess.run(c))
0
TanLingxiao