我想从非穿制的样本中重新采样(插值)一个序列。我认为tex不起作用,因为它基本上是插值,假设你的样本是均匀的?做搜索太慢了?
我应该做推力吗?任何指针都很受欢迎。任何例子都会非常有用。
更新
说带圆圈标记的线是我的样本。我知道每个圆点的值。显然,样品均匀分布在水平轴上。
现在,我想知道采样线下方线上每个x标记的值。 x标记沿着线均匀分布。
--- o -------- o ---- o ------ o ------ o ------ o ------(抽样)
- X ----- X ----- X ----- X ----- X ----- X ----- X ---(已知插补)
所以我想知道如何使用CUDA获取每个x标记位置的值?显然,使用C / C ++的最基本算法是针对每个x标记位置,搜索两个最近的圆位置,然后进行线性插值。但在这种情况下,您需要先对两个序列进行排序,然后循环遍历x标记,并对每个x标记进行搜索。这听起来很广泛。
我想知道我们应该如何在CUDA中做到这一点?感谢。
答案 0 :(得分:2)
可能有很多方法。例如,您可以以线程并行方式使用基本cuda binary search。我将演示thrust实现。
出于本讨论的目的,我假设两个数据集(已知的采样点和所需的采样点)是任意放置的(即,我不假设任一样本集均匀分布)。但是,我将规定或要求在已知样本点内完全包含所需的样本点。我相信这是明智的,因为通常的线性插值需要在所需采样点两侧的已知采样点。
因此,我们将使用如下数据集:
o: 1,3,7
f(o): 3,7,15
x: 1.5, 2.5, 4.5, 5.0, 6.0, 6.5
f(x): ?, ?, ?, ?, ?, ?
我们看到f
是已知的功能值,对应于f(o) = 2o+1
,在这种情况下是一条直线(尽管此方法不要求已知的采样点适合任何特定的功能)。 x
表示我们希望根据已知值(f(o)
)插入功能值的索引。我们希望通过从最近的f(x)
点插值来计算f(o)
。请注意,我们的数据集使x
的所有值都位于最小值(1)和最大值(7)o
之间。这是我之前所说的规定/要求。
我们的推力方法是使用矢量化二分搜索,使用thrust::upper_bound
来定位"插入点"其中每个所需的x
值都符合o
序列。这给了我们正确的邻居,并且左邻居(右1)进行插值。一旦我们知道了插入点,那么选择例如这个算法将是一个简单的扩展。如果我们想要使用除线性插值之外的其他东西,两个左边和两个右邻居(或更多)。
插入点然后给我们左右邻居,我们使用此信息将thrust::transform
向量(所需插值点)和{{1}传递给适当制作的x
操作提供:
thrust::tuple
)
使用这些数量加上所需的索引(thrust::zip_iterator
),插值很简单。
编辑:受其他答案的启发,我决定采用一种避免并行二进制搜索的方法,而是使用前缀和方法来识别{{1}的插入索引} x
数据中的数据。此方法假定 x
和o
序列都已排序。
我们将从merge_by_key操作开始。我们将x
与o
合并,以建立排序(这似乎比二分搜索更有效)。 x
和o
数量将是"键" x
的值均为1,o
的值均为0。然后使用我们的示例数据,merge_by_key将生成:
o
当我们对合并的val执行前缀sum(包含扫描)时,我们得到:
x
然后我们可以执行copy_if操作以仅提取与o keys: 1,3,7
o vals: 1,1,1
x keys: 1.5,2.5,4.5,5.0,6.0,6.5
x vals: 0, 0, 0, 0, 0, 0
merged keys: 1, 1.5, 2.5, 3, 4.5, 5.0, 6.0, 6.5, 7
merged vals: 1, 0, 0, 1, 0, 0, 0, 0, 1
val(其合并的val为零)关联的插入索引,以生成在步骤1中生成的相同插入索引序列:
ins. ind.: 1, 1, 1, 2, 2, 2, 2, 2, 3
然后,方法2的其余部分可以使用与方法1中使用的完全相同的剩余插值代码(x
)。
这是一个完整的例子,显示了两种方法:
d_i: 1, 1, 2, 2, 2, 2
同样,一旦我们知道插入点,选择2个右边和2个左边邻居进行更多涉及插值将是一个简单的扩展。我们只需修改传递给transform(插值)仿函数的zip迭代器,并修改仿函数本身以实现所需的算法。
另请注意,此方法假定输入thrust::transform
序列已经排序。如果不是,那么有必要添加$ cat t1224.cu
#include <thrust/device_vector.h>
#include <thrust/binary_search.h>
#include <thrust/transform.h>
#include <thrust/copy.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <iostream>
#include <thrust/merge.h>
#include <thrust/iterator/constant_iterator.h>
#include <thrust/scan.h>
struct interp_func
{
template <typename T>
__host__ __device__
float operator()(float t1, T t2){ // m = (y1-y0)/(x1-x0) y = m(x-x0) + y0
return ((thrust::get<1>(t2) - thrust::get<3>(t2))/(thrust::get<0>(t2) - thrust::get<2>(t2)))*(t1 - thrust::get<2>(t2)) + thrust::get<3>(t2);
}
};
using namespace thrust::placeholders;
int main(){
// sample data
float o[] = {1.0f, 3.0f, 7.0f}; // unevenly spaced sample points for function f
float f[] = {3.0f, 7.0f, 15.0f}; // f(o) = 2o+1
float x[] = {1.5f, 2.5f, 4.5f, 5.0f, 6.0f, 6.5f}; // additional desired sample points for f
int so = sizeof(o)/sizeof(o[0]);
int sx = sizeof(x)/sizeof(x[0]);
// setup data on device
thrust::device_vector<float> d_o(o, o+so);
thrust::device_vector<float> d_f(f, f+so);
thrust::device_vector<float> d_x(x, x+sx);
thrust::device_vector<int> d_i(sx); // insertion indices
thrust::device_vector<float> d_r(sx); // results
// method 1: binary search
// perform search for insertion indices
thrust::upper_bound(d_o.begin(), d_o.end(), d_x.begin(), d_x.end(), d_i.begin());
// then perform linear interpolation based on left and right neighbors
std::cout << "Method 1 insertion indices:" << std::endl;
thrust::copy(d_i.begin(), d_i.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
thrust::transform(d_x.begin(), d_x.end(), thrust::make_zip_iterator(thrust::make_tuple(thrust::make_permutation_iterator(d_o.begin(), d_i.begin()), thrust::make_permutation_iterator(d_f.begin(), d_i.begin()), thrust::make_permutation_iterator(d_o.begin(), thrust::make_transform_iterator(d_i.begin(), _1-1)), thrust::make_permutation_iterator(d_f.begin(), thrust::make_transform_iterator(d_i.begin(), _1-1)))), d_r.begin(), interp_func());
// output results
std::cout << "Interpolation points:" << std::endl;
thrust::copy(d_x.begin(), d_x.end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "Interpolated values:" << std::endl;
thrust::copy(d_r.begin(), d_r.end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "Expected values:" << std::endl;
for (int i = 0; i < sx; i++) std::cout << 2*x[i]+1 << ",";
std::cout << std::endl;
//method 2: merge + prefix sum
thrust::device_vector<float> d_kr(sx+so);
thrust::device_vector<int> d_vr(sx+so);
thrust::device_vector<int> d_s(sx+so);
thrust::merge_by_key(d_o.begin(), d_o.end(), d_x.begin(), d_x.end(), thrust::constant_iterator<int>(1), thrust::constant_iterator<int>(0), d_kr.begin(), d_vr.begin());
thrust::inclusive_scan(d_vr.begin(), d_vr.end(), d_s.begin());
thrust::copy_if(d_s.begin(), d_s.end(), d_vr.begin(), d_i.begin(), _1 == 0);
std::cout << "Method 2 insertion indices:" << std::endl;
thrust::copy(d_i.begin(), d_i.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
// remainder of solution method would be identical to end of method 1 starting with the thrust::transform
return 0;
}
$ nvcc -o t1224 t1224.cu
$ ./t1224
Method 1 insertion indices:
1,1,2,2,2,2,
Interpolation points:
1.5,2.5,4.5,5,6,6.5,
Interpolated values:
4,6,10,11,13,14,
Expected values:
4,6,10,11,13,14,
Method 2 insertion indices:
1,1,2,2,2,2,
$
(键)与o
(值)的按键排序。 o
序列不需要为方法1排序,但必须对方法2进行排序(合并需要对两个序列进行排序)。
答案 1 :(得分:2)
最佳方法的细节取决于所涉及的大小(即,它是一大批短序列还是单个巨大序列等),但在高水平上,您只能使用(并行可能的O) (N))输入序列和并行前缀和的排序。特别是你可以避免任何二进制搜索。查看&#34; intervalExpand&#34;背后的想法。 nowGPU:https://nvlabs.github.io/moderngpu/intervalmove.html
简要介绍伪代码:
1: sort the input sequence
2: for each input point seq[i]:
let count[i] = number of output points in the interval [seq[i], seq[i+1])
3: let indices = exclusive prefix-sum of count
4: use intervalExpand() to go from seq, count, indices to the desired output.
你可以坚持你在步骤4中想要的任何插值公式,包括线性,立方等。重要的是intervalExpand将告诉你每个输出索引,这是正确的输入将输出夹在中间的索引。
同样,如果您正在使用大批小序列,二进制搜索实际上可能更快运行并且更容易编写。否则你应该能够使用modernGPU库中的模板化代码来相对轻松地完成这项工作。
希望有所帮助。