GTX 1660 Ti下PyTorch nn.Conv2d半精度fp16运算比fp32慢问题问询
问题原因分析
- 硬件限制:GTX 1660 Ti属于图灵架构的甜点级显卡,砍掉了Tensor Core硬件单元,而FP16卷积的加速核心依赖Tensor Core实现,没有Tensor Core的情况下FP16运算没有原生算力加成,反而会额外产生精度转换、算子适配的开销,通道数较多的场景下性能反而不如FP32。你测试的第一组in=1、out=64的场景FP16更快,是因为单输入通道下FP16的访存开销比FP32低一半,访存收益覆盖了运算开销,通道数上去后计算占比提升,劣势就显现了。
- 测速代码不规范:你现有测试中每次卷积后都调用
out.cpu()把结果拷回CPU,这个跨设备同步操作会把数据传输开销算进卷积耗时,无法准确反映GPU端的实际运算速度;同时没有做CUDA预热,PyTorch第一次调用CUDA算子会有初始化开销,也会干扰测速结果。
解决方案
1. 先优化测速逻辑确认性能差异
先使用规范的GPU测速代码复现结果,避免操作引入的误差:
import torch import torch.nn as nn import time # 开启cudnn benchmark 自动选最优卷积算法 torch.backends.cudnn.benchmark = True ch_in = 64 ch_out = 128 device = torch.device("cuda:0") # 初始化输入和模型 inputfp16 = torch.randn(1, ch_in, 64, 64, dtype=torch.float16, device=device) inputfp32 = torch.randn(1, ch_in, 64, 64, dtype=torch.float32, device=device) conv2d_16 = nn.Conv2d(ch_in, ch_out, 3, 1, 1).eval().half().to(device) conv2d_32 = nn.Conv2d(ch_in, ch_out, 3, 1, 1).eval().to(device) # 预热:跑10次跳过初始化开销 for _ in range(10): _ = conv2d_16(inputfp16) _ = conv2d_32(inputfp32) torch.cuda.synchronize() # 测试FP16 start = time.time() for _ in range(1000): out = conv2d_16(inputfp16) torch.cuda.synchronize() print(f"FP16耗时: {(time.time()-start)/1000 * 1000:.3f} ms/it, 速度: {1000/(time.time()-start):.2f} it/s") # 测试FP32 start = time.time() for _ in range(1000): out = conv2d_32(inputfp32) torch.cuda.synchronize() print(f"FP32耗时: {(time.time()-start)/1000 * 1000:.3f} ms/it, 速度: {1000/(time.time()-start):.2f} it/s")
2. 软件层面优化
- 保留
torch.backends.cudnn.benchmark = True配置,让cuDNN自动匹配当前硬件下最优的卷积实现算法,部分场景可以降低FP16的运算开销。 - 升级PyTorch到2.0及以上版本,新版本对无Tensor Core设备的FP16算子做了优化,可降低额外开销。
3. 硬件层面优化
如果需要FP16的明显加速收益,更换带有Tensor Core的显卡,包括20系及之后的消费级显卡(RTX 20xx、RTX 30xx、RTX 40xx系列),或者NVIDIA的服务器级计算卡。
内容的提问来源于stack exchange,提问作者user15450029
相关产品推荐
相关产品推荐

