【CUDA并行编程之六】KNN算法的并行实现

之前写了两篇文章一个是KNN算法的C++串行实现,另一个是CUDA计算向量的欧氏距离。那么这篇文章就可以说是前两篇文章的一个简单的整合。在看这篇文章之前可以先阅读前两篇文章。


一、生成数据集

现在需要生成一个N个D维的数据,没在一组数据都有一个类标,这个类标根据第一维的正负来进行标识样本数据的类标:Positive and Negative。

#!/usr/bin/python

import re
import sys
import random
import os

filename = "input.txt"

if(os.path.exists(filename)):
	print("%s exists and del" % filename)
	os.remove(filename)

fout = open(filename,"w")

for i in range( 0,int(sys.argv[1]) ): #str to int
	x = []
	for j in range(0,int(sys.argv[2])):
		x.append( "%4f" % random.uniform(-1,1) ) #generate random data and limit the digits into 4
		fout.write("%s\t" % x[j])
		#fout.write(x) : TypeError:expected a character buffer object 

	if(x[0][0] == '-'):
		fout.write(" Negative"+"\n")
	else:
		fout.write(" Positive"+"\n")

fout.close()

运行程序,生成4000个维度为8的数据:


生成了文件"input.txt":

【CUDA并行编程之六】KNN算法的并行实现_第1张图片


二、串行代码:

这个代码和之前的文章的代码一致,我们选择400个数据进行作为测试数据,3600个数据进行训练数据。

KNN_2.cc:

#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

typedef string tLabel;
typedef double tData;
typedef pair  PAIR;
const int MaxColLen = 10;
const int MaxRowLen = 10000;
ifstream fin;

class KNN
{
private:
		tData dataSet[MaxRowLen][MaxColLen];
		tLabel labels[MaxRowLen];
		tData testData[MaxColLen];
		int rowLen;
		int colLen;
		int k;
		int test_data_num;
		map map_index_dis;
		map map_label_freq;
		double get_distance(tData *d1,tData *d2);
public:
		KNN(int k , int rowLen , int colLen , char *filename);
		void get_all_distance();
		tLabel get_max_freq_label();
		void auto_norm_data();
		void get_error_rate();
		struct CmpByValue
		{
			bool operator() (const PAIR& lhs,const PAIR& rhs)
			{
				return lhs.second < rhs.second;
			}
		};

		~KNN();	
};

KNN::~KNN()
{
	fin.close();
	map_index_dis.clear();
	map_label_freq.clear();
}

KNN::KNN(int k , int row ,int col , char *filename)
{
	this->rowLen = row;
	this->colLen = col;
	this->k = k;
	test_data_num = 0;
	
	fin.open(filename);

	if( !fin )
	{
		cout<<"can not open the file"<>dataSet[i][j];
		}
		fin>>labels[i];
	}

}

void KNN:: get_error_rate()
{
	int i,j,count = 0;
	tLabel label;
	cout<<"please input the number of test data : "<>test_data_num;
	for(i=0;i::const_iterator map_it = map_label_freq.begin();
	tLabel label;
	int max_freq = 0;
	while( map_it != map_label_freq.end() )
	{
		if( map_it->second > max_freq )
		{
			max_freq = map_it->second;
			label = map_it->first;
		}
		map_it++;
	}
	//cout<<"The test data belongs to the "<maxa[j] )
			{
				maxa[j] = dataSet[i][j];
			}
			else if( dataSet[i][j]
makefile:

target:
	g++ KNN_2.cc
	./a.out 7 4000 8 input.txt

cu:
	nvcc KNN.cu
	./a.out 7 4000 8 input.txt

运行结果:

【CUDA并行编程之六】KNN算法的并行实现_第2张图片


三、并行实现

并行实现的过程就是将没一个测试样本到N个训练样本的距离进行并行化,如果串行计算的话,时间复杂度为:O(N*D),如果串行计算的话,时间复杂度为O(D),其实D为数据的维度。

KNN.cu:

#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;

typedef string tLabel;
typedef float tData;
typedef pair  PAIR;
const int MaxColLen = 10;
const int MaxRowLen = 10010;
const int test_data_num = 400;
ifstream fin;

class KNN
{
private:
		tData dataSet[MaxRowLen][MaxColLen];
		tLabel labels[MaxRowLen];
		tData testData[MaxColLen];
		tData trainingData[3600][8];
		int rowLen;
		int colLen;
		int k;
		map map_index_dis;
		map map_label_freq;
		double get_distance(tData *d1,tData *d2);
public:
		KNN(int k , int rowLen , int colLen , char *filename);
		void get_all_distance();
		tLabel get_max_freq_label();
		void auto_norm_data();
		void get_error_rate();
		void get_training_data();
		struct CmpByValue
		{
			bool operator() (const PAIR& lhs,const PAIR& rhs)
			{
				return lhs.second < rhs.second;
			}
		};

		~KNN();	
};

KNN::~KNN()
{
	fin.close();
	map_index_dis.clear();
	map_label_freq.clear();
}

KNN::KNN(int k , int row ,int col , char *filename)
{
	this->rowLen = row;
	this->colLen = col;
	this->k = k;
	
	fin.open(filename);

	if( !fin )
	{
		cout<<"can not open the file"<>dataSet[i][j];
		}
		fin>>labels[i];
	}

}

void KNN:: get_training_data()
{
	for(int i=test_data_num;i::const_iterator map_it = map_label_freq.begin();
	tLabel label;
	int max_freq = 0;
	while( map_it != map_label_freq.end() )
	{
		if( map_it->second > max_freq )
		{
			max_freq = map_it->second;
			label = map_it->first;
		}
		map_it++;
	}
	cout<<"The test data belongs to the "<maxa[j] )
			{
				maxa[j] = dataSet[i][j];
			}
			else if( dataSet[i][j]

运行结果:


因为内存分配的问题(之前文章提到过),那么就需要将训练数据trainingData进行静态的空间分配,这样不是很方便。

可以看到,在测试数据集和训练数据集完全相同的情况下,结果是完全一样的。数据量小,没有做时间性能上的对比。还有可以改进的地方就是可以一次性的将所有testData载入到显存中,而不是一个一个的载入,这样就能够减少训练数据拷贝到显存中的次数,提高效率。


Author:忆之独秀

Email:[email protected]

注明出处:http://blog.csdn.net/lavorange/article/details/42172451


你可能感兴趣的:(DataMining,HPC)