第一次面试被问了有没有尝试过并行计算,自己从来没搞过,再加上自己基础确实不行,最后痛失实习机会,所以决定从哪里摔倒就从哪里爬起来
此内容只在于记录自己自学过程中找到的各种资料以及看到的各种内容,同时记录自己遇到的错误,梳理思路,督促自己学下去
注:本人非计算机科班,计算机基础薄弱到极点,可能有些错误会比较弱智
装环境这里,首先是要安装 CUDA 和 CUDNN,这里我最后实际做的过程是跟着下面这篇走的
深度学习—windows10的CUDA安装和jupyter配置教程,超全
全程跟着做会获得该文章的结果:
x 是用来测试 torch 是不是可以用的,安装有没有装对,而 torch.cuda.is_available() 则是看能不能使用 GPU ,结果是 True 则说明前面设置的都是没问题的
还有些博客是使用的 numba ,这个环境问题我没解决,如果用 vscode 加上 jupyter notebook 在上一篇设置好的环境中跑的结果是
不太会怎么解决,打算在咸鱼找个人问问怎么解决,不过 pycharm 上如何跑这一段倒是找到人帮忙配好环境了(咸鱼yyds),下面开始在 pycharm 中继续尝试探索,起码第一部分能跑一部分代码吧
上述代码是来自博客中文领域最详细的Python版CUDA入门教程
代码与结果分别是
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()
print by gpu.
print by gpu.
print by cpu.
会出现这个的结果的原因是
主函数调用GPU核函数,需要执行如 [1, 2] 这样的执行配置,这个配置是告知GPU以多大的并行粒度同时进行计算。gpu_print[1, 2]() 表示同时开启两个线程并行地执行 gpu_print 函数,函数将被并行地执行2次
如果环境没设置好会出现只看到 "print by cpu" 甚至还有报错
现在尝试更深入一点的尝试,依然是来自这一篇博客
from numba import cuda, float32
import numpy as np
import time
import math
def vecAdd(n, a, b, c):
for i in range(n):
c[i] = a[i] + b[i]
@cuda.jit
def add_kernel(x, y, out):
tx = cuda.threadIdx.x
ty = cuda.blockIdx.x
block_size = cuda.blockDim.x
grid_size = cuda.gridDim.x
start = tx + ty * block_size
stride = block_size * grid_size
for i in range(start, x.shape[0], stride):
out[i] = x[i] + y[i]
def test_add():
n = 100000
x = np.arange(n).astype(np.float32)
y = 2 * x
out = np.empty_like(x)
out1 = np.empty_like(x)
threads_per_block = 128
blocks_per_grid = 30
t1 = time.time()
add_kernel[blocks_per_grid, threads_per_block](x, y, out)
print('gpu cost time is:', time.time() - t1)
print(out[:20])
t2 = time.time()
vecAdd(n, x, y, out1)
print('cpu cost time is:', time.time() - t2)
print(out1[:20])
if __name__ =="__main__":
test_add()
运行上述代码,我的实际结果是
可以发现并没有达到 GPU 跑的比 CPU 快,原博客是这么解释的
对此,原博客针对内存优化给出了一份更好的代码
from numba import cuda
import numpy as np
import math
from time import time
@cuda.jit
def gpu_add(a, b, result, n):
idx = cuda.threadIdx.x + cuda.blockDim.x * cuda.blockIdx.x
if idx < n :
result[idx] = a[idx] + b[idx]
def main():
n = 20000000
x = np.arange(n).astype(np.int32)
y = 2 * x
# 拷贝数据到设备端
x_device = cuda.to_device(x)
y_device = cuda.to_device(y)
# 在显卡设备上初始化一块用于存放GPU计算结果的空间
gpu_result = cuda.device_array(n)
cpu_result = np.empty(n)
threads_per_block = 1024
blocks_per_grid = math.ceil(n / threads_per_block)
start = time()
gpu_add[blocks_per_grid, threads_per_block](x_device, y_device, gpu_result, n)
cuda.synchronize()
print("gpu vector add time " + str(time() - start))
start = time()
cpu_result = np.add(x, y)
print("cpu vector add time " + str(time() - start))
if (np.array_equal(cpu_result, gpu_result.copy_to_host())):
print("result correct!")
if __name__ == "__main__":
main()
但经过实际测试,我的结果是
并没有达到原博客那么好的效果,但也的确是比原来快(多次测试后的结果),原因有两个可能方面:
总的来说,磕磕绊绊的体验了一些代码,下一部分开始从原理去学习,推荐大家去原博客学习,我的再怎么说也只是学习别的博客内容以及按自己会的内容梳理而已
[注] 可能会用到的或者出现过的网址