gpt4 book ai didi

c++ - 如何从 arrayfire 中显式获取线性索引?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:11:21 27 4
gpt4 key购买 nike

假设我有一个 stl::array<float, 24> foo这是 Column-Major 格式 arrayfire 数组的线性化 STL 吊坠,例如af::array bar = af::array(4,3,2, 1, f32); .所以我有一个 af::dim4对象 dims尺寸为 bar , 我最多有 4 af::seq -objects 并且我有线性化数组 foo .

如何显式获取 foo 的索引? (即 bar 的线性化版本)表示例如第二行和第三行,即 bar(af::seq(1,2), af::span, af::span, af::span) ?我在下面给出了一个小代码示例,它显示了我想要的。最后我也解释了为什么我想要这个。

af::dim4 bigDims = af::dim4(4,3,2);
stl::array<float, 24> foo; // Resides in RAM and is big
float* selBuffer_ptr; // Necessary for AF correct type autodetection
stl::vector<float> selBuffer;
// Load some data into foo
af::array selection; // Resides in VRAM and is small

af::seq selRows = af::seq(1,2);
af::seq selCols = af::seq(bigDims[1]); // Emulates af::span
af::seq selSlices = af::seq(bigDims[2]); // Emulates af::span
af::dim4 selDims = af::dim4(selRows.size, selCols.size, selSlices.size);

dim_t* linIndices;
// Magic functionality getting linear indices of the selection
// selRows x selCols x selSlices

// Assign all indexed elements to a consecutive memory region in selBuffer
// I know their positions within the full dataset, b/c I know the selection ranges.

selBuffer_ptr = static_cast<float> &(selBuffer[0]);

selection = af::array(selDims, selBuffer_ptr); // Copies just the selection to the device (e.g. GPU)

// Do sth. with selection and be happy
// I don't need to write back into the foo array.

Arrayfire 必须实现这样的逻辑才能访问元素,我发现了几个相关的类/函数,例如 af::index, af::seqToDims, af::gen_indexing, af::array::operator() - 但是我还想不出一个简单的出路。

我考虑过基本上重新实现 operator() ,这样它就可以类似地工作,但不需要引用数组对象。但如果 arrayfire-framework 中有简单的方法,这可能是浪费精力。

背景:我想这样做的原因是因为 arrayfire 不允许在与 GPU 后端链接时仅将数据存储在主内存(CPU 上下文)中。由于我有大量数据需要逐个处理,而 VRAM 非常有限,我想实例化 af::array - 来自始终驻留在主内存中的 STL 容器的临时对象。

当然我知道我可以编写一些索引魔术来解决我的问题,但我想使用非常复杂的 af::seq可能使索引逻辑的有效实现变得复杂的对象。

最佳答案

在 Gitter 上与 Pavan Yalamanchili 讨论后,我设法得到了一段我想分享的工作代码,以防其他人只需要将他的变量保存在 RAM 中并将其使用时复制部分保存到 VRAM,即Arrayfire 宇宙(如果与 GPU 或 Nvidia 上的 OpenCL 链接)。

这个解决方案还将帮助任何在他的项目的其他地方使用 AF 的人,以及希望有一种方便的方式来访问具有 (N<=4) 的大型线性化 N-dim 数组的人。

//  Compile as: g++ -lafopencl malloc2.cpp && ./a.out
#include <stdio.h>
#include <arrayfire.h>
#include <af/util.h>

#include <cstdlib>
#include <iostream>

#define M 3
#define N 12
#define O 2
#define SIZE M*N*O


int main() {
int _foo; // Dummy variable for pausing program
double* a = new double[SIZE]; // Allocate double array on CPU (Big Dataset!)
for(long i = 0; i < SIZE; i++) // Fill with entry numbers for easy debugging
a[i] = 1. * i + 1;

std::cin >> _foo; // Pause

std::cout << "Full array: ";
// Display full array, out of convenience from GPU
// Don't use this if "a" is really big, otherwise you'll still copy all the data to the VRAM.
af::array ar = af::array(M, N, O, a); // Copy a RAM -> VRAM


af_print(ar);

std::cin >> _foo; // Pause


// Select a subset of the full array in terms of af::seq
af::seq seq0 = af::seq(1,2,1); // Row 2-3
af::seq seq1 = af::seq(2,6,2); // Col 3:5:7
af::seq seq2 = af::seq(1,1,1); // Slice 2


// BEGIN -- Getting linear indices
af::array aidx0 = af::array(seq0);
af::array aidx1 = af::array(seq1).T() * M;
af::array aidx2 = af::reorder(af::array(seq2), 1, 2, 0) * M * N;

af::gforSet(true);
af::array aglobal_idx = aidx0 + aidx1 + aidx2;
af::gforSet(false);

aglobal_idx = af::flat(aglobal_idx).as(u64);
// END -- Getting linear indices

// Copy index list VRAM -> RAM (for easier/faster access)
uintl* global_idx = new uintl[aglobal_idx.dims(0)];
aglobal_idx.host(global_idx);

// Copy all indices into a new RAM array
double* a_sub = new double[aglobal_idx.dims(0)];
for(long i = 0; i < aglobal_idx.dims(0); i++)
a_sub[i] = a[global_idx[i]];

// Generate the "subset" array on GPU & diplay nicely formatted
af::array ar_sub = af::array(seq0.size, seq1.size, seq2.size, a_sub);
std::cout << "Subset array: "; // living on seq0 x seq1 x seq2
af_print(ar_sub);

return 0;
}

/*
g++ -lafopencl malloc2.cpp && ./a.out

Full array: ar
[3 12 2 1]
1.0000 4.0000 7.0000 10.0000 13.0000 16.0000 19.0000 22.0000 25.0000 28.0000 31.0000 34.0000
2.0000 5.0000 8.0000 11.0000 14.0000 17.0000 20.0000 23.0000 26.0000 29.0000 32.0000 35.0000
3.0000 6.0000 9.0000 12.0000 15.0000 18.0000 21.0000 24.0000 27.0000 30.0000 33.0000 36.0000

37.0000 40.0000 43.0000 46.0000 49.0000 52.0000 55.0000 58.0000 61.0000 64.0000 67.0000 70.0000
38.0000 41.0000 44.0000 47.0000 50.0000 53.0000 56.0000 59.0000 62.0000 65.0000 68.0000 71.0000
39.0000 42.0000 45.0000 48.0000 51.0000 54.0000 57.0000 60.0000 63.0000 66.0000 69.0000 72.0000

ar_sub
[2 3 1 1]
44.0000 50.0000 56.0000
45.0000 51.0000 57.0000
*/

该解决方案使用了一些未记录的 AF 函数,并且由于在 global_idx 上运行的 for 循环而被认为速度较慢,但​​到目前为止,它确实是最好的解决方案,如果 on 想要在 CPU 上下文中独占保存数据并仅与用于处理的 AF 的 GPU 上下文。

如果有人知道加快此代码速度的方法,我仍然愿意征求建议。

关于c++ - 如何从 arrayfire 中显式获取线性索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40984387/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com