简体   繁体   English

推力:reduce_by_key将zip_iterator(tuple)传递到自定义函子以按键检索平均值

[英]Thrust: reduce_by_key passing zip_iterator(tuple) into custom functor to retrieve average by key

What I'm trying to do is get an average of values by key via thrust::reduce_by_key . 我想做的是通过thrust::reduce_by_key通过键获取值的thrust::reduce_by_key I first sort_by_key and that works just fine to group by consecutive keys for reduce_by_key . 我首先进行sort_by_key ,然后按reduce_by_key的连续键进行reduce_by_key I used this to help get me this far. 我用来帮助我走得更远。 However, I am getting lots of errors that I cannot understand (this is also my first time using reduce_by_key) and I can't think of a better way to do this without using lots of temporary allocations to (1) get the sum of the values by key then the count by key and (2) divide the two for the average. 但是,我遇到了很多我无法理解的错误(这也是我第一次使用reduce_by_key),并且我想不出一种更好的方法来实现这一点,而无需使用大量临时分配给(1)来获得按键计算值,然后按键计数和(2)将两者相除得出平均值。

input keys:   1,   1,   1,  2,   3,   5,  5,  2
input values: 120, 477, 42, 106, 143, 53, 83, 24

expected output values: 213, 65, 143, 68

I have the following custom functor: 我有以下自定义函子:

struct GetAverage
{
    template<typename Tuple>
    __host__ __device__
    int operator()(const Tuple& t)
    {
        //SumByKey / CountByKey
        return thrust::get<0>(t) / thrust::get<1>(t);
    }
};

The functor is called from the below code, located in main() 仿函数是从位于main()的以下代码调用的

thrust::device_vector<unsigned int> tempKey(8);
thrust::device_vector<unsigned int> tempValue(8);

tempKey[0] = 1;
tempKey[1] = 1;
tempKey[2] = 1;
tempKey[3] = 2;
tempKey[4] = 3;
tempKey[5] = 5;
tempKey[6] = 5;
tempKey[7] = 2;

tempValue[0] = 120;
tempValue[1] = 477;
tempValue[2] = 42;
tempValue[3] = 106;
tempValue[4] = 143;
tempValue[5] = 53;
tempValue[6] = 83;
tempValue[7] = 24;

thrust::sort_by_key(tempKey.begin(), tempKey.end(), tempValue.begin());

thrust::equal_to<int> binary_pred;
thrust::reduce_by_key(
    tempKey.begin(),
    tempKey.end(),
    thrust::make_zip_iterator(
        thrust::make_tuple(
            tempValue.begin(),
            thrust::make_constant_iterator(1)
        )
    ), //values_first; Should go into GetAverage() custom functor as a zipped tuple <tempValue, 1>
    tempKey.begin(), //keys_output; Should be returning the unique keys
    tempValue.begin(), //values_output; Should be returning the average by key 
    binary_pred,
    GetAverage()
);

Example errors: 错误示例:
- no instance of function template "GetAverage::operator()" matches the argument list - no instance of function template "GetAverage::operator()" matches the argument list
- no operator "=" matches these operands - no operator "=" matches these operands
- no suitable conversion function from "InputValueType" to "TemporaryType" exists - no suitable conversion function from "InputValueType" to "TemporaryType" exists
- no suitable conversion function from "thrust::detail::tuple_of_iterator_references<thrust::device_reference<int>, int, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>" to "TemporaryType" exists - no suitable conversion function from "thrust::detail::tuple_of_iterator_references<thrust::device_reference<int>, int, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type, thrust::null_type>" to "TemporaryType" exists

Does anyone have any ideas on how to fix this? 有人对如何解决这个问题有任何想法吗? Or links? 还是链接? I read the documentation on everything in use here and was as careful in trying to understand it as possible, but with no resolution. 我阅读了此处使用的所有内容的文档,并尽力尝试尽可能地理解它,但没有解决方案。 Thanks! 谢谢!

UPDATE 更新
See Eric's answer. 请参阅Eric的答案。 In conjunction with what he said, this is the new source code. 结合他的说法,这是新的源代码。 Created an op to handle plus for Tuples. 创建了一个操作来处​​理元组的加号。 The only thing this code doesn't do is after the reduce_by_key call, a thrust::transform should be used on the results to get the average by dividing the sum by the count. 该代码唯一不做的事情是在reduce_by_key调用之后,应在结果上使用thrust::transform以将总和除以计数来获得平均值。

// --- Defining key tuple type
typedef thrust::tuple<int, int> Tuple;

/* PLUS OPERATOR BETWEEN TUPLES */
struct TuplePlus
{
    __host__ __device__
    Tuple operator ()(const Tuple& lhs, const Tuple& rhs)
    {
        return thrust::make_tuple(
            thrust::get<0>(lhs) + thrust::get<0>(rhs),
            thrust::get<1>(lhs) + thrust::get<1>(rhs)
        );
    }
};

Inside main() I have the following now. main()内部,现在有以下内容。

thrust::equal_to<int> binary_pred;
thrust::reduce_by_key(
    tempKey.begin(),
    tempKey.end(),
    thrust::make_zip_iterator(
        thrust::make_tuple(
            tempValue.begin(),
            thrust::make_constant_iterator(1)
        )
    ), //values_first; goes in as a zipped up tuple <value, 1>
    tempKey.begin(), //keys_output
    thrust::make_zip_iterator(
        thrust::make_tuple(
            tempValue.begin(),
            tempCount.begin()
        )
    ), //values_output; ZipIterator<Sum, Count> by key
    binary_pred,
    TuplePlus()
);

There are two issues. 有两个问题。

The result of a tuple sequence reduction should be a tuple but not int . 元组序列减少的结果应该是元组而不是int According to the document 根据文件

https://thrust.github.io/doc/group__reductions.html#ga633d78d4cb2650624ec354c9abd0c97f https://thrust.github.io/doc/group__reductions.html#ga633d78d4cb2650624ec354c9abd0c97f

The last parameter binary_op should be of the type 最后一个参数binary_op应该是类型

BinaryFunction is a model of Binary Function and BinaryFunction's result_type is convertible to OutputIterator2's value_type. BinaryFunction是Binary Function的模型,BinaryFunction的result_type可转换为OutputIterator2的value_type。

It means your reduction operation should be something like 这意味着您的还原操作应类似于

struct GetSum
{
  template<typename Tuple>
  __host__ __device__
  Tuple operator()(const Tuple& a, construction Tuple& b)
  {
    ...
  }
}

On the other hand, at the reduction stage, you can only calculate the sum but not the average efficiently. 另一方面,在缩减阶段,您只能有效地计算总和,而不能有效地计算平均值。 It means your values_output should also be a zip iterator with the same type as values_first . 这意味着您的values_output也应该是与values_first类型相同的zip迭代器。

OutputIterator2 is a model of Output Iterator and InputIterator2's value_type is convertible to OutputIterator2's value_type. OutputIterator2是Output Iterator的模型,InputIterator2的value_type可转换为OutputIterator2的value_type。

So you need two result arrays, one for the sum by key and one for the count by key. 因此,您需要两个结果数组,一个用于键的总和,另一个用于键的计数。 They should be zipped together and used as values_output . 应该将它们压缩在一起并用作values_output

Then you need another thrust::transform to calculate the final result - average by key. 然后,您需要另一个thrust::transform来计算最终结果-按关键值取平均值。


You could also try the approach proposed by @RobertCrovella, which uses a single thrust::reduce_by_key to calculate the average. 您也可以尝试@RobertCrovella提出的方法,该方法使用单个thrust::reduce_by_key来计算平均值。

Output from reduce_by_key() as a function of two reduced vectors reduce_by_key()的输出是两个精简向量的函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM