返回顶部
首页 > 资讯 > 后端开发 > Python >Python实现GPU加速的基本操作
  • 540
分享到

Python实现GPU加速的基本操作

2024-04-02 19:04:59 540人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录CUDA的线程与块用GPU打印线程编号用GPU打印块编号用GPU打印块的维度用GPU打印线程的维度总结GPU所支持的最大并行度GPU的加速效果总结概要CUDA的线程与块 GPU从

CUDA的线程与块

GPU从计算逻辑来讲,可以认为是一个高并行度的计算阵列,我们可以想象成一个二维的像围棋棋盘一样的网格,每一个格子都可以执行一个单独的任务,并且所有的格子可以同时执行计算任务,这就是GPU加速的来源。那么刚才所提到的棋盘,每一列都认为是一个线程,并有自己的线程编号;每一行都是一个块,有自己的块编号。我们可以通过一些简单的程序来理解这其中的逻辑:

用GPU打印线程编号


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    print ('threadIdx:', cuda.threadIdx.x)

if __name__ == '__main__':
    gpu[2,4]()

threadIdx: 0
threadIdx: 1
threadIdx: 2
threadIdx: 3
threadIdx: 0
threadIdx: 1
threadIdx: 2
threadIdx: 3

用GPU打印块编号


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    print ('blockIdx:', cuda.blockIdx.x)

if __name__ == '__main__':
    gpu[2,4]()

blockIdx: 0
blockIdx: 0
blockIdx: 0
blockIdx: 0
blockIdx: 1
blockIdx: 1
blockIdx: 1
blockIdx: 1

用GPU打印块的维度


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    print ('blockDim:', cuda.blockDim.x)

if __name__ == '__main__':
    gpu[2,4]()

blockDim: 4
blockDim: 4
blockDim: 4
blockDim: 4
blockDim: 4
blockDim: 4
blockDim: 4
blockDim: 4

用GPU打印线程的维度


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    print ('gridDim:', cuda.gridDim.x)

if __name__ == '__main__':
    gpu[2,4]()

gridDim: 2
gridDim: 2
gridDim: 2
gridDim: 2
gridDim: 2
gridDim: 2
gridDim: 2
gridDim: 2

总结

我们可以用如下的一张图来总结刚才提到的GPU网格的概念,在上面的测试案例中,我们在GPU上划分一块2*4大小的阵列用于我们自己的计算,每一行都是一个块,每一列都是一个线程,所有的网格是同时执行计算的内容的(如果没有逻辑上的依赖的话)。

GPU所支持的最大并行度

我们可以用几个简单的程序来测试一下GPU的并行度,因为每一个GPU上的网格都可以独立的执行一个任务,因此我们认为可以分配多少个网格,就有多大的并行度。本机的最大并行应该是在\(2^40\),因此假设我们给GPU分配\(2^50\)大小的网格,程序就会报错:


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    pass

if __name__ == '__main__':
    gpu[2**50,1]()
    print ('Running Success!')

运行结果如下:

Traceback (most recent call last):
File "numba_cuda_test.py", line 10, in <module>
gpu[2**50,1]()
File "/home/dechin/.local/lib/python3.7/site-packages/numba/cuda/compiler.py", line 822, in __call__
self.stream, self.sharedmem)
File "/home/dechin/.local/lib/python3.7/site-packages/numba/cuda/compiler.py", line 966, in call
kernel.launch(args, griddim, blockdim, stream, sharedmem)
File "/home/dechin/.local/lib/Python3.7/site-packages/numba/cuda/compiler.py", line 699, in launch
cooperative=self.cooperative)
File "/home/dechin/.local/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 2100, in launch_kernel
None)
File "/home/dechin/.local/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 300, in safe_cuda_api_call
self._check_error(fname, retcode)
File "/home/dechin/.local/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py", line 335, in _check_error
raise CudaAPIError(retcode, msg)
numba.cuda.cudadrv.driver.CudaAPIError: [1] Call to cuLaunchKernel results in CUDA_ERROR_INVALID_VALUE

而如果我们分配一个额定大小之内的网格,程序就可以正常的运行:


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    pass

if __name__ == '__main__':
    gpu[2**30,1]()
    print ('Running Success!')

这里加了一个打印输出:

Running Success!

需要注意的是,两个维度上的可分配大小是不一致的,比如本机的上限是分配230*210大小的空间用于计算:


# numba_cuda_test.py

from numba import cuda

@cuda.jit
def gpu():
    pass

if __name__ == '__main__':
    gpu[2**30,2**10]()
    print ('Running Success!')

同样的,只要在允许的范围内都是可以执行成功的:

Running Success!

如果在本机上有多块GPU的话,还可以通过select_device的指令来选择执行指令的GPU编号:


# numba_cuda_test.py

from numba import cuda
cuda.select_device(1)
import time

@cuda.jit
def gpu():
    pass

if __name__ == '__main__':
    gpu[2**30,2**10]()
    print ('Running Success!')

如果两块GPU的可分配空间一致的话,就可以运行成功:

Running Success!

GPU的加速效果

前面我们经常提到一个词叫GPU加速,GPU之所以能够实现加速的效果,正源自于GPU本身的高度并行性。这里我们直接用一个数组求和的案例来说明GPU的加速效果,这个案例需要得到的结果是\(b_j=a_j+b_j\),将求和后的值赋值在其中的一个输入数组之上,以节省一些内存空间。当然,如果这个数组还有其他的用途的话,是不能这样操作的。具体代码如下:


# gpu_add.py

from numba import cuda
cuda.select_device(1)
import numpy as np
import time

@cuda.jit
def gpu(a,b,DATA_LENGHTH):
    idx = cuda.threadIdx.x + cuda.blockIdx.x * cuda.blockDim.x
    if idx < DATA_LENGHTH:
        b[idx] += a[idx]

if __name__ == '__main__':
    np.random.seed(1)
    DATA_EXP_LENGTH = 20
    DATA_DIMENSioN = 2**DATA_EXP_LENGTH
    np_time = 0.0
    nb_time = 0.0
    for i in range(100):
        a = np.random.randn(DATA_DIMENSION).astype(np.float32)
        b = np.random.randn(DATA_DIMENSION).astype(np.float32)
        a_cuda = cuda.to_device(a)
        b_cuda = cuda.to_device(b)
        time0 = time.time()
        gpu[DATA_DIMENSION,4](a_cuda,b_cuda,DATA_DIMENSION)
        time1 = time.time()
        c = b_cuda.copy_to_host()
        time2 = time.time()
        d = np.add(a,b)
        time3 = time.time()
        if i == 0:
            print ('The error between numba and numpy is: ', sum(c-d))
            continue
        np_time += time3 - time2
        nb_time += time1 - time0
    print ('The time cost of numba is: {}s'.fORMat(nb_time))
    print ('The time cost of numpy is: {}s'.format(np_time))

需要注意的是,基于Numba实现的Python的GPU加速程序,采用的jit即时编译的模式,也就是说,在运行调用到相关函数时,才会对其进行编译优化。换句话说,第一次执行这一条指令的时候,事实上达不到加速的效果,因为这个运行的时间包含了较长的一段编译时间。但是从第二次运行调用开始,就不需要重新编译,这时候GPU加速的效果就体现出来了,运行结果如下:

$ python3 gpu_add.py The error between numba and numpy is: 0.0
The time cost of numba is: 0.018711328506469727s
The time cost of numpy is: 0.09502553939819336s

可以看到,即使是相比于Python中优化程度十分强大的的Numpy实现,我们自己写的GPU加速的程序也能够达到5倍的加速效果(在前面一篇博客中,针对于特殊计算场景,加速效果可达1000倍以上),而且可定制化程度非常之高。

总结概要

本文针对于Python中使用Numba的GPU加速程序的一些基本概念和实现的方法,比如GPU中的线程和模块的概念,以及给出了一个矢量加法的代码案例,进一步说明了GPU加速的效果。需要注意的是,由于Python中的Numba实现是一种即时编译的技术,因此第一次运算时的时间会明显较长,所以我们一般说GPU加速是指从第二步开始的运行时间。对于一些工业和学界常见的场景,比如分子动力学模拟中的系统演化,或者是深度学习与量子计算中的参数优化,都是相同维度参数多步运算的一个过程,非常适合使用即时编译的技术,配合以GPU高度并行化的加速效果,能够在实际工业和学术界的各种场景下发挥巨大的作用。

到此这篇关于Python实现GPU加速的基本操作的文章就介绍到这了,更多相关Python GPU加速内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python实现GPU加速的基本操作

本文链接: https://lsjlt.com/news/134173.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python实现GPU加速的基本操作
    目录CUDA的线程与块用GPU打印线程编号用GPU打印块编号用GPU打印块的维度用GPU打印线程的维度总结GPU所支持的最大并行度GPU的加速效果总结概要CUDA的线程与块 GPU从...
    99+
    2024-04-02
  • Python实现双向链表基本操作
    双向链表的基本操作的实现,供大家参考,具体内容如下 在之前的博客中介绍了三种链表,分别是单链表、单向循环链表以及双向链表。本篇博客将用Python来实现双向链表的如下操作。(用到的工...
    99+
    2024-04-02
  • Python操作SQLLite(基本操作
      SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。 Python SQLITE数据库是一款非常...
    99+
    2023-01-31
    操作 Python SQLLite
  • Python+OpenCV实现基本的图像处理操作
    目录模块的安装图片的各种操作读取图像展示图像图片保存图片的各种属性图像的基本操作今天小编来和大家分享一下Python在图像处理当中的具体应用,那既然是图像处理,那必然要提到openc...
    99+
    2024-04-02
  • MongoDb的基本操作快速入门
    1.MongoDb简介   mongodb是一个基于分布式存储的开源数据库系统又被称为文档数据库,可以将数据存储为一个文档,数据结构有键值对(key=>value)对组成,存储的文...
    99+
    2024-04-02
  • python基本操作(四)
    为什么交互 计算机取代人类,解放劳动力 如何交互 print('-'*100) input('请输入你的姓名:') print(""100) Python2和Python3的交互(熟悉) name = raw_input('请输入你的姓...
    99+
    2023-01-31
    操作 python
  • python基本操作(五)
    if 条件: 代码1 代码2 代码3 代码块(同一缩进级别的代码,例如代码1、代码2和代码3是相同缩进的代码,这三个代码组合在一起就是一个代码块,相同缩进的代码会自上而下的运行) cls ='humale' gender = 'fema...
    99+
    2023-01-31
    操作 python
  • Python中PyMySQL的基本操作
    目录简介1、查找数据2、添加数据3、删除数据4、更改数据简介 Pymysql 是在 python3.x 版本中用于连接 MySQL 服务器的一个库 PyMySQL 遵循 Python 数据库 API v2.0 规范,并包...
    99+
    2024-04-02
  • python对kafka的基本操作
    from kafka import KafkaProducerfrom kafka import KafkaConsumerfrom kafka.structs import TopicPartitionimport time boots...
    99+
    2023-01-31
    操作 python kafka
  • Python+selenium实现浏览器基本操作详解
    目录关闭 driver 启动的浏览器浏览器最大化与设置浏览器窗口大小浏览器最大化设置浏览器窗口大小浏览器的前进、后退与刷新页面关闭 driver 启动的浏览器 上一章节文末,我们介绍...
    99+
    2024-04-02
  • C++顺序表的基本操作实现
    目录1.顺序表的定义2.顺序表上基本操作的实现完整代码如下:总结1.顺序表的定义 线性表的顺序存储又称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相...
    99+
    2024-04-02
  • Python+OpenCV实现图像基本操作的示例详解
    目录1. 计算机眼中的图像2. 图像的表示3. 基础操作 图像的读取4. 截取部分图像数据(ROI)5. 视频的读取6. 边界填充7. 图像的加法 图像的加法1. 计算机眼中的图像 ...
    99+
    2023-05-16
    Python OpenCV图像基本操作 Python OpenCV图像操作 Python OpenCV图像 Python OpenCV
  • python 字典基本操作
    字典的基本构成---键+:+键值+{},如a={'a':1,'b':2,'c':3}字典的键是不可以改变的,所以定义的时候键应该是数字,字符,元组等不可变值,不能用列表如果想要修改某一键值,直接修改即可---a['c']=4如果想要添加一个...
    99+
    2023-01-31
    字典 操作 python
  • Python 常见加密操作的实现
    目录hashlib加密hmac加密secretsbase64cryptographyhashlib加密 import hashlib   # 有很多种加密方式,md5,...
    99+
    2024-04-02
  • MySQL基本操作和基于MySQL基本操作的综合实例项目
    文章目录 MySQL数据库的基本操作和基于MySQL数据库基本操作的综合实例项目1、 登入MySQL数据库1、创建数据库2、删除数据库3、综合案例——数据库的创建和删除cmd环境创建和删除数据...
    99+
    2023-09-04
    mysql 数据库 sql ide 数据库开发
  • Python中列表的基本操作
    本篇内容主要讲解“Python中列表的基本操作”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python中列表的基本操作”吧!如何创建列表?列表是最常用的Python数据类型,它可以作为一个方括...
    99+
    2023-06-02
  • pandas 使用merge实现百倍加速的操作
    对于非连续数据集,数据可视化时候需要每七天一个采样点。要求是选择此前最新的数据作为当日的数据展示,譬如今天是2019-06-18,而数据集里只有2019-06-15,那就用2019-...
    99+
    2024-04-02
  • Python实现基本数据结构中栈的操作示例
    本文实例讲述了Python实现基本数据结构中栈的操作。分享给大家供大家参考,具体如下: #! /usr/bin/env python #coding=utf-8 #Python实现基本数据结构---栈操...
    99+
    2022-06-04
    数据结构 示例 操作
  • C++实现AVL树的基本操作指南
    目录AVL树的概念AVL树的插入AVL树的四种旋转右单旋左单旋左右双旋右左双旋查找其他接口析构函数拷贝构造拷贝赋值总结AVL树的概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或...
    99+
    2024-04-02
  • Python文件基本操作实用指南
    文件的存储方式 在计算机中,文件是以 二进制的方式保存在磁盘上的 文本文件和二进制文件 文本文件 可以使用文本编辑软件查看...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作