从GPU的内存访问视角对比NHWC和NCHW

本文涉及的产品
大数据开发治理平台 DataWorks,不限时长
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
简介: NHWC和NCHW是卷积神经网络(cnn)中广泛使用的数据格式。它们决定了多维数据,如图像、点云或特征图如何存储在内存中。
  • NHWC(样本数,高度,宽度,通道):这种格式存储数据通道在最后,是TensorFlow的默认格式。
  • NCHW(样本数,通道,高度,宽度):通道位于高度和宽度尺寸之前,经常与PyTorch一起使用。

NHWC和NCHW之间的选择会影响内存访问、计算效率吗?本文将从模型性能和硬件利用率来尝试说明这个问题。

卷积作为GEMM

GEneral Matrix to Matrix Multiplication (通用矩阵的矩阵乘法)

卷积可以使用基于变换的方法来实现,如快速傅立叶变换,它将卷积转换为频域的元素乘法,或者使用无变换的方法,如矩阵乘法,其中输入和滤波器(卷积核)被平面化并使用矩阵操作组合以计算输出特征映射。

但是:fft是内存密集型的,因为它们需要额外的内存来存储转换后的矩阵。并且fft的计算成本很高,特别是在时域和频域之间来回转换数据时,涉及操作开销。

而卷积运算的一般矩阵乘法是这样的。每个接受域按列堆叠,得到特征映射变换矩阵。同时还将滤波器矩阵逐行平摊和叠加,形成滤波器变换矩阵。滤波变换和特征映射变换矩阵经过矩阵乘法运算,形成扁平化的输出矩阵。这里的变换矩阵是一个中间矩阵,只是数值重排,与频域变换没有关系。

N -特征图的批量大小,C -输入通道,h -输入高度,W -输入宽度,

k -输出通道,r -滤波器高度,s -滤波器宽度,p -输出高度,q -输出宽度

特征映射变换矩阵和滤波变换矩阵被认为是中间矩阵,其维数大于特征映射本身。feature map的尺寸= C × H × W, (3x3x3) feature map transform的尺寸= CRS × NPQ (12x4)

GEMM的GPU实现:

GPU为了避免内存预感使用了隐式GEMM。在隐式GEMM中,不是形成Transform矩阵,而是对每个列和行进行动态索引。最终的输出直接存储在输出张量对应的索引中。

由SMs(流多处理器)组成的GPU主要用于执行并行计算。在上面的隐式GEMM中,每个矩阵乘法可以分成更小的矩阵乘法或块。然后每个块都由SMs同时处理,以加快过程。

有了上面的计算过程,还需要存储张量,下面我们看看张量是如何在GPU中存储的。

张量通常以跨行格式存储在GPU中,其中元素在内存布局中以非连续的方式存储。这种跨行存储方法提供了以各种模式(如NCHW或NHWC格式)排列张量的灵活性,优化了内存访问和计算效率。

下图中所示的给定张量,我们可以用NCHW和NHWC的行主格式表示它们,行主存储通过顺序存储每一行来安排内存中的张量元素。

NCHW

这里W是最动态的维度。同一通道中的元素存储在一起,然后是下一个通道中的元素。

NHWC

这里C是动态的维度。所有通道中来自相同空间位置的元素依次存储,然后是来自下一个空间位置的元素,从而优化对每个通道内空间数据的访问。

GPU上的内存吞吐量

GPU是高度并行的处理器,当数据访问以合并方式完成时,它们工作得最好,这意味着它们喜欢以连续的、有组织的方式读取数据。当每个线程在二级缓存中查找数据时,如果是缓存命中(请求内存的内容在缓存中可用),则内存访问速度很快。如果是缓存丢失(缓存命中的否定),那么GPU接近DRAM来获取请求的内存地址的内容,这是一个耗时的操作。

当GPU需要访问存储在内存中的数据时,它会在“事务”中这样做。根据GPU配置,每个事务访问32/128字节的信息。访问的信息保留在缓存中。当另一个GPU线程请求内存访问时,它首先检查缓存。如果数据在缓存中不可用,那么请求将被转发到DRAM。

GPU工作原理十分复杂,我们不想也没有时间在这里详细解释,所以将其简单概括为:

合并内存事务发生在GPU访问连续块中的内存时。如果GPU需要读取连续存储在内存中的32字节数据,它将执行单个合并内存事务来一次检索所有32字节。非合并内存事务发生在GPU需要访问未连续存储在内存中的数据时。在这种情况下,GPU将需要执行多个事务来检索所有必要的数据

在GEMM的情况下,无论滤波器的高度和宽度如何,我们都可以确保读取给定空间位置的所有通道信息。例如,如果我们的输入特征是128 x 128 x 32。无论使用1x1还是3x3内核,我们都可以读取位置(1,1)的所有通道。

如果使用NCHW,它将属于单个通道的所有元素存储在一起,我们将不得不跨到位置a[0], a[16384], a[32,768]……直到位置a[16384x31]进行1x1卷积。这些位置不是连续的,并且肯定会导致缓存丢失,从而导致内存读取期间的额外开销。在每个事务期间读取的其余数据也不被使用,也称为非合并内存事务。

当使用NHWC格式表示张量时,访问位置是a[0],a[1]…,a[127],它们是连续的,并且肯定是缓存命中。第一次访问a[0]会导致缓存丢失和从DRAM获取32/128字节数据的事务。当访问a[1]时,这将是保存事务的缓存命中。即使在一定数量的位置之后缓存丢失导致来自DRAM的事务,事务本身将携带连续内存位置的连续数据,可以在访问进一步位置时缓存命中,称为合并内存事务。

NHWC减少了张核gpu的内存访问瓶颈,从而优化了性能,与NCHW相比,这似乎是一个更好的选择

以下是NVIDIA A100-SXM4-80GB, CUDA 11.2, cuDNN 8.1下NCHW和NHCW的TFLOPS的性能条款。我们看到NHWC在两种设置下的TFLOPS方面表现更好。为了简单起见,在这里没有进入NC/xHWx布局,这是NHWC的一个变体,为NVIDIA张量核心操作准备。

那么为什么Pytorch还要使用NCHW呢?

官方论坛的一个帖子可以作为参考:

https://discuss.pytorch.org/t/why-does-pytorch-prefer-using-nchw/83637

另外就是TensorFlow 的官网也说过这么一段话,也可以作为参考

Most TensorFlow operations used by a CNN support both NHWC and NCHW data format. On GPU, NCHW is faster. But on CPU, NHWC is sometimes faster.

参考资料

https://avoid.overfit.cn/post/0b8715aa855045c693be2e9b20eb93ba

作者:Deepika

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
2月前
|
机器学习/深度学习 存储 PyTorch
【AMP实操】解放你的GPU运行内存!在pytorch中使用自动混合精度训练
【AMP实操】解放你的GPU运行内存!在pytorch中使用自动混合精度训练
137 0
|
2月前
|
机器学习/深度学习 并行计算 算法
龚大视频学习笔记:上帝视角看GPU(2)-逻辑上的模块划分
龚大视频学习笔记:上帝视角看GPU(2)-逻辑上的模块划分
76 0
|
24天前
|
存储 缓存 Java
Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问
【6月更文挑战第22天】Java中的缓冲流提升I/O性能,通过内存缓冲区减少对硬件访问。`BufferedInputStream`和`BufferedOutputStream`用于字节流,缓存数据批量读写。`BufferedReader`和`BufferedWriter`处理字符流,支持按行操作。使用后务必关闭流。
26 3
|
2月前
|
监控 Java 网络性能优化
容器内存可观测性新视角:WorkingSet 与 PageCache 监控
本文介绍了 Kubernetes 中的容器工作内存(WorkingSet)概念,它用于表示容器内存的实时使用量,尤其是活跃内存。
56142 13
容器内存可观测性新视角:WorkingSet 与 PageCache 监控
|
2月前
|
安全 Java C语言
【Python 的内存管理机制专栏】Python 内存管理机制与底层实现:C 语言视角的剖析
【5月更文挑战第18天】Python的内存管理涉及对象分配、引用计数和垃圾回收。对象分配类似C的动态内存,但更自动化。引用计数跟踪对象引用,计数为0时回收。垃圾回收机制自动清理不再使用的对象,避免内存泄漏。这种高效自动化管理让开发者能专注于业务逻辑,而底层实现的理解有助于解决特殊问题和优化性能。
【Python 的内存管理机制专栏】Python 内存管理机制与底层实现:C 语言视角的剖析
|
1月前
|
人工智能 数据管理 vr&ar
终极 GPU 互联技术探索:消失的内存墙
【6月更文挑战第9天】GPU在各领域广泛应用,但内存墙问题限制了性能提升。为解决此问题,研究人员发展GPU互联技术,如NVIDIA的NVLink,实现高速通信,提高系统性能。此外,先进内存技术(如HBM)和智能数据管理策略也在助力突破内存墙。未来,随着GPU互联技术的不断创新,内存墙将被逐步消除,为AI、虚拟现实等领域带来更强计算能力。
|
2月前
|
存储
8086 汇编笔记(二):寄存器(内存访问)
8086 汇编笔记(二):寄存器(内存访问)
|
27天前
|
存储 安全 程序员
c++理论篇——初窥多线程(一) 计算机内存视角下的多线程编程
c++理论篇——初窥多线程(一) 计算机内存视角下的多线程编程
|
2月前
|
存储 监控 异构计算
【Python】GPU内存监控脚本
【Python】GPU内存监控脚本
|
2月前
|
缓存 算法 编译器
C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。
C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。
128 0

热门文章

最新文章