将多GPU与keras.utils.multi_gpu_model一起使用时,SageMaker失败

时间:2018-11-26 20:51:47

标签: tensorflow keras amazon-sagemaker

使用自定义模型运行AWS SageMaker,在多GPU配置中使用Keras加上Tensorflow后端时,TrainingJob失败,并出现 Algorithm Error (算法错误)。

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日志记录没有其他错误或异常。此配置在具有2个NVIDIA GTX 1080和相同Keras Tensorflow后端的本地计算机上可以正常工作。

根据SageMaker文档和tutorialsmulti_gpu_model实用程序在Keras后端为MXNet时可以正常使用,但是当后端为具有相同多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 ,此后变为失败,并带有相同的算法错误

查看CloudWatch日志记录,我可以看到一些工作指标。具体来说,GPU Memory UtilizationCPU Utilization可以,而GPU utilization为0%。

enter image description here

[更新]

由于Keras上的一个known错误,该错误与保存多GPU模型有关,因此我在 keras.utils multi_gpu_model 实用程序的此替代。 >

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仍然无法正常工作。

2 个答案:

答案 0 :(得分:2)

这可能不是您所遇到问题的最佳答案,但这就是我正在使用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:
    https://stackoverflow.com/questions/34199233/how-to-prevent-tensorflow-from-allocating-the-totality-of-a-gpu-memory
    """
    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一起使用。这是您要训练的模型类型吗?

答案 1 :(得分:1)

很抱歉我的反应慢。

似乎有许多并行运行的线程,我想将它们链接在一起,以便其他有相同问题的人可以看到进度和讨论。

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进行训练?