PyCUDA documentation / Документация PyCUDA: Tutorial Introduction http://documen.tician.de/pycuda/tutorial.html
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
До того, как вы сможете использовать PyCUDA, вам нужно будет импортировать и инициализировать его: wuffur 03.08.11 в 11:35 |
|
|
import pycuda.driver as cuda wuffur 03.08.11 в 11:35 |
||
|
Отметим, что вам не нужно использовать инициализацию pycuda.autoinit, контекстное создание, и очистку тоже можно произвести вручную, если вы этого желаете. wuffur 03.08.11 в 11:37 |
||
|
Передача данных wuffur 03.08.11 в 11:37 |
||
|
Следдующим шагом в большинстве программ является передача данных в прибор. В PyCUDA, вы будете в основном передавать данный через массивы numpy на хост.(но в действительности, все, что заставляет работать интерфейс буфера Pythona будет работать, даже строка). Давайте сделаем массив 4x4 случайных чисел: wuffur 03.08.11 в 11:41 |
||
|
import numpy wuffur 03.08.11 в 12:04 |
||
|
Но подождите - это совокупность чисел двойной точности, но большинство приборов nVidia поддерживают только числа одинарной точности: wuffur 03.08.11 в 12:06 |
||
|
a = a.astype(numpy.float32) wuffur 03.08.11 в 12:06 |
||
|
Наконец, нам нужно куда-то передавать данные, поэтому нам нужно выделить память на устройстве: wuffur 03.08.11 в 12:06 |
||
|
a_gpu = cuda.mem_alloc(a.nbytes) wuffur 03.08.11 в 12:07 |
||
|
В качестве последнего шага, нам нужно передать данные в GPU: wuffur 03.08.11 в 12:07 |
||
|
cuda.memcpy_htod(a_gpu, a) wuffur 03.08.11 в 12:08 |
||
|
Выполнение Ядра wuffur 03.08.11 в 12:08 |
||
|
В этом руководстве мы будем придерживаться чего-то простого: будем писать код в объекты из переменных двойной точности в a_gpu. К концу этой документации, мы напишем соответствующий им код Си на CUDA, и передадим этот код конструктору pycuda.compiler.SourceModule: wuffur 03.08.11 в 12:10 |
||
|
mod = SourceModule(""" wuffur 03.08.11 в 12:11 |
||
|
Если здесь нет никаких ошибок, то код теперь откомпилируется и загрузится в прибор. Мы нашли ссылку на нашу pycuda.driver.Function и вызвали ее, специфицируя a_gpu как аргумент и установив размер блока 4x4: wuffur 03.08.11 в 20:33 |
||
|
func = mod.get_function("doublify") wuffur 03.08.11 в 20:33 |
||
|
И наконец, мы произведем выборку данных из GPU и выведим их на экран вместе с оригинальным a: wuffur 04.08.11 в 04:37 |
||
|
a_doubled = numpy.empty_like(a) wuffur 04.08.11 в 04:37 |
||
|
Этот кусок кода выведет, что-то похожее на это: wuffur 04.08.11 в 04:38 |
||
|
[[ 0.51360393 1.40589952 2.25009012 3.02563429] wuffur 04.08.11 в 04:38 |
||
|
Она работает! На этом закончим наше пошаговое руководство. К счастью, PyCuda наследует(запоминает эти данные) это и все вам подчищает, поэтому вы закончили. Однако не пропустите некоторый бонусный материал в следующем разделе. wuffur 04.08.11 в 04:39 |
||
|
(Вы можете найти код для этого демо, по адресу examples/demo.py, в дистрибутиве исходников PyCUDA.) wuffur 04.08.11 в 05:02 |
||
|
Сочетания клавиш для явных копий памяти wuffur 04.08.11 в 05:07 |
||
|
Обработчик аргумента pycuda.driver.In, pycuda.driver.Out и pycuda.driver.InOut может упростить некоторые процессы передачи памяти. Например, вместо создания a_gpu, если замещение a прошло хорошо, можно использовать следующий код: wuffur 04.08.11 в 07:39 |
||
|
func(cuda.InOut(a), block=(4, 4, 1)) wuffur 04.08.11 в 07:39 |
||
|
Подготовленные вызовы. wuffur 04.08.11 в 07:39 |
||
|
Вызов функции использует встроенный метод pycuda.driver.Function.__call__(), берущий на себя накладные расходы на определение типа(смотрите "Справочную документацию по интерфейсу устройств"). Чтобы достичь того же эффекта что и выше без этих накладных расходов, функций связывается с типами аргументов(как спроектировано в структурном модуле стандартной библиотеки Python), и затем вызывается. Это также помогает избежать объявления неявных размеров аргументов, используя классы numpy.number: wuffur 04.08.11 в 07:46 |
||
|
func.prepare("P", block=(4,4,1)) wuffur 04.08.11 в 07:48 |
||
|
Бонус: Абстрагирование от осложнений. wuffur 04.08.11 в 07:49 |
||
|
Использование pycuda.gpuarray.GPUArray,тот же эффект можно достичь написанием значительно меньшего количества кода: wuffur 04.08.11 в 07:50 |
||
|
import pycuda.gpuarray as gpuarray wuffur 04.08.11 в 07:50 |
||
|
a_gpu = gpuarray.to_gpu(numpy.random.randn(4,4).astype(numpy.float32)) wuffur 04.08.11 в 07:50 |
||
|
Продвинутые темы wuffur 04.08.11 в 07:51 |
||
|
(добавлено Nicholas Tung, найдите код в examples/demo_struct.py) wuffur 04.08.11 в 07:52 |
||
|
Предполагается, что у вас есть следующая структура, для удвоения числа переменных длин массивов: wuffur 04.08.11 в 07:53 |
||
|
mod = SourceModule(""" wuffur 04.08.11 в 07:53 |
||
|
__global__ void double_array(DoubleOperation *a) { wuffur 04.08.11 в 07:53 |
||
|
Каждый блок в грид(смотрите документацию CUDA) удвоит один из массивов. Цикл for позволяет удвоить большее количиство элементов данных, чем потоки, хотя и не эффективен, если нельзя гарантировать, что будет необходимое количество потоков. Затем создается класс обертки для струкутры, и два массива инициализируются: wuffur 04.08.11 в 07:57 |
||
|
class DoubleOpStruct: wuffur 04.08.11 в 08:03 |
||
|
struct_arr = cuda.mem_alloc(2 * DoubleOpStruct.mem_size) wuffur 04.08.11 в 08:03 |
||
|
array1 = DoubleOpStruct(numpy.array([1, 2, 3], dtype=numpy.float32), struct_arr) wuffur 04.08.11 в 08:03 |
||
|
Этот код использует функции pycuda.driver.to_device() и pycuda.driver.from_device(), чтобы выделить(локализировать) и скопировать значения и демонстрирует какие отступы выделенных блоков памяти могут использоваться. Наконец, код можно выполнить. Следующий код сначала демонстрирует удвоение обоих массивов, а затем только второй. wuffur 04.08.11 в 08:05 |
||
|
func = mod.get_function("double_array") wuffur 04.08.11 в 08:07 |
||
|
func(numpy.intp(do2_ptr), block = (32, 1, 1), grid=(1, 1)) wuffur 04.08.11 в 08:07 |
||
|
Куда теперь направится wuffur 04.08.11 в 08:07 |
||
|
Когда вы почувствуете себя достаточно знакомыми с основами, можете свободно смотреть следующий раздел (Device Interface Reference Documentation). Для получения большего количества примеров, проверьте поддиректорию examples/ дистрибутива. Этот ярлык может также содержать некоторые тесты производительности, которые показывают разницу между вычислениями на GPU и CPU. В качестве руководства по тому, как это было сделано также может помочь PyCuda’s test suite, расположенный в поддиректории test/ дистрибутива. wuffur 04.08.11 в 08:12 |
