当前位置: 首页 > 科技观察

使用CuPy将Numpy加速700倍?

时间:2023-03-14 10:33:02 科技观察

就其本身而言,Numpy已经比Python有了巨大的速度提升。当你发现你的Python代码运行缓慢,尤其是有很多for-loops时,你通常可以将数据处理转移到Numpy中,并实现其向量化的极速处理。但有一件事,上述Numpy加速仅在CPU上实现。由于消费级CPU通常有8个或更少的内核,因此并行处理的数量有限,因此可以实现的加速也有限。这导致了一种新的加速工具——CuPy库。什么是CuPy?CuPy是一个借助CUDAGPU库在NVIDIAGPU上实现Numpy数组的库。基于Numpy数组的实现,GPU自带的多个CUDA核心可以带来更好的并行加速。CuPy接口是Numpy的镜像,在大多数情况下,它可以作为Numpy的直接替代品。用户只需将Numpy代码替换为兼容的CuPy代码,即可实现GPU加速。CuPy支持Numpy的大部分数组操作,包括索引、广播、数组数学和各种矩阵转换。用户还可以编写自定义Python代码,以针对不受支持的特殊情况利用CUDA和GPU加速。整个过程只需要一小段C++格式的代码,然后CuPy就可以自动进行GPU转换,这和使用Cython非常相似。在开始使用CuPy之前,用户可以通过pip安装CuPy库:pipinstallcupy使用CuPy在GPU上运行为了满足相应的基准测试,PC配置如下:i7–8700kCPU1080TiGPU32GBofDDR43000MHzRAMCUDA9.0安装CuPy后,用户可以像导入Numpy一样导入CuPy:importnumpyasnpimportcupyascpimporttime在后续编码中,Numpy和CuPy之间的切换就像将Numpy的np替换为CuPy的cp一样简单。以下代码为Numpy和CuPy创建了一个包含10亿个1的3D数组。衡量创建数组的速度,用户可以使用Python的原生时间库:###NumpyandCPUs=time.time()*x_cpu=np.ones((1000,1000,1000))*e=time.time()print(e-s)###CuPyandGPUs=time.time()*x_gpu=cp.ones((1000,1000,1000))*e=time.time()print(e-s)这个很简单!令人难以置信的是,即使上面只是创建一个数组,CuPy仍然快得多。Numpy在1.68秒内创建了一个包含10亿个1的数组,而CuPy只用了0.16秒,加速了10.5倍。但CuPy可以做的不止于此。就像在数组中做一些数学运算。这次将整个数组乘以5并再次检查Numpy和CuPy的速度。###NumpyandCPUs=time.time()*x_cpu*=5*e=time.time()print(e-s)###CuPyandGPUs=time.time()*x_gpu*=5*e=time.time()print(e-s)果然,CuPy再次胜过Numpy。Numpy用了0.507秒,而CuPy只用了0.000710秒,快了整整714.1倍。现在尝试使用更多数组并执行以下三个操作:将数组乘以5将数组本身乘以自身添加###NumpyandCPUs=time。.time()print(e-s)###CuPyandGPUs=time.time()*x_gpu*=5x_gpu*=x_gpux_gpu+=x_gpu*e=time.time()print(e-s)结果表明Numpy执行了整个操作在CPU上这个过程用了1.49秒,而CuPy在GPU上只用了0.0922秒,加速了16.16倍。数组(数据点)规模达到1000万,运算速度大幅提升。使用CuPy可以在GPU上实现Numpy和矩阵运算的多重加速。值得注意的是,用户可以实现的加速在很大程度上取决于他们正在使用的数组的大小。下表显示了不同数组大小(数据点)的加速差异:一旦达到1000万个数据点,速度会急剧增加;超过1亿,速度提升非常明显。Numpy实际上在1000万个数据点以下运行得更快。此外,GPU拥有的内存越多,它可以处理的数据就越多。所以用户要注意GPU显存是否足够处理CuPy需要处理的数据。