Python-在GPU工作时将数据从存储器传输到RAM

Python-在GPU工作时将数据从存储器传输到RAM,python,Python,这篇文章不是关于深入学习,而是关于一些繁重的工作 在训练神经网络时,特别是在处理高分辨率图像时,有一个重复的过程,即从存储器(SSD/HDD)加载图像并将其加载到RAM,然后将其输入GPU进行训练 有很多时间GPU在CPU空闲的时候做所有的工作,所以我在想,有没有办法在GPU工作时将下一批图像加载到RAM中?因为如果我没有弄错的话,现在发生的事情是CPU从存储器加载图像,将它们传输到GPU,GPU完成它的工作,然后GPU必须等待CPU从存储器加载新图像 当GPU工作时,我们如何编写一个将新图像检

这篇文章不是关于深入学习,而是关于一些繁重的工作

在训练神经网络时,特别是在处理高分辨率图像时,有一个重复的过程,即从存储器(SSD/HDD)加载图像并将其加载到RAM,然后将其输入GPU进行训练

有很多时间GPU在CPU空闲的时候做所有的工作,所以我在想,有没有办法在GPU工作时将下一批图像加载到RAM中?因为如果我没有弄错的话,现在发生的事情是CPU从存储器加载图像,将它们传输到GPU,GPU完成它的工作,然后GPU必须等待CPU从存储器加载新图像


当GPU工作时,我们如何编写一个将新图像检索到RAM的生成器

好的,假设您有以下两项任务:

import time


def cpu_operation(n):
    print('Start CPU', n)
    for x in range(100):
        time.sleep(0.01)
    print('End CPU', n)
    return n


def expensive_gpu_operation(n):
    print('Start GPU', n)
    time.sleep(0.3)
    print('Stop GPU', n)
    return n
以下是您现在如何运行它们:

def slow():
    results = []
    for task in range(5):
        cpu_result = cpu_operation(task)
        gpu_result = expensive_gpu_operation(cpu_result)
        results.append(gpu_result)
    return results
我们按顺序运行这些-CPU,GPU,CPU,GPU。。。输出如下所示:

Start CPU 0
End CPU 0
Start GPU 0
Stop GPU 0
Start CPU 1
End CPU 1
Start GPU 1
Stop GPU 1
Start CPU 2
End CPU 2
Start GPU 2
Stop GPU 2
Start CPU 3
End CPU 3
Start GPU 3
Stop GPU 3
Start CPU 4
End CPU 4
Start GPU 4
Stop GPU 4
假设我们可以通过在GPU任务X完成之前启动CPU任务X+1来节省一些时间,这样CPU X+1和GPU X就可以并行运行,对吗

(我们不能并行运行CPU X和GPU X,因为GPU X需要来自CPU X输出的输入,因此需要+1。)

让我们使用线程!基本上,我们想做一些事情,比如:

  • 启动CPU N,等待它完成
  • 等待GPU N-1完成,在后台启动GPU N
所以我们得到了一些并行性。实现这一点的最简单方法是一个有1个线程的线程池——它可以像队列一样工作。在每个循环中,我们只安排一个任务并存储
async\u结果
。完成后,我们将能够检索所有结果

现在输出变成:

Start CPU 0
End CPU 0
Start CPU 1
Start GPU 0
Stop GPU 0
End CPU 1
Start CPU 2
Start GPU 1
Stop GPU 1
End CPU 2
Start CPU 3
Start GPU 2
Stop GPU 2
End CPU 3
Start CPU 4
Start GPU 3
Stop GPU 3
End CPU 4
Start GPU 4
Stop GPU 4
我们可以观察平行性



请注意,当
昂贵的\gpu\U操作
被调度时,它实际上要等到
时间后才能运行。在下一个CPU操作中睡眠
。这是由于全局解释器锁造成的-主线程必须在工作线程有机会执行某项操作之前放弃GIL,这发生在
time.sleep()
,在您的情况下,我希望在您执行一些I/o操作时会发生这种情况-开始读取下一批图像。

将GPU工作卸载到其他线程以便您的主线程可以继续工作是否有意义?可能的重复请让我知道这种方法是否适用于您!如果线程池令人困惑,我们可能会显式启动一个线程,但它需要更多的代码。这看起来很简单,我实际上打算为将来的深度学习任务实现一个通用的数据加载包装器,如果出现任何问题,我将在这里更新
Start CPU 0
End CPU 0
Start CPU 1
Start GPU 0
Stop GPU 0
End CPU 1
Start CPU 2
Start GPU 1
Stop GPU 1
End CPU 2
Start CPU 3
Start GPU 2
Stop GPU 2
End CPU 3
Start CPU 4
Start GPU 3
Stop GPU 3
End CPU 4
Start GPU 4
Stop GPU 4