首页 > 编程语言 >Python_CUDA入门教程学习记录

Python_CUDA入门教程学习记录

时间:2025-01-18 11:56:44浏览次数:3  
标签:thread blockDim Python 入门教程 CUDA print GPU block cuda

这是本人21年读书时学习CUDA基础知识保留的一些笔记,学习时的内容出处和图片来源不记得了,仅作为个人记录!

CUDA编程关键术语:
  • host : cpu
  • device : GPU
  • host memory : cpu 内存
  • device memory : gpu onboard显存
  • kernels : 调用CPU上的在GPU执行的函数
  • device function : 只能在GPU上执行的函数

安装Numba库:
$ conda install numba

检查一下CUDA和Numba是否安装成功

from numba import cuda print(cuda.gpus)

如果上述步骤没有问题,可以得到结果:<Managed Device 0>…

一般使用CUDA_VISIBLE_DEVICES这个环境变量来选择某张卡。如选择5号GPU卡运行你的程序。
CUDA_VISIBLE_DEVICES='5' python example.py

GPU计算流程
  1. 初始化,并将必要的数据拷贝到GPU设备的显存上
  2. CPU调用GPU函数,启动GPU多个核心同时进行计算。
  3. CPU与GPU异步计算。
  4. 将GPU计算结果拷贝回主机端,得到计算结果。
与传统CPU对比

在这里插入图片描述

from numba import cuda

def cpu_print():
    print("print by cpu.")

@cuda.jit
def gpu_print():
    # GPU核函数
    print("print by gpu.")

def main():
    gpu_print[1, 2]()
    cuda.synchronize()
    cpu_print()

if __name__ == "__main__":
    main()
  • 使用from numba import cuda引入cuda库
  • 在GPU函数上添加@cuda.jit装饰符,表示该函数是一个在GPU设备上运行的函数,GPU函数又被称为核函数
  • 主函数调用GPU核函数时,需要添加如[1, 2]这样的执行配置,这个配置是在告知GPU以多大的并行粒度同时进行计算。gpu_print[1, 2]()表示同时开启2个线程并行地执行gpu_print函数,函数将被并行地执行2次。下文会深入探讨如何设置执行配置。
  • GPU核函数的启动方式是异步的:启动GPU函数后,CPU不会等待GPU函数执行完毕才执行下一行代码。必要时,需要调用cuda.synchronize(),告知CPU等待GPU执行完核函数后,再进行CPU端后续计算。这个过程被称为同步,也就是GPU执行流程图中的红线部分。如果不调用cuda.synchronize()函数,执行结果也将改变,"print by cpu.将先被打印。虽然GPU函数在前,但是程序并没有等待GPU函数执行完,而是继续执行后面的cpu_print函数,由于CPU调用GPU有一定的延迟,反而后面的cpu_print先被执行,因此cpu_print的结果先被打印了出来。
Thread层次结构

在这里插入图片描述

  • CUDA将核函数所定义的运算称为线程(Thread),多个线程组成一个块(Block),多个块组成网格(Grid)。这样一个grid可以定义成千上万个线程,也就解决了并行执行上万次操作的问题。例如,把前面的程序改为并行执行8次:可以用2个block,每个block中有4个thread。原来的代码可以改为gpu_print[2, 4]()其中方括号中第一个数字表示整个grid有多少个block,方括号中第二个数字表示一个block有多少个thread

  • 实际上,线程(thread)是一个编程上的软件概念。从硬件来看,thread运行在一个CUDA核心上,多个thread组成的block运行在Streaming Multiprocessor(SM的概念详见本系列第一篇文章)多个block可以运行在一个SM上,但是一个额block只能运行在一个SM上,多个block组成的grid运行在一个GPU显卡上。

在这里插入图片描述

CUDA提供了一系列内置变量,以记录thread和block的大小及索引下标。以[2, 4]这样的配置为例:
  1. blockDim.x变量表示block的大小是4,即每个block有4个thread,
  2. threadIdx.x变量是一个从0到blockDim.x - 1(4-1=3)的索引下标,记录这是第几个thread;`
  3. gridDim.x`变量表示grid的大小是2,即每个grid有2个block,
  4. blockIdx.x变量是一个从0到gridDim.x - 1(2-1=1)的索引下标,记录这是第几个block。

在这里插入图片描述

  • 某个thread在整个grid中的位置编号为:threadIdx.x + blockIdx.x * blockDim.x

在这里插入图片描述

from numba import cuda

def cpu_print(N):
    for i in range(0, N):
        print(i)

@cuda.jit
def gpu_print(N):
    idx = cuda.threadIdx.x + cuda.blockIdx.x * cuda.blockDim.x 
    if (idx < N):
        print(idx)

def main():
    print("gpu print:")
    gpu_print[2, 4](8)
    cuda.synchronize()
    print("cpu print:")
    cpu_print(8)

if __name__ == "__main__":
    main() #结果相同
  • 这里的GPU函数在每个CUDA thread中打印了当前thread的编号,起到了CPU函数for循环同样的作用。因为for循环中的计算内容互相不依赖,也就是说,某次循环只是专心做自己的事情,循环第i次不影响循环第j次的计算,所以这样互相不依赖的for循环非常适合放到CUDAthread里做并行计算。 在实际使用中,我们一般将CPU代码中互相不依赖的的for循环适当替换成CUDA代码。

  • 这份代码打印了8个数字,核函数有一个参数N,N = 8,假如我们只想打印5个数字呢?当前的执行配置共2 * 4 = 8个线程,线程数8与要执行的次数5不匹配,不过我们已经在代码里写好了if (idx < N)的判断语句,判断会帮我们过滤不需要的计算。我们只需要把N = 5传递给gpu_print函数中就好,CUDA仍然会启动8个thread,但是大于等于N的thread不进行计算。注意,当线程数与计算次数不一致时,一定要使用这样的判断语句,以保证某个线程的计算不会影响其他线程的数据。

Block大小的设置
  • 不同的执行配置会影响GPU程序的速度,一般需要多次调试才能找到较好的执行配置,在实际编程中,执行配置[gridDim, blockDim]应参考下面的方法:

    1. block运行在SM上,不同硬件架构(Turing、Volta、Pascal…)的CUDA核心数不同,一般需要根据当前硬件来设置block的大小blockDim(执行配置中第二个参数)。一个block中的thread数最好是32、128、256的倍数注意,限于当前硬件的设计,block大小不能超过1024
    2. grid的大小gridDim(执行配置中第一个参数),即一个grid中block的个数可以由总次数N除以blockDim,并向上取整。
      例如,我们想并行启动1000个thread,可以将blockDim设置为128,1000 ÷ 128 = 7.8,向上取整为8。使用时,执行配置可以写成gpuWork[8, 128](),CUDA共启动8 * 128 = 1024个thread,实际计算时只使用前1000个thread,多余的24个thread不进行计算。

注意,这几个变量比较容易混淆,再次明确一下:blockDim是block中thread的个数(如果是二维blockDim.x是列数,blockDim.y是行数),一个block中的threadIdx最大不超过blockDimgridDim是grid中block的个数,一个grid中的blockIdx最大不超过gridDim

以上讨论中,block和grid大小均是一维,实际编程使用的执行配置常常更复杂,block和grid的大小可以设置为二维甚至三维,如下图所示。

  • 例如Thread(2,0)的位置计算,threadIdx.x = 2,threadIdx.y=0,blockIdx.x = 1,blockIdx.y = 1,
    blockDim.x = 4,blockDim.y = 3,计算得该线程在grid中所有线程的索引为
    Thread_x = blockIdx.x* blockDim.x+threadIdx.x = 6
    Thread_y = blockIdx.y* blockDim.y+threadIdx.y = 3
内存分配
  • cuda.device_array(): 在设备上分配一个空向量,类似于numpy.empty()
  • cuda.to_device():将主机的数据拷贝到设备
ary = np.arange(10) 
device_ary = cuda.to_device(ary)
  • cuda.copy_to_host():将设备的数据拷贝回主机
host_ary = device_ary.copy_to_host()

在这里插入图片描述

  • Globel Memory : 最常用,传输到gpu的数据基本都在这里(显存)所有thread共享(相对于其他memory相对慢)
  • Constant Memory:常量内存
  • Texture Memory:纹理内存
  • Shared Memory :block中所有thread共享
  • local Memory :thread独自使用
  • registers : 寄存器 thread独自使用

标签:thread,blockDim,Python,入门教程,CUDA,print,GPU,block,cuda
From: https://blog.csdn.net/qq_40938217/article/details/145222540

相关文章

  • python 一口气画三类提琴图对比
    要从三个CSV文件中提取指定列名(这里是s2),并绘制小提琴图,其中横坐标是11km、17km、23km,纵坐标名称是S30/(km2),你可以使用Python的pandas库来处理CSV数据,seaborn库来绘制小提琴图,以及matplotlib库来设置图形属性。以下是一个完整的示例代码:#!usr/bin/envpython#-*-coding:utf-8-......
  • 第10个项目:图片转Turtle代码生成器Python源码
    完整源码在文末,可直接下载使用,也可在此基础上做定制开发。应用场景:上传图片,自动生成Turtle代码。点击执行代码,可把图片完整画出来。功能特点:支持设置背景图片,可在背景图片上嵌入式画图,很有意思。软件截图:核心源码:importtkinterastkfromtkinterimportfiledialog,t......
  • 【2024年华为OD机试】 (A卷,200分)- 硬件产品销售方案(Java & JS & Python&C/C++)
    一、问题描述题目描述某公司目前推出了AI开发者套件,AI加速卡,AI加速模块,AI服务器,智能边缘多种硬件产品,每种产品包含若干个型号。现某合作厂商要采购金额为amount元的硬件产品搭建自己的AI基座。例如当前库存有N种产品,每种产品的库存量充足,给定每种产品的价格,记为price(不......
  • 【2024年华为OD机试】 (B卷,100分)- 流水线(Java & JS & Python&C/C++)
    一、问题描述题目描述一个工厂有m条流水线,来并行完成n个独立的作业,该工厂设置了一个调度系统,在安排作业时,总是优先执行处理时间最短的作业。现给定流水线个数m,需要完成的作业数n,每个作业的处理时间分别为t1,t2,...,tn。请你编程计算处理完所有作业的耗时为多......
  • 股票API接口使用python、JAVA等多种语言实例代码演示免费获取实时数据、历史数据、CDM
    ​最新整理的股票API接口,下方所有接口链接均可直接点击验证,查看返回的数据。沪深两市股票列表股票API接口链接(可点击验证):https://api.mairui.club/hslt/list/LICENCE-66D8-9F96-0C7F0FBCD073【实时数据接口】沪深两市实时交易数据接口股票API接口链接(可点击验证):https:......
  • Python 进阶 - 多线程(一)
    Python进阶-多线程相关概念解释器GILthreading方法属性threading.enumerate()threading.active_count()threading.current_thread()threading.get_ident()threading.main_thread()threading.stack_size([size])threading.get_native_id()threading.TIMEOUT_MAX线程......
  • SpringCloud+Vue+Python人工智能(fastAPI,机器学习,深度学习)前后端架构各功能实现思路
    随着公司业务的增加,公司需要一个java+python人工智能相互配合架构,正常网站业务用java来做,而ai,例如电价预测等回归任务,以及大模型预测全网负荷,新能源出力等任务,使用python通过fastapi暴露接口来做,那么就需要springcloud架构注册发现。前端统一使用Vue进行效果的展示因此本......
  • Python图形用户界面(GUI)库
    Python图形用户界面(GUI)库是用于创建图形用户界面的工具集,它们允许开发者使用Python语言来构建具有图形元素的用户界面。以下是一些常用的PythonGUI库:1.Tkinter•简介:Tkinter是Python的标准GUI库,它提供了创建窗口、按钮、文本框和其他GUI组件的工具。由于它是Python安装包......
  • 第 6 课 Python函数和模块
    1.函数介绍        在Python语言中,函数可分为内置函数和自定义函数。内置函数也称作内建函数,是Python自带的函数,无需导入任何函数库即可直接调用。常用的内置函数有print()、input()、range()等。自定义函数就是将一段有规律的、可重复使用的代码定义成函数,以提升......
  • Python 字符串分割时 spilt 和 re 效率对比
    假设有一些文件名是数字_文档名的格式,如何用python将数字提取出来?可以使用Python的正则表达式模块re提取文件名中的数字部分。以下是实现代码:示例代码:importre#示例文件名列表file_names=["1_file1.txt","2_file2.txt","10_document.doc","random_file.......