Multi GPU en keras

33

¿Cómo puede programar en la biblioteca de keras (o flujo de tensor) para particionar el entrenamiento en múltiples GPU? Digamos que se encuentra en una instancia de Amazon ec2 que tiene 8 GPU y desea utilizarlas todas para entrenar más rápido, pero su código es solo para una sola CPU o GPU.

Hector Blandin
fuente
3
¿Has consultado el tensorflow doc?
n1tk
@ sb0709: comencé a leer esta mañana pero me preguntaba cómo hacerlo en keras
Hector Blandin
1
no sé en keras pero para tensorflow: tf usará GPU por defecto para el cálculo, incluso si es para CPU (si está presente GPU compatible). así que puede hacer un bucle for: "for d en ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]:" y en el "tf.device (d)" debe incluir todos los recursos de la GPU de su instancia. Por lo tanto, se utilizará tf.device ().
n1tk
Me gusta esto ?? para d en ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]: tf.device (d) y eso es? Lo intentaré así :)
Hector Blandin
1
Por lo que sé, sí, puedes hacer cualquier tarea en un dispositivo diferente.
n1tk

Respuestas:

37

De las preguntas frecuentes de Keras:

https://keras.io/getting-started/faq/#how-can-i-run-a-keras-model-on-multiple-gpus

A continuación se muestra el código copiado para habilitar el "paralelismo de datos". Es decir, que cada una de sus GPU procese un subconjunto diferente de sus datos de forma independiente.

from keras.utils import multi_gpu_model

# Replicates `model` on 8 GPUs.
# This assumes that your machine has 8 available GPUs.
parallel_model = multi_gpu_model(model, gpus=8)
parallel_model.compile(loss='categorical_crossentropy',
                       optimizer='rmsprop')

# This `fit` call will be distributed on 8 GPUs.
# Since the batch size is 256, each GPU will process 32 samples.
parallel_model.fit(x, y, epochs=20, batch_size=256)

Tenga en cuenta que esto parece ser válido solo para el backend de Tensorflow en el momento de la escritura.

Actualización (febrero de 2018) :

Keras ahora acepta la selección automática de gpu usando multi_gpu_model, por lo que ya no tiene que codificar el número de gpus. Detalles en esta solicitud de extracción . En otras palabras, esto habilita un código que se ve así:

try:
    model = multi_gpu_model(model)
except:
    pass

Pero para ser más explícito , puedes seguir con algo como:

parallel_model = multi_gpu_model(model, gpus=None)

Bono :

Para verificar si realmente está utilizando todas sus GPU, específicamente las de NVIDIA, puede monitorear su uso en el terminal usando:

watch -n0.5 nvidia-smi

Referencias

weiji14
fuente
¿ multi_gpu_model(model, gpus=None)Funciona en el caso de que solo haya 1 GPU? Sería genial si se adaptara automáticamente a la cantidad de GPU disponibles.
CMCDragonkai
Sí, creo que funciona con 1 GPU, consulte github.com/keras-team/keras/pull/9226#issuecomment-361692460 , pero es posible que tenga que tener cuidado de que su código esté adaptado para ejecutarse en un multi_gpu_model en lugar de un modelo simple . Para la mayoría de los casos, probablemente no importaría, pero si va a hacer algo como tomar la salida de alguna capa intermedia, deberá codificar en consecuencia.
weiji14
¿Tiene alguna referencia a las diferencias del modelo multi gpu?
CMCDragonkai
Esa referencia fue genial @ weiji14. Sin embargo, también estoy interesado en cómo funciona esto por inferencia. ¿Keras de alguna manera divide lotes de manera equitativa o programa de turnos en réplicas de modelos disponibles?
CMCDragonkai
4
  1. Para TensorFlow:

TensorFlow con GPU

Aquí está el código de muestra sobre cómo se usa, por lo que para cada tarea se especifica la lista con dispositivos / dispositivo:

# Creates a graph.
c = []
for d in ['/gpu:2', '/gpu:3']:
  with tf.device(d):
    a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3])
    b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2])
    c.append(tf.matmul(a, b))
with tf.device('/cpu:0'):
  sum = tf.add_n(c)
# Creates a session with log_device_placement set to True.
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
# Runs the op.
print(sess.run(sum))

tf usará GPU de manera predeterminada para el cálculo, incluso si es para CPU (si está presente GPU compatible). así que puede hacer un bucle for: "for d en ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]:" y en el "tf.device (d)" debe incluir todos los recursos de la GPU de su instancia. Por lo tanto, se utilizará tf.device ().

Escalando el entrenamiento del modelo Keras a múltiples GPU

  1. Keras

Para Keras usando Mxnet que args.num_gpus , donde num_gpus es la lista de las GPU requeridas.

def backend_agnostic_compile(model, loss, optimizer, metrics, args):
  if keras.backend._backend == 'mxnet':
      gpu_list = ["gpu(%d)" % i for i in range(args.num_gpus)]
      model.compile(loss=loss,
          optimizer=optimizer,
          metrics=metrics, 
          context = gpu_list)
  else:
      if args.num_gpus > 1:
          print("Warning: num_gpus > 1 but not using MxNet backend")
      model.compile(loss=loss,
          optimizer=optimizer,
          metrics=metrics)
  1. horovod.tensorflow

Además de todo, Uber de origen abierto Horovod recientemente y creo que es genial:

Horovod

import tensorflow as tf
import horovod.tensorflow as hvd

# Initialize Horovod
hvd.init()

# Pin GPU to be used to process local rank (one GPU per process)
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())

# Build model…
loss = 
opt = tf.train.AdagradOptimizer(0.01)

# Add Horovod Distributed Optimizer
opt = hvd.DistributedOptimizer(opt)

# Add hook to broadcast variables from rank 0 to all other processes during
# initialization.
hooks = [hvd.BroadcastGlobalVariablesHook(0)]

# Make training operation
train_op = opt.minimize(loss)

# The MonitoredTrainingSession takes care of session initialization,
# restoring from a checkpoint, saving to a checkpoint, and closing when done
# or an error occurs.
with tf.train.MonitoredTrainingSession(checkpoint_dir=“/tmp/train_logs”,
                                      config=config,
                                      hooks=hooks) as mon_sess:
 while not mon_sess.should_stop():
   # Perform synchronous training.
   mon_sess.run(train_op)
n1tk
fuente
2

Básicamente, puede tomar ejemplo del siguiente ejemplo. Todo lo que necesita es especificar los valores de consumo de CPU y GPU después de importar keras.

import keras

config = tf.ConfigProto( device_count = {'GPU': 1 , 'CPU': 56} )
sess = tf.Session(config=config) 
keras.backend.set_session(sess)

Después de eso, te quedaría el modelo.

model.fit(x_train, y_train, epochs=epochs, validation_data=(x_test, y_test))

Finalmente, puede disminuir los valores de consumo, no el trabajo en los límites superiores.

johncasey
fuente