2016-12-05 9 views
2

Column-Major 형식 배열 파이어 배열에 선형화 된 STL 펜던트 인 stl::array<float, 24> foo이 있다고 가정합니다. af::array bar = af::array(4,3,2, 1, f32);. 그래서 나는 객체 dims의 크기가 bar이고, 최대 4 개는 af::seq이고 객체는 선형 배열 foo입니다.arrayfire에서 선형 인덱스를 명시 적으로 가져 오는 방법은 무엇입니까?

foo (예 : bar의 선형화 된 버전)의 색인을 명시 적으로 가져 오는 것이 가능한가요? 2.nd 및 3.rd 행 (예 : 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는 GPU 백엔드에 링크되는 동안 만 메인 메모리 (CPU 컨텍스트)에 데이터를 저장하는 것을 허용하지 않기 때문에 내가 그렇게 할 이유입니다. 필자는 많은 양의 데이터를 처리해야하고 VRAM은 매우 제한적이므로 항상 주 메모리에있는 stl-container에서 ad-hoc을 af::array 인스턴스로 인스턴스화하고 싶습니다.

물론 나는 내 문제를 해결하기 위해 일부 색인 마법을 프로그램 할 수 있지만 꽤 복잡한 색인 구조를 효율적으로 구현할 수있는 매우 복잡한 af::seq 개체를 사용하고 싶습니다.

+0

선형 인덱스가이 경우에 도움이되는 이유는 무엇입니까? 선형 인덱스를 얻은 후에해야 할 일에 대해 몇 가지 코드를 표시하면 좋을 것입니다. –

답변

1

Gitter의 Pavan Yalamanchili와의 토론 끝에 다른 사람들이 자신의 변수를 VRAM에만 복사하여 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 통해 실행에 가정으로 느리지 만, 지금까지의 정말 최고의 하나가 할 수있는 CPU의 전용 컨텍스트 및 공유에 데이터를 저장하고 싶은에있는 경우 처리를 위해 AF의 GPU 컨텍스트가있는 부분 만

누구든지이 코드를 빠르게 할 수있는 방법을 알고 있다면 제안을받을 수 있습니다.