为什么在二维卷积操作中,将宽度(W)维度放在高度(H)之前会破坏空间局部性原则,并影响缓存性能

空间局部性原则

空间局部性指的是程序倾向于访问与最近访问过的内存位置接近的内存位置。对于深度学习模型中的张量数据,这意味着当处理图像或特征图时,如果能够连续地访问相邻像素的数据,那么可以最大化利用CPU/GPU缓存,因为缓存通常加载的是连续的一块内存。

二维卷积操作

在二维卷积中,过滤器(kernel)会在输入特征图上滑动,依次计算每个输出像素值。这个过程涉及到沿着高度(H)和宽度(W)两个方向移动过滤器。具体来说:

  • 遍历顺序:通常情况下,遍历是从左到右(W方向),从上到下(H方向)。也就是说,先完成一行内所有元素的计算,然后移动到下一行。

  • 内存布局影响:如果我们使用 (N, H, W, C) 的格式,那么在遍历同一行中的相邻元素时,内存地址是连续的。例如,在读取一个3x3过滤器窗口内的数据时,假设我们正在处理第一行的前三个元素 [0,0], [0,1], [0,2],这些元素在内存中是连续存储的,这使得缓存能够高效地预取和加载这些数据,提高访问速度。

  • 如果选择 (N, W, H, C)

  • 破坏空间局部性:但是,如果我们将张量维度调整为 (N, W, H, C),即宽度(W)维度排在高度(H)之前,那么在遍历同一行中的相邻元素时,内存地址不再是连续的。比如,当我们尝试按照常规的从左到右、从上到下的顺序遍历时,实际上是在跳跃式地访问不同行的数据,而不是连续访问同一行的数据。这会导致每次访问新元素时都需要从主内存重新加载数据,无法有效利用缓存,从而降低了缓存命中率和整体性能。

示例

假设有一个简单的4x4特征图(忽略批次N和通道C),按 (N, H, W, C) 布局,它在内存中可能是这样的(简化表示):

复制代码
[H=0, W=0], [H=0, W=1], [H=0, W=2], [H=0, W=3],
[H=1, W=0], [H=1, W=1], [H=1, W=2], [H=1, W=3],
[H=2, W=0], [H=2, W=1], [H=2, W=2], [H=2, W=3],
[H=3, W=0], [H=3, W=1], [H=3, W=2], [H=3, W=3]

而按 (N, W, H, C) 布局,则变成:

复制代码
[W=0, H=0], [W=1, H=0], [W=2, H=0], [W=3, H=0],
[W=0, H=1], [W=1, H=1], [W=2, H=1], [W=3, H=1],
[W=0, H=2], [W=1, H=2], [W=2, H=2], [W=3, H=2],
[W=0, H=3], [W=1, H=3], [W=2, H=3], [W=3, H=3]

在这个新的布局中,当你想要按行遍历时,你实际上是跨着不同的行来访问数据,这导致了较差的空间局部性和缓存性能。

因此,为了保持良好的空间局部性和高效的缓存利用,在进行二维卷积操作时,通常推荐使用 (N, H, W, C) 的内存布局。

相关推荐
苏渡苇1 小时前
Redis 版本演进、新特性与协议那些事儿
数据库·redis·缓存·开源协议·redis版本·redis新特性
鬼蛟1 小时前
Nacos
数据库·redis·缓存
码农阿豪1 小时前
一次 AI 调用 15 万 Token 只花了 $0.058?彻底搞懂 Token、缓存读、补全计费机制!(附完整架构图)
人工智能·spring·缓存
Ai搬运工11 小时前
【保姆级教程】B站缓存视频如何转为正常MP4格式?
缓存·音视频·bilibili
敲上瘾1 小时前
高并发内存池(三):PageCache(页缓存)的实现
linux·c++·缓存·高并发内存池·池化技术
快点好好学习吧1 小时前
CPU 从 L1/L2 缓存读取 MySQL 代码指令的庖丁解牛
android·mysql·缓存
awljwlj1 小时前
黑马点评复习—缓存相关【包含可能的问题和基础知识复习】
java·后端·spring·缓存
大飞哥~BigFei2 小时前
缓存一致性终极解决方案之Facebook租约机制的开源实现集成改造
java·缓存·开源
LL_break2 小时前
从零上手Redis:string编码原理、常用命令与设计逻辑详解
java·数据库·redis·缓存·java-ee
墨^O^2 小时前
C++ Memory Order 完全指南:从 relaxed 到 seq_cst,深入理解无锁编程与 happens-before
linux·开发语言·c++·笔记·学习·算法·缓存