# Cupy和numpy的比较

## 

Cupy是使用NVIDIA CUDA核心进行加速运算,因为GPU上有好多CUDA核心,相比CPU可以同时并行更多的线程,因此可以大大提高运算速度,当数据量达到千万级时,用cupy会大大增加运算速度。

该作业我主要是验证以上观点,通过比较`cupy`和`numpy`在不同矩阵大小下进行加法和乘法的运算时间来验证该观点。

## 实验

### 加法

从 1x1 的大小开始生成随机数矩阵,每次对矩阵的长和宽分别 x2 以扩大矩阵,每个矩阵大小下分别用 `cupy` 和 `numpy` 分别进行十次矩阵相加运算,最后比较他们的平均运算时间(不包括矩阵生成,只包括运算)。得到的结果如下,

```
目前矩阵大小为1x1=1
cupy 加法的平均执行时间是 0.000059 s
numpy 加法的平均执行时间是 0.000004 s
目前矩阵大小为2x2=4
cupy 加法的平均执行时间是 0.000011 s
numpy 加法的平均执行时间是 0.000003 s
目前矩阵大小为4x4=16
cupy 加法的平均执行时间是 0.000012 s
numpy 加法的平均执行时间是 0.000003 s
目前矩阵大小为8x8=64
cupy 加法的平均执行时间是 0.000012 s
numpy 加法的平均执行时间是 0.000005 s
目前矩阵大小为16x16=256
cupy 加法的平均执行时间是 0.000013 s
numpy 加法的平均执行时间是 0.000004 s
目前矩阵大小为32x32=1024
cupy 加法的平均执行时间是 0.000014 s
numpy 加法的平均执行时间是 0.000005 s
目前矩阵大小为64x64=4096
cupy 加法的平均执行时间是 0.000015 s
numpy 加法的平均执行时间是 0.000006 s
目前矩阵大小为128x128=16384
cupy 加法的平均执行时间是 0.000014 s
numpy 加法的平均执行时间是 0.000013 s
目前矩阵大小为256x256=65536
cupy 加法的平均执行时间是 0.000014 s
numpy 加法的平均执行时间是 0.000039 s
目前矩阵大小为512x512=262144
cupy 加法的平均执行时间是 0.000023 s
numpy 加法的平均执行时间是 0.000195 s
目前矩阵大小为1024x1024=1048576
cupy 加法的平均执行时间是 0.000025 s
numpy 加法的平均执行时间是 0.001306 s
目前矩阵大小为2048x2048=4194304
cupy 加法的平均执行时间是 0.000031 s
numpy 加法的平均执行时间是 0.010306 s
目前矩阵大小为4096x4096=16777216
cupy 加法的平均执行时间是 0.000069 s
numpy 加法的平均执行时间是 0.036332 s
目前矩阵大小为8192x8192=67108864
cupy 加法的平均执行时间是 0.000131 s
numpy 加法的平均执行时间是 0.140579 s
目前矩阵大小为16384x16384=268435456
cupy 加法的平均执行时间是 0.003624 s
numpy 加法的平均执行时间是 0.565655 s
......(显存爆了)......
```

可以看到一开始用小矩阵进行加法运算时,`cupy` 运算速度时不及 `numpy` 的,当矩阵大小达到 128x128 时,其速度相近了。当矩阵大小更大时,`cupy` 的优势体现出来了,`cupy` 的运算速度比 `numpy` 快了百倍。 

### 乘法

乘法的测试方法也和加法一样,只是 `add(x, y)` 替换成了 `multiply(x, y)`。具体结果如下,

```
目前矩阵大小为1x1=1
cupy 乘法的平均执行时间是 0.000060 s
numpy 乘法的平均执行时间是 0.000004 s
目前矩阵大小为2x2=4
cupy 乘法的平均执行时间是 0.000012 s
numpy 乘法的平均执行时间是 0.000003 s
目前矩阵大小为4x4=16
cupy 乘法的平均执行时间是 0.000012 s
numpy 乘法的平均执行时间是 0.000003 s
目前矩阵大小为8x8=64
cupy 乘法的平均执行时间是 0.000012 s
numpy 乘法的平均执行时间是 0.000003 s
目前矩阵大小为16x16=256
cupy 乘法的平均执行时间是 0.000013 s
numpy 乘法的平均执行时间是 0.000004 s
目前矩阵大小为32x32=1024
cupy 乘法的平均执行时间是 0.000013 s
numpy 乘法的平均执行时间是 0.000004 s
目前矩阵大小为64x64=4096
cupy 乘法的平均执行时间是 0.000013 s
numpy 乘法的平均执行时间是 0.000006 s
目前矩阵大小为128x128=16384
cupy 乘法的平均执行时间是 0.000013 s
numpy 乘法的平均执行时间是 0.000014 s
目前矩阵大小为256x256=65536
cupy 乘法的平均执行时间是 0.000014 s
numpy 乘法的平均执行时间是 0.000043 s
目前矩阵大小为512x512=262144
cupy 乘法的平均执行时间是 0.000021 s
numpy 乘法的平均执行时间是 0.000189 s
目前矩阵大小为1024x1024=1048576
cupy 乘法的平均执行时间是 0.000025 s
numpy 乘法的平均执行时间是 0.001378 s
目前矩阵大小为2048x2048=4194304
cupy 乘法的平均执行时间是 0.000029 s
numpy 乘法的平均执行时间是 0.010370 s
目前矩阵大小为4096x4096=16777216
cupy 乘法的平均执行时间是 0.000066 s
numpy 乘法的平均执行时间是 0.041170 s
目前矩阵大小为8192x8192=67108864
cupy 乘法的平均执行时间是 0.000127 s
numpy 乘法的平均执行时间是 0.161565 s
目前矩阵大小为16384x16384=268435456
cupy 乘法的平均执行时间是 0.000871 s
numpy 乘法的平均执行时间是 0.651580 s
......(显存爆了)......
```

得出的结论也和加法相同,但我注意到 `cupy` 在 16384x16384 量级的乘法运算上要比加法运算快 4 倍,这是什么原因呢?照理来说,两个运算时间应该相近才对,于是我又在该大小的矩阵乘法下运行了100次加法和乘法,结果如下,

```
目前矩阵大小为16384x16384=268435456
cupy 加法的平均执行时间是 0.001242 s
numpy 加法的平均执行时间是 0.577567 s
cupy 乘法的平均执行时间是 0.001297 s
numpy 乘法的平均执行时间是 0.669743 s
```

可能是因为10次样本太少,导致统计出现了一些偏差,在100次下,`cupy` 乘法和加法的运算时间相近。

## 结论

当数据量大于万级(128x128=16384)时,`cupy` 的运算速度就会超越 `numpy`;当数据量大于百万级(1024x1024=1048576)时,`cupy` 的运算速度远超 `numpy`。

## 附录

具体代码:

- [hello_cupy.py](./hello_cupy.py)