2016-12-05 51 views
2

假設我有一個stl::array<float, 24> foo這是一個線性化的STL掛件到一個列 - 專業格式陣列陣列,例如, af::array bar = af::array(4,3,2, 1, f32);。所以我有一個af::dim4對象dims尺寸bar,我有多達4 af::seq-對象,我有線性陣列foo如何從arrayfire中顯式獲取線性索引?

怎樣才能明確得到foo(即bar的線性化版本)代表例如第2.nd和第3.r行,即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框架中有一個簡單的方法,這可能是浪費精力。

背景: 我想這樣做的原因是因爲arrayfire不允許只存儲在主內存(CPU上下文)的數據,同時針對GPU後端被鏈接。由於我有大量的數據需要逐塊處理,並且VRAM非常有限,所以我想從始終駐留在主內存中的stl容器實例化af::array -object ad-hoc。

當然我知道我可以編寫一些索引魔術來解決我的問題,但我想使用相當複雜的對象,這可以使索引邏輯的高效實現變得複雜。

+0

爲什麼在這種情況下線性指數會有所幫助?如果您可以在獲得線性指數後顯示一些關於您打算做什麼的代碼。 –

回答

1

在與Gitter的Pavan Yalamanchili討論之後,我設法得到了一段我想分享的代碼片段,以防其他人需要將其變量僅保存在RAM中,並將其複製到VRAM中,即Arrayfire宇宙(如果與GPU或Nvidia上的OpenCL鏈接)。

這個解決方案也可以幫助任何在他的項目中使用AF的人,並且想要有一個方便的方式訪問一個大的線性化N-dim陣列(N < = 4)。

// 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循環運行,但到目前爲止,其真正的最好的人可以做,如果在要在專門的CPU上下文和共享保存數據只有具有AF處理的GPU上下文的部分。

如果有人知道加快代碼的速度,我仍然樂於提供建議。