【问题标题】:How to translate computation in index notation into sequence of SIMD ops in general case?在一般情况下,如何将索引符号中的计算转换为 SIMD 操作序列?
【发布时间】:2023-03-31 20:55:01
【问题描述】:

UPD:原始形式的问题表述不当,因为我严重混淆了术语(SIMD 与矢量化计算),并给出了过于宽泛的示例,无法准确说明问题所在; 我投票关闭它“不清楚你在问什么”,只要它出现,我会在上面链接一个更好的问题


在数学中,人们通常会使用索引符号来描述 n 维张量计算,如下所示:

A[i,j,k] = B[k,j] + C[d[k],i,B[k,j]] + d[k]*f[j] // for 0<i<N, 0<j<M, 0<k<K

但是如果我们想使用任何 SIMD 库来有效地并行化该计算(并利用线性代数魔法),我们将不得不使用来自BLASnumpytensorflow、@ 的原语来表达它987654325@、... 这通常很棘手。

A_ijk*B_kj 这样的[爱因斯坦符号][1] 表达式通常通过[np.einsum][2] 求解(我猜是使用tensordotsumtranspose?)。求和和其他元素操作也可以,但是“智能”索引非常棘手(特别是,如果索引在表达式中出现的次数超过一次)。

我想知道是否有任何与语言无关的库以某种形式(比如说,上面的形式)将表达式转换为可以使用现有线性代数库有效执行的Intermediate Representation

有些库试图并行化循环计算(用户 API 通常看起来像 C++ 中的 #pragma 或 python 中的 @numba.jit),但我问的是稍微不同的事情:将上面形式的 abritary 表达式转换为有限SIMD 命令序列,如 elementwise-ops、matvecs、tensordots 等。

如果还没有与语言无关的解决方案,我个人对 numpy 计算很感兴趣 :)

【问题讨论】:

  • 我问这个问题有什么问题?答案“不,这是不可能的,因为 X”也是一个可以接受的答案 :) 如果存在那种库\算法(而且我并不孤单),我会非常高兴。如果问题形式本身很难看,我会重新提出问题。
  • 你能用 C 或某种伪代码写一个循环,清楚地表达你想要向量化的计算类型吗?我不确定我是否理解您的 {} 符号。但是,如果它类似于矩阵乘法,是的,转置其中一个输入通常非常有用,因此您需要连续结果的数据连续存储在两个源中。
  • @PeterCordes 感谢您的评论!我同意,我已经更新了问题,现在符号看起来不那么模棱两可了吗?
  • 另外,为什么i没有出现在右侧?相同的数据是否重复N 次??
  • (我的 cmets 正在成为答案,所以我就这样发布了)

标签: numpy math tensorflow linear-algebra simd


【解决方案1】:

关于代码的更多问题:

  • 我看到B[k,j] 被用作索引和值。一切都是整数吗?如果不是,哪些部分是 FP,转换发生在哪里?
  • 为什么i 不出现在右手边?相同的数据是否重复了 N 次?

哦,哎呀,所以你有一个聚集操作,索引来自d[k]B[k,j]。只有少数 SIMD 指令集支持此功能(例如 AVX2)。

我主要使用 Intel's x86 intrinsics 手动对 C 中的内容进行矢量化(或自动矢量化并检查编译器的 asm 输出以确保它没有出错),所以如果有任何与平台无关的表达方式,请 IDK那个操作。

我不认为许多跨平台 SIMD 语言会提供集合或任何构建在集合之上的东西。我还没有使用过 numpy。 我不希望您找到包含聚集的 BLAS、LAPACK 或其他库函数,除非您去寻找这个确切问题的实现。

通过高效的聚集(例如 Intel Skylake 或 Xeon Phi),如果您在循环中使用 SIMD 在j 上进行矢量化处理,它可能会正常,因此您可以同时从B[]f[] 加载整个矢量, 并将其与将 d[k] 广播到每个位置的向量一起使用。您可能想要存储转置的结果矩阵,例如A[i][k][j],因此最终存储不必是分散的。您绝对需要避免在最内层循环中循环 k,因为这会使来自 B[] 的负载不连续,并且您有 d[k] 而不是 f[j] 在内部循环内变化。


我对 GPGPU 所做的工作不多,但他们使用 SIMD 的方式不同。与 CPU 使用的短向量不同,它们实际上将许多标量处理器组合在一起。 OpenCL 或 CUDA 或任何其他热门的新 GPGPU 技术可能会更有效地处理您的集合。


SIMD 命令,如 elementwise-ops、matvecs、tensordots 等。

当我想到“SIMD 命令”时,我会想到 汇编指令(或 ARM NEON 或其他),或者至少是编译为单个指令的 C/C++ 内在函数。 :P

矩阵向量乘积不是单一的“指令”。如果您使用该术语,则处理缓冲区的每个函数都是“SIMD 指令”。

您问题的最后一部分似乎是要求一个独立于编程语言的 numpy 版本,用于将高性能库函数粘合在一起。或者您是否认为可能会有一些东西可以对此类操作进行相互优化,因此您可以编写一些可以编译为矢量化循环的东西,该循环执行诸如多次使用每个输入而无需在单独的库调用中重新加载它之类的事情?

IDK,如果有类似的东西,除了普通的 C 编译器对数组循环的自动向量化。

【讨论】:

  • 是的,我们假设它们都是整数;这不是一个实际问题,我只是想说明表达式包括聚集、乘法和求和;实际上我只对gather 部分感兴趣; SIMD 我的意思是所有在大量数据上执行“类似操作”的操作(即元素操作、向量操作、聚集等),这可能是我这边的术语混淆 - 是吗?跨度>
  • 您的回答确实非常详细和有帮助,它回答了我提出的问题(问题是在当前的表述中,它问的不是我最初想知道的:))-我不想要要更改问题以使您的答案过时(因为您的答案很棒!),您不介意我现在接受它并在出现时链接一个新的更好的问题吗?
  • 我的问题基本上是“给定一个复杂的收集语句,如result[i, j, k] = A[B[i, j], k, c[i]] - 如何自动将其转换为智能索引表达式(用于 numpy)或一系列转置、重塑和一维聚集(对于张量流)”,因为每次我需要编写这样的代码时,我都会花一些时间重新发明如何重塑\转置数据以获得所需的结果;我通常最终会成功,但我希望我能写像result[i, j, k]=..(上图)这样的东西
  • @BenUsman:是的,这个问题有两个部分。一个关于那个特定的表达,一个关于这种事情的 numpy 符号。由于我不使用python,所以我无法对另一部分说太多。一个引用这个的新问题听起来像是最好的计划。如果您认为这对未来的读者/搜索者来说是值得的,甚至可以编辑这个问题以匹配我回答的部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 2018-07-26
  • 2014-05-05
  • 2015-02-28
相关资源
最近更新 更多