2016-12-05 7 views
2

カラムメジャーフォーマットのアレイファイアアレイに対して線形化されたSTLペンダントであるstl::array<float, 24> fooがあるとします。 af::array bar = af::array(4,3,2, 1, f32);。だから私はオブジェクトdimsbarの寸法を持って、私は最大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からaf::array-adjectをインスタンス化したいと思います。

もちろん私は自分の問題を回避するためにいくつかのインデックスマジックをプログラムすることができますが、私はかなり複雑なインデックスのロジックを効率的に実装することができる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上で実行中のループのために起因すると思わ遅いですが、今のところその本当に最高の1は、排他的と共有CPUコンテキストでデータを保持したいのならば行うことができます処理のためにAFのGPUコンテキストを持つ部分のみ。

誰かがこのコードをスピードアップする方法を知っていたら、私はまだ提案を受けています。

関連する問題