web-dev-qa-db-fra.com

Raccord multi-filetage TensorFlow / Keras

J'essaie de former plusieurs modèles keras avec différentes valeurs de paramètre en utilisant plusieurs threads (et le backend tensorflow). J'ai vu quelques exemples d'utilisation du même modèle dans plusieurs threads, mais dans ce cas particulier, je rencontre diverses erreurs concernant des graphiques en conflit, etc. Voici un exemple simple de ce que j'aimerais pouvoir faire:

from concurrent.futures import ThreadPoolExecutor
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.layers import Dense
from keras.models import Sequential


sess = tf.Session()


def example_model(size):
    model = Sequential()
    model.add(Dense(size, input_shape=(5,)))
    model.add(Dense(1))
    model.compile(optimizer='sgd', loss='mse')
    return model


if __name__ == '__main__':
    K.set_session(sess)
    X = np.random.random((10, 5))
    y = np.random.random((10, 1))
    models = [example_model(i) for i in range(5, 10)]

    e = ThreadPoolExecutor(4)
    res_list = [e.submit(model.fit, X, y) for model in models]

    for res in res_list:
        print(res.result())

L'erreur résultante est ValueError: Tensor("Variable:0", shape=(5, 5), dtype=float32_ref) must be from the same graph as Tensor("Variable_2/read:0", shape=(), dtype=float32).. J'ai également essayé d'initialiser les modèles dans les threads, ce qui donne un échec similaire.

Avez-vous des réflexions sur la meilleure façon de procéder? Je ne suis pas du tout attaché à cette structure exacte, mais je préférerais pouvoir utiliser plusieurs threads plutôt que des processus afin que tous les modèles soient entraînés dans la même allocation de mémoire GPU.

22
bnaul

Les graphiques Tensorflow ne sont pas threadsafe (voir https://www.tensorflow.org/api_docs/python/tf/Graph ) et lorsque vous créez une nouvelle session Tensorflow, il utilise par défaut le graphique par défaut.

Vous pouvez contourner cela en créant une nouvelle session avec un nouveau graphique dans votre fonction parallélisée et en y construisant votre modèle de kéros.

Voici du code qui crée et adapte un modèle sur chaque processeur graphique disponible en parallèle:

import concurrent.futures
import numpy as np

import keras.backend as K
from keras.layers import Dense
from keras.models import Sequential

import tensorflow as tf
from tensorflow.python.client import device_lib

def get_available_gpus():
    local_device_protos = device_lib.list_local_devices()
    return [x.name for x in local_device_protos if x.device_type == 'GPU']

xdata = np.random.randn(100, 8)
ytrue = np.random.randint(0, 2, 100)

def fit(gpu):
    with tf.Session(graph=tf.Graph()) as sess:
        K.set_session(sess)
        with tf.device(gpu):
            model = Sequential()
            model.add(Dense(12, input_dim=8, activation='relu'))
            model.add(Dense(8, activation='relu'))
            model.add(Dense(1, activation='sigmoid'))

            model.compile(loss='binary_crossentropy', optimizer='adam')
            model.fit(xdata, ytrue, verbose=0)

            return model.evaluate(xdata, ytrue, verbose=0)

gpus = get_available_gpus()
with concurrent.futures.ThreadPoolExecutor(len(gpus)) as executor:
    results = [x for x in executor.map(fit, gpus)]
print('results: ', results)
18
dkamm