【问题标题】:No Multi-GPU speed up for GANGAN 没有多 GPU 加速
【发布时间】:2019-04-05 23:25:52
【问题描述】:

我有一个codebase,我尝试在其中复制 GAN 论文。我最近买了第二个 gpu,我正在尝试更新我的代码以利用额外的硬件。我尝试了 Tensorflow cifar10 multi-gpu example 中概述的方法。但是,当我使用 2 个 gpu 运行我的代码时,它并没有运行得更快,事实上,它比使用单个 gpu 运行时慢了大约 10%。查看资源管理器,它说我的两个 GPU 都以大约 50% 的容量运行。

我在 Windows 10 上运行,使用 python 3.7、TF 1.13。我正在使用 2 个 2080ti 和 2950 cpu。

我的第一个想法是我的输入管道有问题,所以我尝试了许多变体,例如使用多个数据迭代器、使用 tf.data.experimental.prefetch_to_device()、不输入我的潜在向量等. 没有任何影响,因为我的 CPU 使用率大约是 5%,我很确定我没有瓶颈。

我也尝试了一些不同的方法来设置塔的变量范围,但这没有帮助。

我还尝试将批量大小加倍,以防我没有通过 GPU 输入足够的数据,但这导致计算每个批量所需的时间增加了 2 倍,而 GPU 利用率相同,为 50%。

我的代码是here,相关部分是:

        d_grads = []
        g_grads = []
        for i in range(FLAGS.num_gpus):
            with tf.device('/gpu:{:d}'.format(i)):
                with tf.variable_scope('D', reuse=tf.AUTO_REUSE):
                    Dx, Dx_logits = self.discriminator(xs[i], yxs[i])
                with tf.variable_scope('G', reuse=tf.AUTO_REUSE):
                    G = self.generator(z[i], labels[i])
                with tf.variable_scope('D', reuse=tf.AUTO_REUSE):
                    Dg, Dg_logits = self.discriminator(G, labels[i])

                loss_d, loss_g = self.losses(Dx_logits, Dg_logits, Dx, Dg)

                vars = tf.trainable_variables()
                for v in vars:
                    print(v.name)
                d_params = [v for v in vars if v.name.startswith('D/')]
                g_params = [v for v in vars if v.name.startswith('G/')]

                d_grads.append(d_adam.compute_gradients(loss_d, var_list=d_params))
                g_grads.append(g_adam.compute_gradients(loss_g, var_list=g_params))

        d_opt = d_adam.apply_gradients(average_gradients(d_grads))
        g_opt = g_adam.apply_gradients(average_gradients(g_grads))

【问题讨论】:

    标签: tensorflow


    【解决方案1】:

    在您的 gan.py 文件中,请参阅第 17 行 num_gpus 已设置为 1。其次,检查此链接以获取 Allowing GPU memory growth。默认情况下,TensorFlow 将几乎所有 GPU 的所有 GPU 内存(受 CUDA_VISIBLE_DEVICES 限制)映射到进程可见。在某些情况下,希望进程只分配可用内存的子集,或者只根据进程的需要增加内存使用量。 TensorFlow 在 Session 上提供了两个 Config 选项来控制它。

    第一个是 allow_growth 选项,它尝试根据运行时分配只分配尽可能多的 GPU 内存:它开始分配非常少的内存,当Sessions 运行时,需要更多的 GPU 内存。

    config = tf.ConfigProto()
    config.gpu_options.allow_growth = True
    session = tf.Session(config=config, ...)
    

    第二种方法是per_process_gpu_memory_fraction 选项,它确定每个可见GPU 应分配的内存总量的比例。例如,您可以通过以下方式告诉 TensorFlow 仅分配每个 GPU 总内存的 40%:

    config = tf.ConfigProto()
    config.gpu_options.per_process_gpu_memory_fraction = 0.4
    session = tf.Session(config=config, ...)
    

    如果您想真正限制 TensorFlow 进程可用的 GPU 内存量,这很有用。

    在多 GPU 系统上使用单个 GPU

    如果您的系统中有多个 GPU,则默认选择 ID 最低的 GPU。如果您想在不同的 GPU 上运行,则需要明确指定首选项:

    # 创建一个图表。

    with tf.device('/device:GPU:2'):
      a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
      b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
      c = tf.matmul(a, b)
    # 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(c))
    

    如果你指定的设备不​​存在,你会得到InvalidArgumentError:

    InvalidArgumentError: Invalid argument: Cannot assign a device to node 'b':
    Could not satisfy explicit device specification '/device:GPU:2'
       [[{ {node b}} = Const[dtype=DT_FLOAT, value=Tensor<type: float shape: [3,2]
       values: 1 2 3...>, _device="/device:GPU:2"]()]]
    

    如果您希望 TensorFlow 自动选择现有且受支持的设备来运行操作,以防指定的设备不​​存在,您可以在创建会话时在配置选项中将 allow_soft_placement 设置为 True。

    # 创建一个图表。

    with tf.device('/device:GPU:2'):
      a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
      b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
      c = tf.matmul(a, b)
    # Creates a session with allow_soft_placement and log_device_placement set
    # to True.
    sess = tf.Session(config=tf.ConfigProto(
          allow_soft_placement=True, log_device_placement=True))
    # Runs the op.
    print(sess.run(c))
    

    使用多个 GPU

    如果您想在多个 GPU 上运行 TensorFlow,您可以以多塔方式构建模型,其中每个塔分配给不同的 GPU。例如:

    # 创建一个图表。

    c = []
    for d in ['/device:GPU:2', '/device: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))
    

    【讨论】:

    • 关于标志的好点,当我想用​​ 2 个 gpus 运行时,我传入 --num_gpus=2。我不知道你强调记忆是为了什么?我可以在性能监视器中看到 ~ 我的 gpus 上的所有内存都被占用了。我可以看到他们两个都在计算,但每个都只有一半的容量。
    • 我认为您系统上的多 GPU 硬件配置设置不正确。您能否运行以下命令来共享您的 GPU 布局:nvidia-smi topo -m 并粘贴输出。有关详细信息,请检查多个 GPU 比单个 GPU 慢 (github.com/avolkov1/keras_experiments/issues/13)
    • 当我尝试运行该命令时,我得到Invalid combination of input arguments. Please run 'nvidia-smi -h' for help.。根据this pdf,topo 命令仅适用于 linux,我在 windows 上运行。还有其他想法吗?
    • 我运行了您链接中建议的带宽测试。它说 CPU - GPU 带宽是 12699.6 MB/s,而 GPU - GPU 带宽是 517367.7 MB/s。
    • 我还尝试了this question 中的建议,以在 gpu:0 上明确定位梯度平均,但这没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    • 2014-09-24
    • 1970-01-01
    • 2021-05-12
    相关资源
    最近更新 更多