Уплотнение потока с помощью Thrust; лучшие практики и самый быстрый способ?

Я заинтересован в портировании некоторого существующего кода для использования тяги, чтобы посмотреть, смогу ли я относительно легко ускорить его на графическом процессоре.

Я хочу выполнить операцию сжатия потока, при которой будут храниться только ненулевые элементы. У меня это в основном работает, согласно приведенному ниже примеру кода. Часть, которую я не знаю, как решить, связана со всем дополнительным пространством заполнения, которое находится в d_res и, следовательно, в h_res после того, как произойдет уплотнение.

В примере просто используется последовательность 0-99 со всеми четными элементами, установленными на ноль. Это всего лишь пример, и настоящей проблемой будет общий разреженный массив.

Этот ответ здесь очень помог мне, хотя, когда дело доходит до считывания данных, размер просто известен как постоянный: Как быстро сжать разреженный массив с помощью CUDA C?

Я подозреваю, что могу обойти это, подсчитав количество 0 в d_src, а затем только выделяя d_res для этого размера или выполняя подсчет после сжатия и копируя только это количество элементов. Это действительно правильный способ сделать это?

Я чувствую, что для этого будет какое-то простое решение с помощью умного использования итераторов или какой-либо другой функции тяги.

#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>

//Predicate functor
struct is_not_zero
{
    __host__ __device__
        bool operator()(const int x)
    {
        return (x != 0);
    }
};

using namespace std;

int main(void)
{
    size_t N = 100;

    //Host Vector
    thrust::host_vector<int> h_src(N);

    //Fill with some zero and some nonzero data, as an example
    for (int i = 0; i < N; i++){
        if (i % 2 == 0){
            h_src[i] = 0;
        }
        else{
            h_src[i] = i;
        }
    }

    //Print out source data
    cout << "Source:" << endl;

    for (int i = 0; i < N; i++){
        cout << h_src[i] << " ";
    }
    cout << endl;

    //copies to device
    thrust::device_vector<int> d_src = h_src;

    //Result vector
    thrust::device_vector<int> d_res(d_src.size());

    //Copy non-zero elements from d_src to d_res
    thrust::copy_if(d_src.begin(), d_src.end(), d_res.begin(), is_not_zero());

    //Copy back to host
    thrust::host_vector<int> h_res(d_res.begin(), d_res.end());
    //thrust::host_vector<int> h_res = d_res; //Or just this?

    //Show results
    cout << "h_res size is " << h_res.size() << endl;
    cout << "Result after remove:" << endl;

    for (int i = 0; i < h_res.size(); i++){
        cout << h_res[i] << " ";
    }
    cout << endl;

    return 0;
}

Кроме того, я новичок в работе с тягой, поэтому, если приведенный выше код имеет какие-либо очевидные недостатки, противоречащие рекомендуемым практикам использования тяги, сообщите мне об этом.

Точно так же скорость всегда представляет интерес. Читая некоторые из различных руководств по тяге, кажется, что здесь небольшие изменения, и могут быть большие сбережения скорости или потери. Поэтому, пожалуйста, дайте мне знать, если есть умный способ ускорить это.


person Andrew P.    schedule 07.06.2015    source источник


Ответы (1)


Похоже, вы упустили из виду, что copy_if возвращает итератор, который указывает на конец скопированных данных из операции сжатия потока. Итак, все, что требуется, это:

//copies to device
thrust::device_vector<int> d_src = h_src;

//Result vector
thrust::device_vector<int> d_res(d_src.size());

//Copy non-zero elements from d_src to d_res
auto result_end = thrust::copy_if(d_src.begin(), d_src.end(), d_res.begin(), is_not_zero());

//Copy back to host
thrust::host_vector<int> h_res(d_res.begin(), result_end);

Делая это, размеры h_res содержат только ненулевые значения и копируют только ненулевые значения из выходных данных сжатия потока. Никаких дополнительных вычислений не требуется.

person Community    schedule 07.06.2015
comment
Это именно то, что я искал, спасибо. Похоже, что «удалить» имеет аналогичный результат, поэтому теперь я также могу сравнить время этого подхода «удалить-затем-сортировать» с обратным подходом «сортировать-затем-удалить». - person Andrew P.; 08.06.2015