企业网站实名认证怎么做,厦门小鱼网,网站建设与制作dw8教程,wordpress在固定链接设置页面文章目录 加速方法#xff1a;Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids一、Numba简介二、Numba类型#xff1a;CPU GPU三、项目实战 —— 数组的每个元素加23.1、使用 python - range 循环计算 —— #xff08;时耗#xff1a;137.37 秒#xff09;3.2、使用 python… 文章目录 加速方法Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids一、Numba简介二、Numba类型CPU GPU三、项目实战 —— 数组的每个元素加23.1、使用 python - range 循环计算 —— 时耗137.37 秒3.2、使用 python - numpy 数组计算 —— 时耗1.05 秒3.3、使用 numba - CPU 加速计算 —— 时耗13.85 秒3.4、使用 numba - GPU 加速计算 —— 时耗0.13 秒3.5、使用 numba.prange 并行循环计算 加速方法Numba、CuPy、PyTorch、PyCUDA、Dask、Rapids
加速方法简介支持平台适用范围Numba通过即时编译JIT来加速Python函数CPU GPU数值计算密集循环CuPyNumPy的GPU加速库GPU数组操作和数学计算大规模数据集PyTorch深度学习框架GPU张量操作和自动求导PyCUDA与CUDA交互的Python库GPU在Python中编写CUDA代码并在GPU上执行Dask并行计算库CPU GPU并行操作大规模数据集Rapids基于NVIDIA GPU加速的数据科学生态系统GPU提供数据处理和机器学习的库如cuDF、cuML
一、Numba简介
Numba官网专为 NumPy 科学计算而打造的用于加速 Python 代码的即时编译器Just-In-Time, JIT Compiler。 由 Anaconda 公司主导开发 原理使用行业标准LLVM编译器库在运行时将 Python 和 NumPy 代码的子集转换为快速的机器代码。 速度接近 C 或 FORTRAN 的速度 操作简单只需将 Numba 装饰器之一应用到 Python 函数Numba 将使用即时编译JIT编译为原生代码机器代码然后加速运行。 不需要替换 Python 解释器、运行单独的编译步骤也不需要安装 C/C 编译器原生代码Native code直接在计算机硬件上执行的机器代码。 适用范围 只支持NumPy库Numba 基于 NumPy 底层代码开发 不支持其余的Python库自定义-重开发将函数分解为底层代码 1NumPy数值计算CPU将 Python 函数即时编译为机器代码用于加速数学运算等计算密集型任务最初设计。2NumPy数组操作CPU高效处理 NumPy 的数组操作和广播操作且可以加速大型数组操作。3支持并行计算CPU和GPU使用 prange 来并行处理循环结构4支持GPU加速将代码转移到 GPU 上以加速执行 二、Numba类型CPU GPU Numba官网案例1并行化测试jit、prange、dask Numba官网案例2GPU加速 import numba # pip install numba
from numba import cuda, jit##############################################################
Numba装饰器CPU加速
函数说明jit(nopythonTrue, parallelTrue, targetcpu)
输入参数1加速模式nopythonTrue默认、forceobjTrue 备注Numba默认使用nopython编译函数。若无法完成编译将使用对象模式将导致性能损失。2并行模式parallelTrue默认3指定平台targetcpu默认、targetgpu 多种不同的应用jit() # 适用于科学计算、数值计算和密集计算。jit(targetcpu) # CPU加速与jit()等效jit(targetcuda) # GPU加速与cuda.jit()等效jit(nopythonTrue) # 强制使用 nopython 模式将函数尽可能编译成机器代码如果无法完成编译则会引发错误与njit()等效。jit(forceobjTrue) # 强制使用对象模式而不是默认的 nopython 模式。适用于一些特殊情况如涉及动态类型的代码。jit(parallelTrue) # 尝试并行化循环充分利用多核处理器的性能需将range转换为prange。njit() # 强制使用 nopython 模式比jit更快但更严格只接受Numpy数据类型。vectorize # 适用于元素级别的向量化操作单输入和单输出、输出数组的形状由输入数组的形状决定guvectorize # 适用于元素级别的向量化操作多输入和输出数组、输出数组的形状可以指定stencil # 一种基于固定模板的局部计算。通过访问输入数组的邻域元素来计算输出数组的每个元素。
##############################################################
Numba装饰器GPU加速 cuda.jit() # 用于在GPU上执行 CUDA 加速# cuda.jit()与 cuda.jit ———— 若不传递参数两者是等效的。
# cuda.jit 使用默认选项 cuda.jit()并且不需要传递任何参数。
# cuda.jit() 显式调用 cuda.jit 装饰器并且可以传递一些选项参数。三、项目实战 —— 数组的每个元素加2
3.1、使用 python - range 循环计算 —— 时耗137.37 秒
import numpy as npdef numpy_cpu_kernel(input_array):shape input_array.shape # 获取数组形状result_array np.zeros(shape) # 初始化一个全零数组形状与输入数组相同# 循环遍历每个元素将其加 2for z in range(shape[0]):for y in range(shape[1]):for x in range(shape[2]):result_array[z, y, x] input_array[z, y, x] 2return result_arrayif __name__ __main__:# 在主机上创建 3D 数组input_data np.zeros((1024, 1024, int(1024 * 0.5)))import timestart_time time.time()# 在主机上调用 NumPy 函数result_array_on_host numpy_cpu_kernel(input_data)print(f总共耗时: {time.time() - start_time:.2f} 秒)# 打印结果数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())总共耗时: 137.37 秒3.2、使用 python - numpy 数组计算 —— 时耗1.05 秒
import numpy as npdef numpy_cpu_kernel(input_array):return input_array 2 # 将输入数组的每个元素加 2if __name__ __main__:# 在主机上创建 3D 数组input_data np.zeros((1024, 1024, int(1024 * 0.5)))import timestart_time time.time()# 在主机上调用 NumPy 函数result_array_on_host numpy_cpu_kernel(input_data)print(f总共耗时: {time.time() - start_time:.2f} 秒)# 打印结果数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())总共耗时: 1.05 秒3.3、使用 numba - CPU 加速计算 —— 时耗13.85 秒
from numba import jit
import numpy as np# 使用 Numba 的 jit 装饰器进行即时编译
jit(nopythonTrue)
def my_cpu_kernel(input_array, output_array):# 使用三个嵌套循环遍历 3D 输入数组的每个元素for x in range(input_array.shape[2]):for z in range(input_array.shape[0]):for y in range(input_array.shape[1]):# 执行简单的操作将输入数组的元素加 2并将结果存储到输出数组中output_array[z, y, x] input_array[z, y, x] 2if __name__ __main__:# 1在主机上创建输入数组input_data np.zeros((1024, 1024, int(1024 * 0.5))) # 创建一个全零的3D数组result_array_on_host np.zeros_like(input_data)# 2在 CPU 上调用加速函数import timestart_time time.time()my_cpu_kernel(input_data, result_array_on_host)print(f总运行时间: {time.time() - start_time:.2f} 秒) # 打印运行时间# 打印输出数组的形状和最大值print(result_array_on_host.shape)print(result_array_on_host.max())总共耗时: 13.8582594394683843.4、使用 numba - GPU 加速计算 —— 时耗0.13 秒
【深度学习环境配置】Anaconda Pycharm CUDA cuDNN Pytorch Opencv资源已上传 在CUDA编程中 CPU和主存RAM称为主机HostGPU和显存VRAM称为设备Device CPU无法直接读取显存数据GPU无法直接读取主存数据主机与设备必须通过总线Bus相互通讯 RAM是CPU的主内存显存是GPU的专用内存 GPU计算流程 1cuda.to_device()将主机端的数据拷贝到设备端上并在GPU上分配与主机上数据相同大小的内存。2cuda.device_array_like()或cuda.device_array()在GPU上分配用于输出数据的内存。3gpu[blocks_per_grid, threads_per_block]在CPU上调用GPU函数启动GPU多核并行计算详细看1.2。4CPU与GPU异步计算 GPU函数的启动方式是异步的 异步计算CPU不会等待GPU函数执行完毕才执行下一行代码。同步计算在调用的GPU函数后面添加 cuda.synchronize() —— 表示CPU需要等待GPU函数执行后再计算。 5cuda.copy_to_host()将GPU设备端的计算结果拷贝回CPU主机端上。Python通过Numba实现GPU加速 numba的GPU加速 —— 1天到1分钟的转变numba的GPU加速 —— 超过Numpy的速度有多难 from numba import cuda
import numpy as np# 使用 Numba 的 CUDA 装饰器进行 GPU 加速
cuda.jit
def my_cuda_kernel(input_array, output_array):x cuda.grid(1) # 使用1维索引if x input_array.shape[2]: # 检查索引是否在数组范围内for z in range(input_array.shape[0]):for y in range(input_array.shape[1]):# 执行简单的操作将输入数组的元素加 2并将结果存储到输出数组中output_array[z, y, x] input_array[z, y, x] 2if __name__ __main__:# 1在主机上创建3D数组input_data np.zeros((1024, 1024, int(1024 * 0.5)))# 2拷贝数据 在GPU上分配内存device_input_array cuda.to_device(input_data) # 将主机上的input_data复制到GPU上device_output_array cuda.device_array_like(input_data) # 在GPU上开辟一个与 input_data 相同形状的数组用于存储计算结果。# 3定义线程块的大小 线程块的数量threads_per_block (16,)blocks_per_grid_x (input_data.shape[2] threads_per_block[0] - 1) // threads_per_block[0]blocks_per_grid (blocks_per_grid_x,)# 4调用CUDA核函数import timestart_time time.time()my_cuda_kernel[blocks_per_grid, threads_per_block](device_input_array, device_output_array)print(f总运行时间: {time.time() - start_time:.2f} 秒) # 打印运行时间# 5将结果从GPU复制回主机result_array_on_host device_output_array.copy_to_host() # 将计算结果从GPU复制回主机print(result_array_on_host.shape)print(result_array_on_host.max())总共耗时: 0.1360003948211673.5、使用 numba.prange 并行循环计算 prangeparallel range类似于Python标准库中的 range但专用于并行化循环计算引入额外的开销。可以在多个处理器核心上同时执行循环以提高密集型计算的性能。 适用范围 大规模数据和密集型计算只有在循环非常庞大时才可以充分利用多核处理器否则将导致耗时更长。 独立迭代每个迭代之间不存在依赖关系时若后面的迭代依赖于前面迭代的计算结果类似于递归函数可能会导致耗时更长。 NumPy数组使用NumPy数组可以表现出更好的性能。 import random
import numba
import time###############################################
# numba加速 串行版本Serial version
###############################################
numba.jit(nopythonTrue)
def monte_carlo_pi_serial(nsamples):acc 0for i in range(nsamples):x random.random()y random.random()if (x ** 2 y ** 2) 1.0:acc 1return 4.0 * acc / nsamples###############################################
# numba加速 并行版本Parallel version
###############################################
numba.jit(nopythonTrue, parallelTrue)
def monte_carlo_pi_parallel(nsamples):acc 0for i in numba.prange(nsamples):x random.random()y random.random()if (x ** 2 y ** 2) 1.0:acc 1return 4.0 * acc / nsamplesif __name__ __main__:start_time time.time()monte_carlo_pi_serial(33000000) # 串行版本print(f总共耗时: {time.time() - start_time:.2f} 秒)start_time time.time()monte_carlo_pi_parallel(33000000) # 并行版本print(f总共耗时: {time.time() - start_time:.2f} 秒)一万次循环:0.277700185775756840.42730212211608887三千万次循环:0.464895009994506840.4749984741210937510亿次循环:6.72973990440368651.1980292797088623100亿次循环:67.732758283615116.892062425613403