为什么在二维卷积操作中,将宽度(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) 的内存布局。

相关推荐
流星白龙13 小时前
【Redis】4.基本全局命令
数据库·redis·缓存
流星白龙16 小时前
【Redis】3.Redis安装与命令行客户端
数据库·redis·缓存
我不想名字重复1 天前
redis缓存和数据库数据保持一致
数据库·redis·缓存
时空无限1 天前
vllm 大模型启动缓存相关环境变量 export
linux·缓存·vllm
流星白龙1 天前
【Redis】6.计数其他命令
数据库·redis·缓存
正儿八经的少年1 天前
redis 的大 key 和热 key 详解
数据库·redis·缓存
X-⃢_⃢-X1 天前
十、Redis之布隆过滤器
数据库·redis·缓存
Database_Cool_1 天前
阿里云 Tair(企业级内存数据库)vs 腾讯云 Redis 云缓存深度对比:性能/数据结构/成本全维度 Benchmark
数据库·阿里云·缓存
流星白龙1 天前
【Redis】1.Redis特性
数据库·redis·缓存
chexus1 天前
21. 深入 Nginx HTTP 缓存源码:CDN功能
nginx·http·缓存