在 keras.utils.multi_gpu_model 下使用多 GPU 时 SageMaker 失败

SageMaker fails when using Multi-GPU with keras.utils.multi_gpu_model

运行 带有自定义模型的 AWS SageMaker,在多 gpu 配置中使用 Keras 和 Tensorflow 后端时,TrainingJob 失败并出现算法错误

from keras.utils import multi_gpu_model

parallel_model = multi_gpu_model(model, gpus=K)
parallel_model.compile(loss='categorical_crossentropy',
optimizer='rmsprop')
parallel_model.fit(x, y, epochs=20, batch_size=256)

这个简单的并行模型加载将失败。 CloudWatch 日志记录没有进一步的错误或异常。此配置在具有 2x NVIDIA GTX 1080、相同 Keras Tensorflow 后端的本地计算机上正常工作。

根据 SageMaker 文档和 tutorials,当 Keras 后端是 MXNet 时,multi_gpu_model 实用程序可以正常工作,但当后端是具有相同多 GPU 配置的 Tensorflow 时,我没有发现任何提及。

[更新]

我已经使用下面的建议答案更新了代码,并且在 TrainingJob 挂起之前添加了一些日志记录

此记录重复两次

2018-11-27 10:02:49.878414: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0, 1, 2, 3
2018-11-27 10:02:49.878462: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-11-27 10:02:49.878471: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988] 0 1 2 3
2018-11-27 10:02:49.878477: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0: N Y Y Y
2018-11-27 10:02:49.878481: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 1: Y N Y Y
2018-11-27 10:02:49.878486: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 2: Y Y N Y
2018-11-27 10:02:49.878492: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 3: Y Y Y N
2018-11-27 10:02:49.879340: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/device:GPU:0 with 14874 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:1b.0, compute capability: 7.0)
2018-11-27 10:02:49.879486: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/device:GPU:1 with 14874 MB memory) -> physical GPU (device: 1, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:1c.0, compute capability: 7.0)
2018-11-27 10:02:49.879694: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/device:GPU:2 with 14874 MB memory) -> physical GPU (device: 2, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:1d.0, compute capability: 7.0)
2018-11-27 10:02:49.879872: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/device:GPU:3 with 14874 MB memory) -> physical GPU (device: 3, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:1e.0, compute capability: 7.0)

在每个 GPU 的一些日志信息之前,重复 4 次

2018-11-27 10:02:46.447639: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 3 with properties:
name: Tesla V100-SXM2-16GB major: 7 minor: 0 memoryClockRate(GHz): 1.53
pciBusID: 0000:00:1e.0
totalMemory: 15.78GiB freeMemory: 15.37GiB

根据日志记录,所有 4 个 GPU 都可见并已加载到 Tensorflow Keras 后端。之后没有应用程序日志记录,TrainingJob 状态暂时为 inProgress,之后变为 Failed,使用相同的 Algorithm错误.

查看 CloudWatch 日志记录,我可以看到一些指标在起作用。具体来说 GPU Memory Utilization, CPU Utilization 是可以的,而 GPU utilization 是 0%.

[更新]

由于 Keras 上的一个 known 错误是关于保存多 GPU 模型,我正在使用 multi_gpu_model 实用程序keras.utils

from keras.layers import Lambda, concatenate
from keras import Model
import tensorflow as tf
    
def multi_gpu_model(model, gpus):
    #source: https://github.com/keras-team/keras/issues/8123#issuecomment-354857044
  if isinstance(gpus, (list, tuple)):
    num_gpus = len(gpus)
    target_gpu_ids = gpus
  else:
    num_gpus = gpus
    target_gpu_ids = range(num_gpus)

  def get_slice(data, i, parts):
    shape = tf.shape(data)
    batch_size = shape[:1]
    input_shape = shape[1:]
    step = batch_size // parts
    if i == num_gpus - 1:
      size = batch_size - step * i
    else:
      size = step
    size = tf.concat([size, input_shape], axis=0)
    stride = tf.concat([step, input_shape * 0], axis=0)
    start = stride * i
    return tf.slice(data, start, size)

  all_outputs = []
  for i in range(len(model.outputs)):
    all_outputs.append([])

  # Place a copy of the model on each GPU,
  # each getting a slice of the inputs.
  for i, gpu_id in enumerate(target_gpu_ids):
    with tf.device('/gpu:%d' % gpu_id):
      with tf.name_scope('replica_%d' % gpu_id):
        inputs = []
        # Retrieve a slice of the input.
        for x in model.inputs:
          input_shape = tuple(x.get_shape().as_list())[1:]
          slice_i = Lambda(get_slice,
                           output_shape=input_shape,
                           arguments={'i': i,
                                      'parts': num_gpus})(x)
          inputs.append(slice_i)

        # Apply model on slice
        # (creating a model replica on the target device).
        outputs = model(inputs)
        if not isinstance(outputs, list):
          outputs = [outputs]

        # Save the outputs for merging back together later.
        for o in range(len(outputs)):
          all_outputs[o].append(outputs[o])

  # Merge outputs on CPU.
  with tf.device('/cpu:0'):
    merged = []
    for name, outputs in zip(model.output_names, all_outputs):
      merged.append(concatenate(outputs,
                                axis=0, name=name))
    return Model(model.inputs, merged)

这在本地 2x NVIDIA GTX 1080 / Intel Xeon / Ubuntu 16.04 上工作正常。它会在 SageMaker 训练作业上失败。

我已在

的 AWS Sagemaker 论坛上发布了这个问题

[更新]

我稍微修改了 tf.session 代码,添加了一些初始化程序

with tf.Session() as session:
    K.set_session(session)
    session.run(tf.global_variables_initializer())
    session.run(tf.tables_initializer())

现在至少我可以从实例指标中看到使用了一个 GPU(我假设设备 gpu:0)。无论如何,多GPU都不工作。

这可能不是您问题的最佳答案,但这是我用于带有 Tensorflow 后端的多 GPU 模型的答案。首先我初始化使用:

def setup_multi_gpus():
    """
    Setup multi GPU usage

    Example usage:
    model = Sequential()
    ...
    multi_model = multi_gpu_model(model, gpus=num_gpu)
    multi_model.fit()

    About memory usage:
    
    """
    import tensorflow as tf
    from keras.utils.training_utils import multi_gpu_model
    from tensorflow.python.client import device_lib

    # IMPORTANT: Tells tf to not occupy a specific amount of memory
    from keras.backend.tensorflow_backend import set_session  
    config = tf.ConfigProto()  
    config.gpu_options.allow_growth = True  # dynamically grow the memory used on the GPU  
    sess = tf.Session(config=config)  
    set_session(sess)  # set this TensorFlow session as the default session for Keras.


    # getting the number of GPUs 
    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']

    num_gpu = len(get_available_gpus())
    print('Amount of GPUs available: %s' % num_gpu)

    return num_gpu

那我打电话给

# Setup multi GPU usage
num_gpu = setup_multi_gpus()

并创建一个模型。

...

之后您可以将其设为多 GPU 模型。

multi_model = multi_gpu_model(model, gpus=num_gpu)
multi_model.compile...
multi_model.fit...

此处与您所做的唯一不同的是 Tensorflow 初始化 GPU 的方式。我无法想象这是问题所在,但可能值得一试。

祝你好运!

编辑:我注意到序列到序列无法使用多 GPU。这是您要训练的模型类型吗?

对于回复缓慢,我深表歉意。

好像有很多线程是运行并发的,想把它们link放在一起,让有同样问题的其他人看到进度和讨论进行中。

https://forums.aws.amazon.com/thread.jspa?messageID=881541 https://forums.aws.amazon.com/thread.jspa?messageID=881540

https://github.com/aws/sagemaker-python-sdk/issues/512

关于这个有几个问题。

什么版本的 TensorFlow 和 Keras?

我不太确定是什么导致了这个问题。您的容器是否具有所有需要的依赖项,例如 CUDA 等? https://www.tensorflow.org/install/gpu

你能用 Keras 使用单个 GPU 进行训练吗?