prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  fix device names for multi_gpu_model
  This PR will try to fix #8213.
  
  `DeviceSpec.from_string(device).to_string()` is used by tensorflow. ([Ref](https://github.com/tensorflow/tensorflow/blob/40c475b48c091a70ad8061c1508dff6ded2d2af6/tensorflow/python/framework/device.py#L251))
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `keras/utils/training_utils.py`
  Content:
  ```
  1 from ..layers.merge import concatenate
  2 from .. import backend as K
  3 from ..layers.core import Lambda
  4 from ..engine.training import Model
  5 
  6 
  7 def _get_available_devices():
  8     from tensorflow.python.client import device_lib
  9     local_device_protos = device_lib.list_local_devices()
  10     return [x.name for x in local_device_protos]
  11 
  12 
  13 def multi_gpu_model(model, gpus):
  14     """Replicates a model on different GPUs.
  15 
  16     Specifically, this function implements single-machine
  17     multi-GPU data parallelism. It works in the following way:
  18 
  19     - Divide the model's input(s) into multiple sub-batches.
  20     - Apply a model copy on each sub-batch. Every model copy
  21         is executed on a dedicated GPU.
  22     - Concatenate the results (on CPU) into one big batch.
  23 
  24     E.g. if your `batch_size` is 64 and you use `gpus=2`,
  25     then we will divide the input into 2 sub-batches of 32 samples,
  26     process each sub-batch on one GPU, then return the full
  27     batch of 64 processed samples.
  28 
  29     This induces quasi-linear speedup on up to 8 GPUs.
  30 
  31     This function is only available with the TensorFlow backend
  32     for the time being.
  33 
  34     # Arguments
  35         model: A Keras model instance. To avoid OOM errors,
  36             this model could have been built on CPU, for instance
  37             (see usage example below).
  38         gpus: Integer >= 2, number of on GPUs on which to create
  39             model replicas.
  40 
  41     # Returns
  42         A Keras `Model` instance which can be used just like the initial
  43         `model` argument, but which distributes its workload on multiple GPUs.
  44 
  45     # Example
  46 
  47     ```python
  48         import tensorflow as tf
  49         from keras.applications import Xception
  50         from keras.utils import multi_gpu_model
  51         import numpy as np
  52 
  53         num_samples = 1000
  54         height = 224
  55         width = 224
  56         num_classes = 1000
  57 
  58         # Instantiate the base model
  59         # (here, we do it on CPU, which is optional).
  60         with tf.device('/cpu:0'):
  61             model = Xception(weights=None,
  62                              input_shape=(height, width, 3),
  63                              classes=num_classes)
  64 
  65         # Replicates the model on 8 GPUs.
  66         # This assumes that your machine has 8 available GPUs.
  67         parallel_model = multi_gpu_model(model, gpus=8)
  68         parallel_model.compile(loss='categorical_crossentropy',
  69                                optimizer='rmsprop')
  70 
  71         # Generate dummy data.
  72         x = np.random.random((num_samples, height, width, 3))
  73         y = np.random.random((num_samples, num_classes))
  74 
  75         # This `fit` call will be distributed on 8 GPUs.
  76         # Since the batch size is 256, each GPU will process 32 samples.
  77         parallel_model.fit(x, y, epochs=20, batch_size=256)
  78     ```
  79     """
  80     if K.backend() != 'tensorflow':
  81         raise ValueError('`multi_gpu_model` is only available '
  82                          'with the TensorFlow backend.')
  83     if gpus <= 1:
  84         raise ValueError('For multi-gpu usage to be effective, '
  85                          'call `multi_gpu_model` with `gpus >= 2`. '
  86                          'Received: `gpus=%d`' % gpus)
  87 
  88     import tensorflow as tf
  89 
  90     target_devices = ['/cpu:0'] + ['/gpu:%d' % i for i in range(gpus)]
  91     available_devices = _get_available_devices()
  92     for device in target_devices:
  93         if device not in available_devices:
  94             raise ValueError(
  95                 'To call `multi_gpu_model` with `gpus=%d`, '
  96                 'we expect the following devices to be available: %s. '
  97                 'However this machine only has: %s. '
  98                 'Try reducing `gpus`.' % (gpus,
  99                                           target_devices,
  100                                           available_devices))
  101 
  102     def get_slice(data, i, parts):
  103         shape = tf.shape(data)
  104         batch_size = shape[:1]
  105         input_shape = shape[1:]
  106         step = batch_size // parts
  107         if i == gpus - 1:
  108             size = batch_size - step * i
  109         else:
  110             size = step
  111         size = tf.concat([size, input_shape], axis=0)
  112         stride = tf.concat([step, input_shape * 0], axis=0)
  113         start = stride * i
  114         return tf.slice(data, start, size)
  115 
  116     all_outputs = []
  117     for i in range(len(model.outputs)):
  118         all_outputs.append([])
  119 
  120     # Place a copy of the model on each GPU,
  121     # each getting a slice of the inputs.
  122     for i in range(gpus):
  123         with tf.device('/gpu:%d' % i):
  124             with tf.name_scope('replica_%d' % i):
  125                 inputs = []
  126                 # Retrieve a slice of the input.
  127                 for x in model.inputs:
  128                     input_shape = tuple(x.get_shape().as_list())[1:]
  129                     slice_i = Lambda(get_slice,
  130                                      output_shape=input_shape,
  131                                      arguments={'i': i,
  132                                                 'parts': gpus})(x)
  133                     inputs.append(slice_i)
  134 
  135                 # Apply model on slice
  136                 # (creating a model replica on the target device).
  137                 outputs = model(inputs)
  138                 if not isinstance(outputs, list):
  139                     outputs = [outputs]
  140 
  141                 # Save the outputs for merging back together later.
  142                 for o in range(len(outputs)):
  143                     all_outputs[o].append(outputs[o])
  144 
  145     # Merge outputs on CPU.
  146     with tf.device('/cpu:0'):
  147         merged = []
  148         for outputs in all_outputs:
  149             merged.append(concatenate(outputs,
  150                                       axis=0))
  151         return Model(model.inputs, merged)
  152
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/keras/utils/training_utils.py b/keras/utils/training_utils.py
  --- a/keras/utils/training_utils.py
  +++ b/keras/utils/training_utils.py
  @@ -10,6 +10,11 @@
       return [x.name for x in local_device_protos]
   
   
  +def _normalize_device_name(name):
  +    name = name.lower().replace('device:', '')
  +    return name
  +
  +
   def multi_gpu_model(model, gpus):
       """Replicates a model on different GPUs.
   
  @@ -89,6 +94,7 @@
   
       target_devices = ['/cpu:0'] + ['/gpu:%d' % i for i in range(gpus)]
       available_devices = _get_available_devices()
  +    available_devices = [_normalize_device_name(name) for name in available_devices]
       for device in target_devices:
           if device not in available_devices:
               raise ValueError(
  
verification_info: {"golden_diff": "diff --git a/keras/utils/training_utils.py b/keras/utils/training_utils.py\n--- a/keras/utils/training_utils.py\n+++ b/keras/utils/training_utils.py\n@@ -10,6 +10,11 @@\n     return [x.name for x in local_device_protos]\n \n \n+def _normalize_device_name(name):\n+    name = name.lower().replace('device:', '')\n+    return name\n+\n+\n def multi_gpu_model(model, gpus):\n     \"\"\"Replicates a model on different GPUs.\n \n@@ -89,6 +94,7 @@\n \n     target_devices = ['/cpu:0'] + ['/gpu:%d' % i for i in range(gpus)]\n     available_devices = _get_available_devices()\n+    available_devices = [_normalize_device_name(name) for name in available_devices]\n     for device in target_devices:\n         if device not in available_devices:\n             raise ValueError(\n", "issue": "fix device names for multi_gpu_model\nThis PR will try to fix #8213.\r\n\r\n`DeviceSpec.from_string(device).to_string()` is used by tensorflow. ([Ref](https://github.com/tensorflow/tensorflow/blob/40c475b48c091a70ad8061c1508dff6ded2d2af6/tensorflow/python/framework/device.py#L251))\n", "before_files": [{"content": "from ..layers.merge import concatenate\nfrom .. import backend as K\nfrom ..layers.core import Lambda\nfrom ..engine.training import Model\n\n\ndef _get_available_devices():\n    from tensorflow.python.client import device_lib\n    local_device_protos = device_lib.list_local_devices()\n    return [x.name for x in local_device_protos]\n\n\ndef multi_gpu_model(model, gpus):\n    \"\"\"Replicates a model on different GPUs.\n\n    Specifically, this function implements single-machine\n    multi-GPU data parallelism. It works in the following way:\n\n    - Divide the model's input(s) into multiple sub-batches.\n    - Apply a model copy on each sub-batch. Every model copy\n        is executed on a dedicated GPU.\n    - Concatenate the results (on CPU) into one big batch.\n\n    E.g. if your `batch_size` is 64 and you use `gpus=2`,\n    then we will divide the input into 2 sub-batches of 32 samples,\n    process each sub-batch on one GPU, then return the full\n    batch of 64 processed samples.\n\n    This induces quasi-linear speedup on up to 8 GPUs.\n\n    This function is only available with the TensorFlow backend\n    for the time being.\n\n    # Arguments\n        model: A Keras model instance. To avoid OOM errors,\n            this model could have been built on CPU, for instance\n            (see usage example below).\n        gpus: Integer >= 2, number of on GPUs on which to create\n            model replicas.\n\n    # Returns\n        A Keras `Model` instance which can be used just like the initial\n        `model` argument, but which distributes its workload on multiple GPUs.\n\n    # Example\n\n    ```python\n        import tensorflow as tf\n        from keras.applications import Xception\n        from keras.utils import multi_gpu_model\n        import numpy as np\n\n        num_samples = 1000\n        height = 224\n        width = 224\n        num_classes = 1000\n\n        # Instantiate the base model\n        # (here, we do it on CPU, which is optional).\n        with tf.device('/cpu:0'):\n            model = Xception(weights=None,\n                             input_shape=(height, width, 3),\n                             classes=num_classes)\n\n        # Replicates the model on 8 GPUs.\n        # This assumes that your machine has 8 available GPUs.\n        parallel_model = multi_gpu_model(model, gpus=8)\n        parallel_model.compile(loss='categorical_crossentropy',\n                               optimizer='rmsprop')\n\n        # Generate dummy data.\n        x = np.random.random((num_samples, height, width, 3))\n        y = np.random.random((num_samples, num_classes))\n\n        # This `fit` call will be distributed on 8 GPUs.\n        # Since the batch size is 256, each GPU will process 32 samples.\n        parallel_model.fit(x, y, epochs=20, batch_size=256)\n    ```\n    \"\"\"\n    if K.backend() != 'tensorflow':\n        raise ValueError('`multi_gpu_model` is only available '\n                         'with the TensorFlow backend.')\n    if gpus <= 1:\n        raise ValueError('For multi-gpu usage to be effective, '\n                         'call `multi_gpu_model` with `gpus >= 2`. '\n                         'Received: `gpus=%d`' % gpus)\n\n    import tensorflow as tf\n\n    target_devices = ['/cpu:0'] + ['/gpu:%d' % i for i in range(gpus)]\n    available_devices = _get_available_devices()\n    for device in target_devices:\n        if device not in available_devices:\n            raise ValueError(\n                'To call `multi_gpu_model` with `gpus=%d`, '\n                'we expect the following devices to be available: %s. '\n                'However this machine only has: %s. '\n                'Try reducing `gpus`.' % (gpus,\n                                          target_devices,\n                                          available_devices))\n\n    def get_slice(data, i, parts):\n        shape = tf.shape(data)\n        batch_size = shape[:1]\n        input_shape = shape[1:]\n        step = batch_size // parts\n        if i == gpus - 1:\n            size = batch_size - step * i\n        else:\n            size = step\n        size = tf.concat([size, input_shape], axis=0)\n        stride = tf.concat([step, input_shape * 0], axis=0)\n        start = stride * i\n        return tf.slice(data, start, size)\n\n    all_outputs = []\n    for i in range(len(model.outputs)):\n        all_outputs.append([])\n\n    # Place a copy of the model on each GPU,\n    # each getting a slice of the inputs.\n    for i in range(gpus):\n        with tf.device('/gpu:%d' % i):\n            with tf.name_scope('replica_%d' % i):\n                inputs = []\n                # Retrieve a slice of the input.\n                for x in model.inputs:\n                    input_shape = tuple(x.get_shape().as_list())[1:]\n                    slice_i = Lambda(get_slice,\n                                     output_shape=input_shape,\n                                     arguments={'i': i,\n                                                'parts': gpus})(x)\n                    inputs.append(slice_i)\n\n                # Apply model on slice\n                # (creating a model replica on the target device).\n                outputs = model(inputs)\n                if not isinstance(outputs, list):\n                    outputs = [outputs]\n\n                # Save the outputs for merging back together later.\n                for o in range(len(outputs)):\n                    all_outputs[o].append(outputs[o])\n\n    # Merge outputs on CPU.\n    with tf.device('/cpu:0'):\n        merged = []\n        for outputs in all_outputs:\n            merged.append(concatenate(outputs,\n                                      axis=0))\n        return Model(model.inputs, merged)\n", "path": "keras/utils/training_utils.py"}], "after_files": [{"content": "from ..layers.merge import concatenate\nfrom .. import backend as K\nfrom ..layers.core import Lambda\nfrom ..engine.training import Model\n\n\ndef _get_available_devices():\n    from tensorflow.python.client import device_lib\n    local_device_protos = device_lib.list_local_devices()\n    return [x.name for x in local_device_protos]\n\n\ndef _normalize_device_name(name):\n    name = name.lower().replace('device:', '')\n    return name\n\n\ndef multi_gpu_model(model, gpus):\n    \"\"\"Replicates a model on different GPUs.\n\n    Specifically, this function implements single-machine\n    multi-GPU data parallelism. It works in the following way:\n\n    - Divide the model's input(s) into multiple sub-batches.\n    - Apply a model copy on each sub-batch. Every model copy\n        is executed on a dedicated GPU.\n    - Concatenate the results (on CPU) into one big batch.\n\n    E.g. if your `batch_size` is 64 and you use `gpus=2`,\n    then we will divide the input into 2 sub-batches of 32 samples,\n    process each sub-batch on one GPU, then return the full\n    batch of 64 processed samples.\n\n    This induces quasi-linear speedup on up to 8 GPUs.\n\n    This function is only available with the TensorFlow backend\n    for the time being.\n\n    # Arguments\n        model: A Keras model instance. To avoid OOM errors,\n            this model could have been built on CPU, for instance\n            (see usage example below).\n        gpus: Integer >= 2, number of on GPUs on which to create\n            model replicas.\n\n    # Returns\n        A Keras `Model` instance which can be used just like the initial\n        `model` argument, but which distributes its workload on multiple GPUs.\n\n    # Example\n\n    ```python\n        import tensorflow as tf\n        from keras.applications import Xception\n        from keras.utils import multi_gpu_model\n        import numpy as np\n\n        num_samples = 1000\n        height = 224\n        width = 224\n        num_classes = 1000\n\n        # Instantiate the base model\n        # (here, we do it on CPU, which is optional).\n        with tf.device('/cpu:0'):\n            model = Xception(weights=None,\n                             input_shape=(height, width, 3),\n                             classes=num_classes)\n\n        # Replicates the model on 8 GPUs.\n        # This assumes that your machine has 8 available GPUs.\n        parallel_model = multi_gpu_model(model, gpus=8)\n        parallel_model.compile(loss='categorical_crossentropy',\n                               optimizer='rmsprop')\n\n        # Generate dummy data.\n        x = np.random.random((num_samples, height, width, 3))\n        y = np.random.random((num_samples, num_classes))\n\n        # This `fit` call will be distributed on 8 GPUs.\n        # Since the batch size is 256, each GPU will process 32 samples.\n        parallel_model.fit(x, y, epochs=20, batch_size=256)\n    ```\n    \"\"\"\n    if K.backend() != 'tensorflow':\n        raise ValueError('`multi_gpu_model` is only available '\n                         'with the TensorFlow backend.')\n    if gpus <= 1:\n        raise ValueError('For multi-gpu usage to be effective, '\n                         'call `multi_gpu_model` with `gpus >= 2`. '\n                         'Received: `gpus=%d`' % gpus)\n\n    import tensorflow as tf\n\n    target_devices = ['/cpu:0'] + ['/gpu:%d' % i for i in range(gpus)]\n    available_devices = _get_available_devices()\n    available_devices = [_normalize_device_name(name) for name in available_devices]\n    for device in target_devices:\n        if device not in available_devices:\n            raise ValueError(\n                'To call `multi_gpu_model` with `gpus=%d`, '\n                'we expect the following devices to be available: %s. '\n                'However this machine only has: %s. '\n                'Try reducing `gpus`.' % (gpus,\n                                          target_devices,\n                                          available_devices))\n\n    def get_slice(data, i, parts):\n        shape = tf.shape(data)\n        batch_size = shape[:1]\n        input_shape = shape[1:]\n        step = batch_size // parts\n        if i == gpus - 1:\n            size = batch_size - step * i\n        else:\n            size = step\n        size = tf.concat([size, input_shape], axis=0)\n        stride = tf.concat([step, input_shape * 0], axis=0)\n        start = stride * i\n        return tf.slice(data, start, size)\n\n    all_outputs = []\n    for i in range(len(model.outputs)):\n        all_outputs.append([])\n\n    # Place a copy of the model on each GPU,\n    # each getting a slice of the inputs.\n    for i in range(gpus):\n        with tf.device('/gpu:%d' % i):\n            with tf.name_scope('replica_%d' % i):\n                inputs = []\n                # Retrieve a slice of the input.\n                for x in model.inputs:\n                    input_shape = tuple(x.get_shape().as_list())[1:]\n                    slice_i = Lambda(get_slice,\n                                     output_shape=input_shape,\n                                     arguments={'i': i,\n                                                'parts': gpus})(x)\n                    inputs.append(slice_i)\n\n                # Apply model on slice\n                # (creating a model replica on the target device).\n                outputs = model(inputs)\n                if not isinstance(outputs, list):\n                    outputs = [outputs]\n\n                # Save the outputs for merging back together later.\n                for o in range(len(outputs)):\n                    all_outputs[o].append(outputs[o])\n\n    # Merge outputs on CPU.\n    with tf.device('/cpu:0'):\n        merged = []\n        for outputs in all_outputs:\n            merged.append(concatenate(outputs,\n                                      axis=0))\n        return Model(model.inputs, merged)\n", "path": "keras/utils/training_utils.py"}]}