Python - 深度学习系列13- 显卡与CPU计算对比

说明

因为装3060Ti的时候踩了坑(雷?),所以不太清楚这张卡是不是如同之前想象的一样,所以这篇文章会进行一系列的实验和对比。可能对其他希望用显卡进行计算的人有所帮助。

  • 1 本篇的代码可以在装好显卡(以及环境)以后测试。
  • 2 估算CPU以及不同显卡间的算力差距。

显卡计算的特点是:只要内存不爆,那么多大的矩阵计算时间是差不多的。

1 基本概念

如果把显卡只当成矩阵计算的工具,那么最重要的就是矩阵的尺寸/数据类型。因为矩阵占用的空间是平方增加的,所以要清除存储允许的计算上限。

float16类型在深度学习领域CNN的模型压缩,加速推理中常用,因为float32太占空间了。

  • float64 : 8字节 (双精度)
  • float32 : 4字节 (单精度,默认 1 个符号位,8 个指数位,23 个尾数位)
  • float16: 2字节 (半精度,1 个符号位,5 个指数位,10 个尾数位)

2 测试代码

这段代码来自这篇文章,我做些改造。
当前机器的配置是:

  • 1 CPU:3400G (4核八线程 3.7GHZ)
  • 2 Memory: 32G(16X2)
  • 3 显卡:3060Ti (8G显存)

使用的计算包:

  • 1 numpy
  • 2 torch

测试计算两个向量间的欧几里得距离

2.1 CPU计算(10亿X10亿)

a = np.random.rand(1,1000000000)
b = np.random.rand(1,1000000000)

# 这段放在jupyter里面跑
%%timeit
#计算numpy计算速度
time_start=time.time()
dist1 = np.linalg.norm(a - b)#numpy求欧氏距离
time_end=time.time()
print(time_end-time_start)

在这里插入图片描述
可以看到,内存几乎被占满了。我们可以看到每个元素的大小(8字节)

type(a[0][0])
---
numpy.float64

速度大约是1.9s
在这里插入图片描述

如果有些数据的前序处理还是在内存中做,毕竟内存比较廉价。

单个向量的大小(1000000000 * 8) / 1e9 ~ 8G,在计算过程中应该是保存axb=c,所以估算总共大小约为24G。

这么大的数据如果放在显卡中计算会直接称爆显存,所以没有比较的意义。

2.2 CPU计算 by numpy(1亿X1亿)

a = np.random.rand(1,100000000)
b = np.random.rand(1,100000000)

%%timeit
#计算numpy计算速度
time_start=time.time()
dist1 = np.linalg.norm(a - b)#numpy求欧氏距离
time_end=time.time()
print(time_end-time_start)

在这里插入图片描述
总共需要约为192ms 。(内存估算2.4G)

2.3 CPU计算 by torch(1亿X1亿)

c = torch.rand(1,100000000)
d = torch.rand(1,100000000)

%%timeit
#计算tensor在cpu上的计算速度
time_start=time.time()
dist2 = F.pairwise_distance(c, d, p=2)#pytorch求欧氏距离
time_end=time.time()
print(time_end-time_start)

大约花费140ms左右,比numpy还要快一点。
在这里插入图片描述
每个元素的大小也是64位的
在这里插入图片描述
从htop中观察,torch似乎调用了更多的cpu资源(内存占用反而更小一些)
在这里插入图片描述

2.4 GPU(3060Ti,4000+ cuda单元)计算 torch(1亿*1亿)

e = torch.rand(1,100000000).cuda()
f = torch.rand(1,100000000).cuda()

%%timeit
#计算tensor在cuda上的计算速度
time_start=time.time()
# 我计算结果的精度调高,原例子是p=2
dist2 = F.pairwise_distance(e, f, p=5)
time_end=time.time()
print(time_end-time_start)

结果不到6ms的时间。
在这里插入图片描述

显卡状态,可以看到这个计算几乎让显卡满载
在这里插入图片描述
和CPU比较,使用显卡计算的速度倍数提升约为23.5倍(141/6)。这个例子似乎CPU并没有完全满载(半载),可以认为GPU比CPU快10倍,之后可以在别的场景再比较。
在这里插入图片描述

显卡价格: ¥2,999 (差不多是30系性价比之王了吧)
CPU价格: ¥999

价格上显卡是CPU的3倍,算力是CPU的10倍,能耗是CPU的3倍,从计算角度上还是比较划算的,不过也并没有想象的差距那么大。以后有机会和同价格的CPUpk一下(3900x,理论上速度应该是3400G的3.3倍):

  • 1 CPU总体上使用起来方便
  • 2 过去x86架构的CPU不太适合计算,但以后ARM架构(例如M1芯片),有可能本身提供比显卡好的多的算力和更低的功耗。

cpu的算力估计可以参考这篇文章
在这里插入图片描述
简单点估算

CPU的算力与CPU的核心的个数,核心的频率,核心单时钟周期的能力三个因素有关系
常用双精度浮点运算能力衡量CPU的科学计算的能力,就是处理64bit小数点浮动数据的能力
支持AVX2的处理器在1个核心1个时钟周期可以执行16次浮点运算,也称为16FLOPs
CPU的算力=核心的个数 x 核心的频率 x 16FLOPs
支持AVX512的处理器在1个核心1个时钟周期可以执行32次浮点运算,也称为32FLOPs
CPU的算力=核心的个数 x 核心的频率 x 32FLOPs

CPU的算力=核心的个数 x 核心的频率 x 32 FLOPs = 8 * 3.7g X32 = 0.95TFLOPS

如果按这个来估计,那么3060Ti应该是10T左右的算力,但10倍是基于之前htop看到的cpu资源耗费比计算的(有可能cpu本身的浮点计算已经全部用满了);假设cpu已经全力计算,那么3060Ti的浮点算力接近20T,和之前估计的就比较接近。

还有就是单精度,或者双精度的影响,参考
在这里插入图片描述
那么按这个来算, 3060ti的算力(未超频版,取主频中值估计):

  • 双精度 FP64: (4864/2)*1.5 G* 2 = 7.3T
  • 单精度 FP32: 4864*1.5 * 2 = 14.5T

默认情况下测试似乎是按fp32跑了,我将类型改为fp16, 果然又快了一倍。

  • fp64: 11.5 ms
  • fp32: 5.76 ms
  • fp16: 2.89 ms

2.5 GPU(1060 ,1000+ cuda单元)计算 torch(1亿*1亿)

import torch
from torch.functional import F

e = torch.rand(1,100000000).cuda()
f = torch.rand(1,100000000).cuda()

%%timeit
#计算tensor在cuda上的计算速度
time_start=time.time()
# 我计算结果的精度调高,原例子是p=2
dist2 = F.pairwise_distance(e, f, p=5)
time_end=time.time()
print(time_end-time_start)
---
...
0.020745515823364258
0.020746707916259766
0.02073812484741211
20.7 ms ± 21.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

1060显卡的执行过程监督
在这里插入图片描述
从时间的倍数上看,3060Ti的计算性能是1060的3.55倍;价格的化3060Ti是¥2999,1060价格是¥1100左右,2.72倍。当然除了计算性能之外,3060Ti的显存更大,速度更快(8G GDDR6 vs 5G GDDR5)。另外,CUDA单元方面3060Ti是4680个CUDA单元,而1060是1280个CUDA单元,3060Ti是3.65倍;核心频率方面 ,3060Ti的GPU基础频率1410MHz,加速频率1665MHz;1060的核心频率1506MHz,Boost频率1709MHz,总体上差不多吧。

2.6 CPU 4650G(6核12线程)

import time
import numpy as np 
a = np.random.rand(1,100000000)
b = np.random.rand(1,100000000)


%%timeit
#计算numpy计算速度
time_start=time.time()
dist1 = np.linalg.norm(a - b)#numpy求欧氏距离
time_end=time.time()
print(time_end-time_start)
---
...
0.2752072811126709
0.27521586418151855
0.2744309902191162
275 ms ± 805 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

使用pytorch cpu版计算会比numpy稍微快几毫秒。

2.7 CPU 4790k(4核8线程)

import numpy as np 
a = np.random.rand(1,100000000)
b = np.random.rand(1,100000000)

%%timeit
#计算numpy计算速度
time_start=time.time()
dist1 = np.linalg.norm(a - b)#numpy求欧氏距离
time_end=time.time()
print(time_end-time_start)
---
0.22238779067993164
0.2396526336669922
0.2394123077392578
0.23943424224853516
0.23966670036315918
0.2403874397277832
0.2395646572113037
0.23941373825073242
240 ms ± 323 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

在使用pytorch cpu计算时,速度反而慢了一大截。可能和cpu、cuda版本这些都有关系

import torch
from torch.functional import F

e = torch.rand(1,100000000).cuda()
f = torch.rand(1,100000000).cuda()

%%timeit
#计算tensor在cuda上的计算速度
time_start=time.time()
# 我计算结果的精度调高,原例子是p=2
dist2 = F.pairwise_distance(e, f, p=5)
time_end=time.time()
print(time_end-time_start)
---
...
0.39830899238586426
0.4005136489868164
0.39644789695739746
397 ms ± 1.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

其他机型

NUC11

在这里插入图片描述
我买的是i7的cpu,4核8G,整体性能(1.7S)和3400G相仿(1.9S)。在能耗上肯定是i7胜出,并且还带了集显。

import numpy as np
a = np.random.rand(1,1000000000)
b = np.random.rand(1,1000000000)

%%timeit
dist1 = np.linalg.norm(a - b)
1.7 s ± 1.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

M1 芯片

订购了一个M1 Pro的满血版,还没有拿到。看到有些文章给了几款CPU的算力(估计是单精度浮点的),记录一下:

型号算力备注
M12.7T从M1 Pro 16GPU推断
M1 Pro 16GPU5.2T2048个EU,30w功率,接近3050Ti
M1 Max10.4 T

回头拿到机器在计算对比一下。

使用conda方式安装了jupyter之后,运行一亿欧几里得测试


import pandas as pd
import numpy as np
import time

a = np.random.rand(1,100000000)
b = np.random.rand(1,100000000)

%%timeit 
#计算numpy计算速度
time_start=time.time()
dist1 = np.linalg.norm(a - b)#numpy求欧氏距离
time_end=time.time()
print(time_end-time_start)

---
142 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

这个算力看起来类似3400G的算力,倒是比较符合我的预期。不过目前的方法似乎不太能够调出m1 pro的所有算力,看起来只是一个cpu核在计算(甚至gpu都不知道如何调用)。

看来如何调用出m1 pro的算力是个问题。

3 建模场景测试

这个待续 >>>











评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值