Асинхронная передача памяти GPU с помощью cupy

Можно ли асинхронно передавать память из / в GPU с помощью cupy (или chainer)?

Я обучаю относительно небольшую сеть с очень большими данными, которые не помещаются в память графического процессора. Эти данные должны храниться в памяти ЦП и последовательно предоставляться графическому процессору для его минипакетного расчета.

Время передачи памяти является основным узким местом этого приложения. Я думаю, что асинхронная передача памяти решает эту проблему, т.е. во время расчета одного мини-пакета другой мини-пакет передается на GPU в фоновом режиме.

Мне интересно, что это было бы возможно с классом cupy.cuda.Stream, но я еще не знаю. Буду признателен за любые комментарии / советы.

РЕДАКТИРОВАТЬ: Я думал, что следующие коды выполняют асинхронную передачу памяти, но это не так.

import numpy as np
import cupy as cp

a_cpu = np.ones((10000, 10000), dtype=np.float32)
b_cpu = np.ones((10000, 10000), dtype=np.float32)

a_stream = cp.cuda.Stream(non_blocking=True)
b_stream = cp.cuda.Stream(non_blocking=True)

a_gpu = cp.empty_like(a_cpu)
b_gpu = cp.empty_like(b_cpu)

a_gpu.set(a_cpu, stream=a_stream)
b_gpu.set(b_cpu, stream=b_stream)

# This should start before b_gpu.set() is finished.
a_gpu *= 2

NVVP показывает, что передача памяти происходит последовательно.


person Keisuke FUJII    schedule 23.11.2017    source источник


Ответы (1)


Я нашел одно решение, погрузившись в исходный код цепочки .

Важным моментом кажется сохранение фиксированного буфера памяти при построении np.ndarray.

def pinned_array(array):
    # first constructing pinned memory
    mem = cupy.cuda.alloc_pinned_memory(array.nbytes)
    src = numpy.frombuffer(
                mem, array.dtype, array.size).reshape(array.shape)
    src[...] = array
    return src

a_cpu = np.ones((10000, 10000), dtype=np.float32)
b_cpu = np.ones((10000, 10000), dtype=np.float32)
# np.ndarray with pinned memory
a_cpu = pinned_array(a_cpu)
b_cpu = pinned_array(b_cpu)

a_stream = cp.cuda.Stream(non_blocking=True)
b_stream = cp.cuda.Stream(non_blocking=True)

a_gpu = cp.empty_like(a_cpu)
b_gpu = cp.empty_like(b_cpu)

a_gpu.set(a_cpu, stream=a_stream)
b_gpu.set(b_cpu, stream=b_stream)

# wait until a_cpu is copied in a_gpu
a_stream.synchronize()
# This line runs parallel to b_gpu.set()
a_gpu *= 2
person Keisuke FUJII    schedule 26.11.2017
comment
Как вы проверяете, выполняются ли две операции параллельно? Есть ли способ профилировать это? - person Mikhail Genkin; 20.01.2021
comment
Зачем нужно булавить память? Вроде работает и без - person user1315621; 28.01.2021