用CUDA计算相应矩阵行之间的欧氏距离
我有一个非常简单的算法,计算两个矩阵对应行之间的平方欧几里德距离。我有以下代码,但不幸的是,对于不同的矩阵大小,它没有返回正确的结果。更具体地说,它适用于大小为用CUDA计算相应矩阵行之间的欧氏距离,cuda,parallel-processing,gpu,Cuda,Parallel Processing,Gpu,我有一个非常简单的算法,计算两个矩阵对应行之间的平方欧几里德距离。我有以下代码,但不幸的是,对于不同的矩阵大小,它没有返回正确的结果。更具体地说,它适用于大小为2000x4,500x4,2500x2,600x8,1000x8,100x8的矩阵,但不适用于大小为2500x3,2500x5,400x3,100x3,100x10,的矩阵,1000x12,500x12,500x14 有人能帮我吗?我想手动执行,不使用任何优化的库,因为我想了解线程管理 __global__ void cudaEuclid
2000x4
,500x4
,2500x2
,600x8
,1000x8
,100x8
的矩阵,但不适用于大小为2500x3
,2500x5
,400x3
,100x3
,100x10
,的矩阵,1000x12
,500x12
,500x14
有人能帮我吗?我想手动执行,不使用任何优化的库,因为我想了解线程管理
__global__ void cudaEuclid( float* A, float* B, float* C, int rows, int cols )
{
int i, squareeucldist = 0;
int r = blockDim.x * blockIdx.x + threadIdx.x; // rows
int c = blockDim.y * blockIdx.y + threadIdx.y; // cols
extern __shared__ float sdata[];
//int r = blockIdx.y; int c = threadIdx.x;
if( r < rows && c < cols ){
//C[r + rows*c] = ( A[r + rows*c] - B[r + rows*c] ) * ( A[r + rows*c] - B[r + rows*c] );
sdata[threadIdx.x] = ( A[r + rows*c] - B[r + rows*c] ) * ( A[r + rows*c] - B[r + rows*c] );
__syncthreads();
// contiguous range pattern
for(int offset = blockDim.x / 2;
offset > 0;
offset >>= 1)
{
if(threadIdx.x < offset)
{
// add a partial sum upstream to our own
sdata[threadIdx.x] += sdata[threadIdx.x + offset];
}
// wait until all threads in the block have
// updated their partial sums
__syncthreads();
}
// thread 0 writes the final result
if(threadIdx.x == 0)
{
C[r] = sdata[0];
}
}
}
\uuuuu全局\uuuuu无效cudaEuclid(浮点*A、浮点*B、浮点*C、整数行、整数列)
{
int i,squareUCLDist=0;
int r=blockDim.x*blockIdx.x+threadIdx.x;//行
int c=blockDim.y*blockIdx.y+threadIdx.y;//cols
外部共享浮点数据[];
//int r=blockIdx.y;int c=threadIdx.x;
if(r0;
偏移量>>=1)
{
if(螺纹IDX.x<偏移量)
{
//在我们自己的上游加上一部分金额
sdata[threadIdx.x]+=sdata[threadIdx.x+偏移量];
}
//等待,直到块中的所有线程都已完成
//更新了他们的部分总和
__同步线程();
}
//线程0写入最终结果
if(threadIdx.x==0)
{
C[r]=sdata[0];
}
}
}
内核调用是:
dim3 dimBlock( cols, 1 );
dim3 dimGrid( 1, rows );
cudaEuclid<<<dimGrid, cols, cols*sizeof(float)>>>( d_A, d_B, d_C, rows, cols );
dim3 dimBlock(cols,1);
dim3 dimGrid(1行);
cudaEuclid(d_A、d_B、d_C、rows、cols);
PS:我想说的是,我发布了一个类似的问题,但从一开始就不清楚,讨论方向混乱。尽管Tom提出了一个非常有用的建议,即它在未来的优化实现中将非常实用,但我需要一些更手工的东西。最后,我写这篇文章的原因是因为我不想让相关的文章变得更复杂。谢谢。事实上,只有当n
足够小时,您的代码才能在m*2^n
上工作。您可能想更仔细地阅读第14页的以下幻灯片
思考以下问题
当blockDim.x
等于3或5时会发生什么李>
当blockDim.x
或cols
不是2的幂时,如何正确执行并行缩减李>
为什么减少的结果小于预期李>
sdata[]
中的哪些元素未添加到最终总和中李>
当cols
为5时,如果将blockDim.x
和smem的大小设置为2^3,结果是否正确李>
对于q5,如何处理smem[5..7]
试着用你的笔和纸一步一步地模拟运行for循环会有所帮助。尽管OP不想使用优化的库来回答他的问题,但这篇文章有一个有用的标题,其他用户可以发现,在没有手写内核的情况下解决这个问题很有用
我很好奇,并对这个问题进行了一些研究,考虑使用CUDA推力。我以下面的代码结束,该代码通过使用推力::reduce_by_key
计算两个矩阵的同源行之间的距离
#include <thrust\device_vector.h>
#include <thrust\transform_reduce.h>
#include <thrust\sequence.h>
#include <thrust\random.h>
#include <thrust\gather.h>
#include <thrust\extrema.h>
using namespace thrust::placeholders;
/****************************************************/
/* POWER DIFFERENCE FUNCTOR FOR EUCLIDEAN DISTANCES */
/****************************************************/
struct PowerDifference {
__host__ __device__ float operator()(const float& a, const float& b) const { return pow(a - b, 2); }
};
/*******************/
/* EXPAND OPERATOR */
/*******************/
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
OutputIterator expand(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
OutputIterator output)
{
typedef typename thrust::iterator_difference<InputIterator1>::type difference_type;
difference_type input_size = thrust::distance(first1, last1);
difference_type output_size = thrust::reduce(first1, last1);
// scan the counts to obtain output offsets for each input element
thrust::device_vector<difference_type> output_offsets(input_size, 0);
thrust::exclusive_scan(first1, last1, output_offsets.begin());
// scatter the nonzero counts into their corresponding output positions
thrust::device_vector<difference_type> output_indices(output_size, 0);
thrust::scatter_if(thrust::counting_iterator<difference_type>(0), thrust::counting_iterator<difference_type>(input_size),
output_offsets.begin(), first1, output_indices.begin());
// compute max-scan over the output indices, filling in the holes
thrust::inclusive_scan(output_indices.begin(), output_indices.end(), output_indices.begin(), thrust::maximum<difference_type>());
// gather input values according to index array (output = first2[output_indices])
OutputIterator output_end = output; thrust::advance(output_end, output_size);
thrust::gather(output_indices.begin(), output_indices.end(), first2, output);
// return output + output_size
thrust::advance(output, output_size);
return output;
}
/********/
/* MAIN */
/********/
int main()
{
/**************************/
/* SETTING UP THE PROBLEM */
/**************************/
const int N = 10; // --- Number of vector elements
const int Nvec = 20; // --- Number of vectors for each matrix
// --- Random uniform integer distribution between 0 and 100
thrust::default_random_engine rng;
thrust::uniform_int_distribution<int> dist(0, 20);
// --- Matrix allocation and initialization
thrust::device_vector<float> d_matrix1(Nvec * N);
thrust::device_vector<float> d_matrix2(Nvec * N);
for (size_t i = 0; i < d_matrix1.size(); i++) d_matrix1[i] = (float)dist(rng);
for (size_t i = 0; i < d_matrix2.size(); i++) d_matrix2[i] = (float)dist(rng);
printf("\n\nFirst matrix\n");
for(int i = 0; i < Nvec; i++) {
std::cout << " [ ";
for(int j = 0; j < N; j++)
std::cout << d_matrix1[i * N + j] << " ";
std::cout << "]\n";
}
printf("\n\nSecond matrix\n");
for(int i = 0; i < Nvec; i++) {
std::cout << " [ ";
for(int j = 0; j < N; j++)
std::cout << d_matrix2[i * N + j] << " ";
std::cout << "]\n";
}
/****************************************************************************/
/* CALCULATING THE EUCLIDEAN DISTANCES BETWEEN THE ROWS OF THE TWO MATRICES */
/****************************************************************************/
// --- Creating the indices for the reduction by key
thrust::device_vector<int> d_sequence(Nvec);
thrust::device_vector<int> d_indices(Nvec * N);
thrust::device_vector<int> d_counts(Nvec, N);
thrust::sequence(d_sequence.begin(), d_sequence.begin() + Nvec);
expand(d_counts.begin(), d_counts.end(), d_sequence.begin(), d_indices.begin());
printf("\n\nSecond matrix\n");
for(int i = 0; i < Nvec; i++) {
std::cout << " [ ";
for(int j = 0; j < N; j++)
std::cout << d_indices[i * N + j] << " ";
std::cout << "]\n";
}
thrust::device_vector<float> d_squared_differences(Nvec * N);
thrust::transform(d_matrix1.begin(), d_matrix1.end(), d_matrix2.begin(), d_squared_differences.begin(), PowerDifference());
thrust::device_vector<float> d_norms(Nvec);
thrust::reduce_by_key(d_indices.begin(), d_indices.end(), d_squared_differences.begin(), d_indices.begin(), d_norms.begin());
printf("\n\ndnorms\n");
for(int i = 0; i < Nvec; i++) {
std::cout << d_norms[i] << " ";
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用命名空间推力::占位符;
/****************************************************/
/*欧氏距离的幂差函子*/
/****************************************************/
结构功率差{
__主机___设备_;浮点运算符()(常量浮点&a,常量浮点&b)常量{return pow(a-b,2);}
};
/*******************/
/*扩展运算符*/
/*******************/
模板
输出迭代器扩展(输入迭代器1优先1,
输入计数器1 last1,
输入计数器2 first2,
输出计数器(输出)
{
typedef typename推力::迭代器_差异::类型差异_类型;
差异类型输入大小=推力::距离(第一个1,最后一个1);
差异类型输出大小=推力::减小(第一个1,最后一个1);
//扫描计数以获得每个输入元素的输出偏移量
推力::设备矢量输出偏移量(输入大小,0);
推力:独占扫描(first1,last1,output_offset.begin());
//将非零计数分散到相应的输出位置
推力:设备矢量输出指数(输出大小,0);
推力::分散if(推力::计数迭代器(0),推力::计数迭代器(输入大小),
output_offset.begin(),first1,output_index.begin());
//计算输出索引的最大扫描,填充孔
推力::包括性推力扫描(输出推力索引.begin(),输出推力索引.end(),输出推力索引.begin(),推力::最大值());
//根据索引数组收集输入值(output=first2[output\u index])
输出计数器输出端=输出;推力::前进(输出端,输出大小);
推力::聚集(输出索引.begin(),输出索引.end(),first2,输出);
//返回输出+输出大小
推力:前进(输出、输出尺寸);
返回输出;
}
/********/
/*主要*/
/********/
我