性能

性能篇
先使用nvidia-smi -l 1命令查看GPU使用率,如果GPU使用率为0优先检查代码是否调用了GPU进行计算。如果GPU使用率已经为90%+,则可以考虑换多卡并行或更高算力的GPU。
发现训练速度明显很慢时,可以先用以下代码进行压测排除硬件问题,观察GPU的使用率:
import torch m = k = n = 8192 a = torch.zeros(m, k, dtype=torch.float32).cuda("cuda:0") b = torch.zeros(k, n, dtype=torch.float32).cuda("cuda:0") for _ in range(100): y = torch.matmul(a, b) torch.cuda.synchronize("cuda:0")
瓶颈分析
首先确认您正在训练的模型具备什么样的特点,在性能上可以分为以下几种情况:
  1. 小模型、数据预处理简单。比如用LeNet训练MNIST,这种情况优化的余地小,因为模型本身对算力的需求小,适合用一般的GPU来训练即可,用越好的GPU使用率会越低。这种场景GPU的使用率特点是保持在一个较低的水平,但是波动小。
  2. 小模型、数据预处理较复杂。比如用ResNet18层网络跑ImageNet分类,这种情况CPU预处理会占用更长周期,而GPU的计算非常快占用时长短,因此适合选择更好的CPU和一般的GPU。这种场景GPU的使用率特点是波动大,峰值比较高,然后大部分时间都很低。
  3. 大模型、数据预处理简单。这种情况一般GPU都会利用很高且波动小,但是对磁盘的要求也很高,如果利用率低那么请参考下述的方法压榨性能。
  4. 大模型,数据预处理复杂。这种情况对CPU和GPU的要求都很高,都可能成为瓶颈,包括磁盘性能,需具体算法具体分析。
对于以上1和2两种情况,优化余地较小,更适合从选择主机下手配合代码优化,提高经济性。对于3和4如果发现GPU利用率较低时可以按下述方法排查瓶颈,优化性能。
如果GPU始终没有利用率,请确认:3090、A4000等安培架构的卡需要cuda11.x才能使用(最好cuda11.1及以上),请使用较高版本的框架。
Step.1 查看GPU的利用率
在终端中执行nvidia-smi -l 1命令



如果GPU占用率为0说明代码可能没有使用GPU,需检查代码。
如果GPU占用率忽高忽低、占用率峰值在50%以下,那么可能是数据预处理跟不上GPU的处理速度,请看下述步骤。

PyTorch线程数问题

    初步判断方法:如果您租用了多卡实例,并且每块GPU卡都运行不同的实验,那么可能存在一些问题。
    由于默认情况下,PyTorch会创建与核数相同的线程数来执行相关计算。如果在同一个实例中使用多张GPU卡,并让它们分别运行不同的实验,每个PyTorch进程都会默认创建与核数相同的线程数,导致系统大量时间用于线程调度而非计算,从而降低计算速度和CPU/GPU利用率。为了解决这个问题,可以使用代码torch.set_num_threads(N)设置单个进程所开启的线程数。

    更多经验:

    如果您在使用单机多卡并行,并且使用了PyTorch框架,建议将torch.nn.DataParallel (DP)更换为torch.nn.DistributedDataParallel (DDP),这样可以提高性能和扩展性。官方文档指出:DistributedDataParallel提供了更好的性能和扩展性,适用于多GPU环境。
另外,如果您使用的是安培架构的NVIDIA GPU(如RTX 3090等),最新版本的PyTorch 1.9和1.10相较于1.7会有较大的性能提升,而1.7和1.8的性能则相对较差。因此,建议您升级到PyTorch 1.10版本(可以在关机后在更多操作中更换PyTorch 1.10的镜像)。
最后,对于非常消耗资源的算法,最好在多个实验同时调整参数时,选择在不同的主机上启动多个实例,每个实例中运行一个实验,而不是在同一主机上启动多个实例或在同一实例中使用多张不同GPU卡来运行不同的实验。
栏目
问题反馈