Multi GPU em keras

33

Como você pode programar na biblioteca keras (ou tensorflow) para particionar o treinamento em várias GPUs? Digamos que você esteja em uma instância do Amazon ec2 com 8 GPUs e que gostaria de usá-los para treinar mais rapidamente, mas seu código é apenas para uma única CPU ou GPU.

Hector Blandin
fonte
3
você verificou o documento tensorflow?
N1tk 19/10/19
@ sb0709: Comecei a ler esta manhã, mas eu queria saber como fazê-lo em keras
Hector Blandin
1
não sei em keras, mas para o fluxo tensor: o tf usará a GPU por padrão para computação, mesmo que seja para CPU (se houver GPU suportada). para que você possa fazer um loop for: "para d em ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]:" e no "tf.device (d)" deve incluir todos os recursos da GPU da sua instância. Então tf.device () será realmente usado.
N1tk 19/10/19
Como isso ?? para d em ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]: tf.device (d) e é isso? Vou tentar assim :)
Hector Blandin
1
Até onde eu sei, você pode executar qualquer tarefa em um dispositivo diferente.
N1tk 19/10/19

Respostas:

37

Nas perguntas frequentes de Keras:

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

Abaixo está o código copiado e colado para ativar o 'paralelismo de dados'. Ou seja, cada uma das suas GPUs processa um subconjunto diferente de seus dados independentemente.

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)

Observe que isso parece ser válido apenas para o back-end do Tensorflow no momento da gravação.

Atualização (fev 2018) :

O Keras agora aceita a seleção automática de gpu usando multi_gpu_model, para que você não precise mais codificar o número de gpus. Detalhes nesta solicitação de recebimento . Em outras palavras, isso habilita um código parecido com este:

try:
    model = multi_gpu_model(model)
except:
    pass

Mas, para ser mais explícito , você pode usar algo como:

parallel_model = multi_gpu_model(model, gpus=None)

Bônus :

Para verificar se você realmente está utilizando todas as suas GPUs, especificamente as da NVIDIA, você pode monitorar seu uso no terminal usando:

watch -n0.5 nvidia-smi

Referências:

weiji14
fonte
O multi_gpu_model(model, gpus=None)trabalho funciona no caso em que há apenas 1 GPU? Seria legal se ele se adaptasse automaticamente ao número de GPUs disponíveis.
precisa saber é o seguinte
Sim, acho que funciona com 1 GPU, consulte github.com/keras-team/keras/pull/9226#issuecomment-361692460 , mas talvez seja necessário ter cuidado para que seu código seja adaptado para execução em um multi_gpu_model em vez de um modelo simples . Na maioria dos casos, isso provavelmente não importa, mas se você fizer algo como obter a saída de alguma camada intermediária, precisará codificar de acordo.
precisa saber é o seguinte
Você tem alguma referência a diferenças no modelo de várias GPUs?
CMCDragonkai
Você quer dizer algo como github.com/rossumai/keras-multi-gpu/blob/master/blog/docs/… ?
precisa saber é o seguinte
Essa referência foi ótima @ weiji14. No entanto, também estou interessado em como isso funciona para inferência. De alguma forma, as keras dividem lotes igualmente ou arredondam a programação de robin nas réplicas de modelos disponíveis?
CMCDragonkai
4
  1. Para TensorFlow:

TensorFlow usando GPUs

Aqui está o código de exemplo de como é usado, portanto, para cada tarefa é especificada a lista com 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á a GPU por padrão para computação, mesmo que seja para CPU (se houver GPU suportada). para que você possa fazer um loop for: "para d em ['/ gpu: 1', '/ gpu: 2', '/ gpu: 3' ... '/ gpu: 8',]:" e no "tf.device (d)" deve incluir todos os recursos da GPU da sua instância. Então tf.device () será realmente usado.

Escalando o treinamento do modelo Keras para várias GPUs

  1. Keras

Para Keras usando Mxnet do que args.num_gpus , em que num_gpus é a lista de suas GPUs necessárias.

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

Além de todo o Uber, o Horovod de código aberto recentemente e acho ótimo:

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
fonte
2

Basicamente, você pode usar o exemplo a seguir. Tudo o que você precisa é especificar valores de consumo de CPU e GPU após a importação de keras.

import keras

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

Depois disso, você ajustaria o modelo.

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

Por fim, você pode diminuir os valores de consumo e não o trabalho nos limites superiores.

johncasey
fonte