我试图写一个k-means聚类类。我想让我的函数并行。
void kMeans::findNearestCluster()
{
short closest;
int moves = 0;
#pragma omp parallel for reduction(+:moves)
for(int i = 0; i < n; i++)
{
float min_dist=FLT_MAX;
for(int k=0; k < clusters; k++)
{
float dist_sum = 0.0, dist2 = 0.0;
for(int j = 0; j < dim; j++)
{
dist_sum = centroids[k*dim+j] - data[i*dim+j];
dist2 += dist_sum * dist_sum;
}
if (dist2 < min_dist)
{
min_dist = dist2;
closest = k;
}
}
if (assignment[i] != closest)
{
assignment[i] = closest;
moves++;
}
}
this->moves = moves;
}
这是它应该如何运作的:
第1步:查找最近的群集
遍历所有数据点,并比较所有质心之间的距离。
找到最近的质心时,它会存储在名为closest
的变量中。
检查此点是否已分配给新找到的最近群集。如果没有,请移动新的。 (增量移动)
第2步:根据新分配重新计算质心。 (功能未显示)
重复步骤1和步骤2,直到不再发生移动。
没有#parallel
moves
收敛为零。如果我#parallel
移动有随机值。我认为因为并行循环与更新move
存在冲突。
也许一个更好的策略是让每个线程都有自己的移动变量,最后它们会有一些上升。
答案 0 :(得分:1)
你在并行循环中使用closest
变量,在写入它之前将其用作检查,然后再增加moves
变量。但它在循环外声明,因此所有迭代都使用相同的变量!由于所有迭代都是并行执行(理论上),因此您不能指望任何迭代都能看到任何其他迭代在分支条件closest
中写入if (assignment[i] != closest)
的内容。通过竞争并行线程随机更新此变量。因此,您的moves
会评估垃圾值。
在外部循环中移动closest
声明或在OpenMP pragma中将其声明为private(closest)
可能会解决您的问题。
顺便说一句,closest
可能未初始化,应该与k
的类型相同,即int
。