2017-04-06 2 views
2

J'ai un modèle Keras qui a été formé sur 8 unités centrales. Cela signifie que le modèle a des blocs comme: with tf.device('gpu:0'). Maintenant, je veux appliquer l'apprentissage de transfert avec un autre pc qui a 4 GPU. Cependant, cela entraîne une erreur, très probablement parce que le modèle a été formé sur plus de GPU (error: could not set cudnn tensor descriptor: CUDNN_STATUS_BAD_PARAM). Dans le journal des erreurs, je peux également voir un avertissement que tensorflow essaie de colocaliser les dégradés sur le périphérique GPU 0-7. Y a-t-il un moyen d'adapter ou d'effacer les appareils dans un modèle formé qui est configuré avec Keras?Modifier les attributions de périphériques dans un modèle Keras formé et rechargé

Pour votre information: Je n'ai pas un fichier méta graphique, car le modèle a également été enregistré avec Keras et non avec la fonction d'économie d'tensorflow


Les tentatives actuelles

J'ai essayé pour changer les propriétés de la couche, mais cela ne l'a pas fait fonctionner:

track = 0 
for i in range(len(model.layers)): 
    if model.layers[i].name[:6] == 'lambda': 
     model.layers[i].arguments['n_gpus'] = n_gpus 
     if model.layers[i].arguments['part'] > n_gpus-1: 
      model.layers[i].arguments['part'] = np.arange(n_gpus)[track] 
      track += 1 
      if track > n_gpus-1: 
       track = 0 

En outre, j'ai essayé de définir le nombre de périphériques visibles, qui a également ne fonctionnait pas:

import os 
os.environ['CUDA_VISIBLE_DEVICES'] = "0,1,2,3" 

script pour créer une scission modèle sur 8 GPUs

""" 
to_multi_gpu & slice_batch by: https://github.com/fchollet/keras/issues/2436 
baseline_model by: http://machinelearningmastery.com/ 
""" 
from keras import backend as K 
from keras.models import Sequential, Model 
from keras.layers import Dense, Input, Lambda, merge 
import tensorflow as tf 

def slice_batch(x, n_gpus, part): 
    """ 
    Divide the input batch into [n_gpus] slices, and obtain slice no. [part] 
    i.e. if len(x)=10, then slice_batch(x, 2, 1) will return x[5:]. 
    x: input batch (input shape of model) 
    n_gpus: number of gpus 
    part: id of current gpu 

    return: sliced model per gpu 
    """ 
    sh = K.shape(x) 
    L = sh[0] // n_gpus 
    if part == n_gpus - 1: 
     return x[part*L:] 
    return x[part*L:(part+1)*L] 

def to_multi_gpu(model, n_gpus): 
    """ 
    Given a keras [model], return an equivalent model which parallelizes 
    the computation over [n_gpus] GPUs. 
    Each GPU gets a slice of the input batch, applies the model on that slice 
    and later the outputs of the models are concatenated to a single 
    tensor, hence the user sees a model that behaves the same as the original. 

    model: sequential model created with the Keras library 
    n_gpus: number of gpus 

    return: model divided over n_gpus 
    """ 
    # Only divide model over multiple gpus if there is more than one 
    if n_gpus > 1: 
     with tf.device('/cpu:0'): 
      x = Input(model.input_shape[1:])#, name=model.input_names[0] 

     towers = [] 
     # Divide model over gpus 
     for g in range(n_gpus): 
      # Work on GPU number g. 
      with tf.device('/gpu:' + str(g)): 
       # Obtain the g-th slice of the batch. 
       slice_g = Lambda(slice_batch, lambda shape: shape, 
           arguments={'n_gpus':n_gpus, 'part':g})(x) 
       # Apply model on the batch slice. 
       towers.append(model(slice_g)) 
     # Merge multi-gpu outputs with cpu 
     with tf.device('/cpu:0'): 
      merged = merge(towers, mode='concat', concat_axis=0) 

     return Model(input=[x], output=merged) 
    else: 
     return model 

def baseline_model(num_pixels, num_classes, n_gpus): 
    # create model 
    model = Sequential() 
    model.add(Dense(num_pixels, input_dim=num_pixels, init='normal', activation='relu')) 
    model.add(Dense(num_classes, init='normal', activation='softmax')) 

    model = to_multi_gpu(model, n_gpus) 
    # Compile model 
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) 
    return model 

if __name__ == '__main__': 
    model = baseline_model(784, 9, 8) 

Répondre

0

Utilisation les paramètres ci-dessous l'ont résolu. Cependant, maintenant le modèle fonctionne sur cpu au lieu de gpu. Comme je peaufine ce modèle sur la dernière couche, ce n'est pas un gros problème. Mais si vous voulez recharger et entraîner le modèle complet, cette réponse pourrait ne pas être satisfaisante. Les paramètres importants sont os.environ['CUDA_VISIBLE_DEVICES'] = "" et allow_soft_placement=True.

Le premier masque tous les gpu et le second fait que Tensorflow alloue automatiquement le modèle sur les périphériques disponibles (dans ce cas, la CPU).


Exemple de code

import os 
os.environ['CUDA_VISIBLE_DEVICES'] = "" 
import tensorflow as tf 
from keras.models import load_model 
from keras import backend as K 

if __name__ == '__main__': 
    model = load_model('baseline_model.h5') 
    init = tf.global_variables_initializer() 
    gpu_options = tf.GPUOptions(allow_growth=True) 
    # Add ops to save and restore all the variables. 
    with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, allow_soft_placement=True,\ 
             log_device_placement=True)) as sess: 
     K.set_session(sess) 
     sess.run(init) 
     tf.train.start_queue_runners(sess=sess) 
     # Call model.fit here 
     sess.close()