Главная страница

Глава 8 Неоднородные вычисления. Неоднородные вычисления Содержание Глава Неоднородные вычисления Основы неоднородных вычислений


Скачать 0.62 Mb.
НазваниеНеоднородные вычисления Содержание Глава Неоднородные вычисления Основы неоднородных вычислений
Дата27.12.2022
Размер0.62 Mb.
Формат файлаdocx
Имя файлаГлава 8 Неоднородные вычисления.docx
ТипГлава
#866699
страница7 из 8
1   2   3   4   5   6   7   8

Как это работает...

Как пояснялось ранее, наш тест состоит в выполнении нашей задачи вычислений, причём обе в ЦПУ посредством функции test_cpu_vector_sum, а затем через установленное GPU при помощи функции test_gpu_vector_sum.

Обе функции выдают отчёт о времени выполнения.

Что касается функции проверки на ЦПУ, test_cpu_vector_sum, она состоит из двух вычислительных циклов по 10000 элементам векторов:
cpu_start_time = time()

for i in range(10000):

for j in range(10000):

c_cpu[i] = a[i] + b[i]

cpu_end_time = time()



Значение общего времени ЦПУ составляет разницу между следующим:
CPU Time = cpu_end_time - cpu_start_time



Что касается функции test_gpu_vector_sum, просматривая ядро выполнения вы можете видеть следующее:
__kernel void sum(__global const float *a,

__global const float *b,

__global float *c){

int i=get_global_id(0);

int j;

for(j=0;j< 10000;j++){

c[i]=a[i]+b[i];}



Значение суммы двух векторов выполняется через единственный цикл вычислений.

Полученный результат, как и можно было ожидать, состоит в значительном снижении во времени вычисления для функции test_gpu_vector_sum:
(base) C:\> python testApplicationPyopencl.py




============================================================

OpenCL Platforms and Devices

============================================================

Platform - Name: NVIDIA CUDA

Platform - Vendor: NVIDIA Corporation

Platform - Version: OpenCL 1.2 CUDA 10.1.152

Platform - Profile: FULL_PROFILE

--------------------------------------------------------

Device - Name: GeForce 840M

Device - Type: GPU

Device - Max Clock Speed: 1124 Mhz

Device - Compute Units: 3

Device - Local Memory: 48 KB

Device - Constant Memory: 64 KB

Device - Global Memory: 2 GB

Device - Max Buffer/Image Size: 512 MB

Device - Max Work Group Size: 1024

============================================================

Platform - Name: Intel(R) OpenCL

Platform - Vendor: Intel(R) Corporation

Platform - Version: OpenCL 2.0

Platform - Profile: FULL_PROFILE

--------------------------------------------------------

Device - Name: Intel(R) HD Graphics 5500

Device - Type: GPU

Device - Max Clock Speed: 950 Mhz

Device - Compute Units: 24

Device - Local Memory: 64 KB

Device - Constant Memory: 64 KB

Device - Global Memory: 3 GB

Device - Max Buffer/Image Size: 808 MB

Device - Max Work Group Size: 256

--------------------------------------------------------

Device - Name: Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz

Device - Type: CPU

Device - Max Clock Speed: 2400 Mhz

Device - Compute Units: 4

Device - Local Memory: 32 KB

Device - Constant Memory: 128 KB

Device - Global Memory: 8 GB

Device - Max Buffer/Image Size: 2026 MB

Device - Max Work Group Size: 8192

CPU Time: 39.505873918533325 s

GPU Kernel evaluation Time: 0.013606592 s

GPU Time: 0.019981861114501953 s



Даже несмотря на то, что наш тест не блещет вычислительной выразительностью, он предоставляет полезное указание на значительный потенциал карты GPU.

Также ознакомьтесь...

OpenCL является стандартным крос- платформенным API для разработки приложений, которые эксплуатируют параллельное вычисление в неоднородных системах. Примечательна аналогия с CUDA, включая всё, начиная с имеющейся иерархии памяти, вплоть до непосредственного соответствия между потоками и элементами исполнения.

Даже на самом уровне программирования имеется множество аналогичных сторон и расширений с одной и той же функциональностью.

Однако OpenCL имеет намного более сложную модель управления устройством по причине способности поддержки широкого разнообразия аппаратных средств. С другой стороны, OpenCL разработан для того чтобы получать переносимость между продуктами различных производителей.

Благодаря большей зрелости и узкой специализации аппаратных средств, CUDA предлагает более простое управление устройством и API более высокого уровня, которые делают его более предпочтительным, но только когда вы имеете дело с конкретными архитектурами (то есть графическими картами nVidia).

В своих последующих разделах мы поясняем за и против библиотек CUDA и OpenCL, а также PyCUDA и PyOpenCL.

За OpenCL и PyOpenCL

Аргументы за таковы:

  • Они делают возможным использование неоднородных систем различного типа микропроцессоров.

  • Один и тот же код исполняется в различных системах.

Против OpenCL и PyOpenCL

Аргументы против таковы:

  • Сложное управление устройством

  • API не полностью стабилен

За CUDA и PyCUDA

Аргументы за такие:

Против CUDA и PyCUDA

Аргументы против такие:

  • Поддерживает только самые последние GPU nVidia ы качестве устройств

  • Снижает неоднородность ЦПУ и GPU

Дополнительно

Анлреас Клёкнер сделал ряд лекций по программированию GPU пр помощи PyCuda и PyOpenCL, доступные по ссылкам в ​www.​bu.​edu и www.​youtube.​com.

Программирование GPU с применением Numba

Numba является компилятором Python, который предоставляет основанный на CUDA API. Он разработан в первую очередь для задания численных вычислений, точно также как и библиотека NumPy. В частности, библиотека numba управляет типы массивов данных, предоставляемых NumPy и обрабатывает их.

Действительно, такая эксплуатация параллелизма данных, которая является присущей численным вычислениям с привлечением массивов, является естественным выбором для ускорителей GPU.

Компилятор работает с особыми типами сигнатур (или декораторов) для функций Python и делает возможной компиляцию времени исполнения (такой тип компиляции также имеет название Как раз вовремя, JiT - Just In Time).

Наиболее важными декораторами являются следующие:

  • jit: Позволяет разработчику писать CUDA- подобные функции. Когда они встречаются, имеющийся компилятор транслирует весь код под декоратором в язык псевдоассемблера PTX с тем, чтобы иметь возможность выполнения в GPU.

  • autojit: Снабжает комментарием функцию для процедуры отложенной компиляции, что означает, что такая функция с этой сигнатурой компилируется всего однажды.

  • vectorize: Создаёт так называемую ufunc (NumPy Universal Function), которая получает некую функцию и выполняет её параллельно для векторных аргументов.

  • guvectorize: Строит так называемую gufunc (NumPy Generalized Universal Function). Объект gufunc может работать с целыми подмассивами.

Приготовление

Numba (выпуск 0.45) совместим с Python 2.7 и 3.5 или более поздними версиями, а также с версиями NumPy с 1.7 до 1.16.

Для установки numba рекомендуется, как и для pyopencl, применять инфраструктуру Anaconda, а потому в приглашении Anaconda просто наберите следующее:
(base) C:\> conda install numba



Кроме того, для применения всего потенциала numba следует установить библиотеку cudatoolkit:
(base) C:\> conda install cudatoolkit



После этого можно проверить будут ли определяться как положено библиотека CUDA и GPU.

Из приглашения Anaconda откройте интерпретатор Python:
(base) C:\> python

Python 3.7.3 (default, Apr 24 2019, 15:29:51) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32

Type "help", "copyright", "credits" or "license" for more information.

>>



Самая первая проверка влечёт за собой проверку того установлена ли как положено библиотека CUDA (cudatoolkit):
>>> import numba.cuda.api

>>> import numba.cuda.cudadrv.libs

>>> numba.cuda.cudadrv.libs.test()



Последующий вывод показывает такое качество нашей установки, при котором все проверки возвращают положительный результат:
Finding cublas from Conda environment

located at C:\Users\Giancarlo\Anaconda3\Library\bin\cublas64_10.dll

trying to open library... ok

Finding cusparse from Conda environment

located at C:\Users\Giancarlo\Anaconda3\Library\bin\cusparse64_10.dll

trying to open library... ok

Finding cufft from Conda environment

located at C:\Users\Giancarlo\Anaconda3\Library\bin\cufft64_10.dll

trying to open library... ok

Finding curand from Conda environment

located at C:\Users\Giancarlo\Anaconda3\Library\bin\curand64_10.dll

trying to open library... ok

Finding nvvm from Conda environment

located at C:\Users\Giancarlo\Anaconda3\Library\bin\nvvm64_33_0.dll

trying to open library... ok

Finding libdevice from Conda environment

searching for compute_20... ok

searching for compute_30... ok

searching for compute_35... ok

searching for compute_50... ok

True



В своей второй проверке мы удостоверяем присутствие графической карты:
>>> numba.cuda.api.detect()



Полученный вывод показывает обнаружена ли графическая карта и поддерживается ли она:
Found 1 CUDA devices

id 0 b'GeForce 840M' [SUPPORTED]

compute capability: 5.0

pci device id: 0

pci bus id: 8

Summary:

1/1 devices are supported

True



Как это сделать...

В данном примере мы предоставляем демонстрацию компилятора Numba с применением аннотации @guvectorize.

Наша задача состоит в умножении матриц:

  1. Импортируем guvectorize из библиотеки numba а также модуль numpy:



  2. from numba import guvectorize

  3. import numpy as np



  1. При помощи декоратора @guvectorize мы определяем ту функцию matmul, которая выполнит задачу умножения матриц:



  2. @guvectorize(['void(int64[:,:], int64[:,:], int64[:,:])'],

  3. '(m,n),(n,p)->(m,p)')

  4. def matmul(A, B, C):

  5. m, n = A.shape

  6. n, p = B.shape

  7. for i in range(m):

  8. for j in range(p):

  9. C[i, j] = 0

  10. for k in range(n):

  11. C[i, j] += A[i, k] * B[k, j]



  1. Наша матрица имеет размер 10 × 10, в то время как значения элементов целые:



  2. dim = 10

  3. A = np.random.randint(dim,size=(dim, dim))

  4. B = np.random.randint(dim,size=(dim, dim))



  1. Наконец, мы вызываем свою функцию matmul для предварительно определённых входных матриц:



  2. C = matmul(A, B)



  1. Мы выводим на печать входные матрицы и получаемую в результате матрицу:



  2. print("INPUT MATRIX A")

  3. print(":\n%s" % A)

  4. print("INPUT MATRIX B")

  5. print(":\n%s" % B)

  6. print("RESULT MATRIX C = A*B")

  7. print(":\n%s" % C)


1   2   3   4   5   6   7   8


написать администратору сайта