C++ vs Python向量运算速度评测

本文的起源来自最近一个让我非常不爽的事。

我最近在改一个开源RNN工具包currennt(http://sourceforge.net/projects/currennt/),想用它实现RNNLM功能。

currennt使用了大量的面向对象的编程技巧,可以使用GPU,向量运算使用了thrust库(https://code.google.com/p/thrust/)。

RNNLM(http://rnnlm.org/)也有相应开源实现,非常算法风格的代码,向量运算就是自己使用数组实现的。

结果……大出我的语料,在不使用GPU的情况下,currennt慢成狗!我不断的修改,直到最后几乎完全在currennt里重写了一个RNNLM……速度才终于一致了。这花费了我大量时间,最关键的是我根本没打算花这些时间,算是计划外开销。

所以这里干脆对常用的几种向量运算做个评测,下回遇到至少心里有数。



参与评测的向量实现包括:

  1. C++ array
  2. C++ STL vector
  3. C++ thrust(CPU)
  4. C++ thrust(GPU)
  5. python
  6. python numpy
  7. python theano

评测指标包括:

  • 创建、填充向量
  • 向量点乘,相乘
  • 矩阵相乘

测试环境:

VS2010

python 2.7.6

Intel Xeon CPU [email protected] x24

thrust v1.5



C++ array

创建全0向量:0.000s,几乎不占用时间

int vector_size=100000000;
float* vector=(float*)calloc(vector_size,sizeof(float));

创建+填充向量:0.140s

int vector_size=100000000;
float* vector=(float*)calloc(vector_size,sizeof(float));
for (int i=0;i<vector_size;++i){
	vector[i]=0.01;
}

向量点乘:0.390s

float sum=0;
for(int i=0;i<vector_size;++i){
	sum+=vector1[i]*vector2[i];
}

向量相乘:0.265s

float sum=0;
for(int i=0;i<vector_size;++i){
	vector3[i]=vector1[i]*vector2[i];
}

矩阵乘向量:0.344s

int matrix1_colnum=50000;
int matrix1_rownum=2000;
int matrix1_size=matrix1_colnum*matrix1_rownum;
float* vector1=(float*)calloc(matrix1_size,sizeof(float));
for (int i=0;i<matrix1_size;++i){
	vector1[i]=0.01;
}

float* vector2=(float*)calloc(matrix1_colnum,sizeof(float));
for (int i=0;i<matrix1_colnum;++i){
	vector2[i]=0.02;
}

start_t=clock();
float* vector3=(float*)calloc(matrix1_rownum,sizeof(float));
for(int row=0;row<matrix1_rownum;++row){
	for(int col=0;col<matrix1_colnum;++col){
		vector3[row]+=vector1[row*matrix1_colnum+col]*vector2[col];
	}
}
end_t=clock();

矩阵乘矩阵:0.749

(耗费时间与matrix1_rownum*matrix1_colnum*matrix2_colnum成正比)

int matrix1_rownum=200;
int matrix1_colnum=5000;
int matrix1_size=matrix1_colnum*matrix1_rownum;
float* vector1=(float*)calloc(matrix1_size,sizeof(float));
for (int i=0;i<matrix1_size;++i){
	vector1[i]=0.01;
}

int matrix2_rownum=5000;
int matrix2_colnum=200;
int matrix2_size=matrix2_rownum*matrix2_colnum;
float* vector2=(float*)calloc(matrix2_size,sizeof(float));
for (int i=0;i<matrix2_size;++i){
	vector2[i]=0.02;
}

int matrix3_size=matrix1_rownum*matrix2_colnum;
float* vector3=(float*)calloc(matrix3_size,sizeof(float));
start_t=clock();
for(int row1=0;row1<matrix1_rownum;++row1){
	for(int col2=0;col2<matrix2_colnum;++col2){
		for(int col1=0;col1<matrix1_colnum;++col1){
			vector3[row1*matrix2_colnum+col2]+=vector1[row1*matrix1_colnum+col1]*vector2[col1*matrix2_colnum+col2];
		}
	}
}
end_t=clock();

C++ STL vector

创建全0向量:0.140s

int vect_size=100000000;vector<float> vector(vect_size);

创建+填充向量:0.140s

int vect_size=100000000;
vector<float> vector(vect_size,0.01);

向量点乘:0.375s

int vect_size=100000000;
vector<float> vector1(vect_size,0.01);
vector<float> vector2(vect_size,0.02);
start_t=clock();
float sum=0;
for(int i=0;i<vect_size;++i){
	sum+=vector1[i]*vector2[i];
}
end_t=clock();

向量相乘:0.250s

int vect_size=100000000;
vector<float> vector1(vect_size,0.01);
vector<float> vector2(vect_size,0.02);
vector<float> vector3(vect_size);
start_t=clock();
for(int i=0;i<vect_size;++i){
	vector3[i]=vector1[i]*vector2[i];
}
end_t=clock();

矩阵乘向量:0.390s

int matrix1_colnum=50000;
int matrix1_rownum=2000;
int matrix1_size=matrix1_colnum*matrix1_rownum;
vector<float> vector1(matrix1_size,0.01);
vector<float> vector2(matrix1_colnum,0.02);
vector<float> vector3(matrix1_rownum);
start_t=clock();
for(int row=0;row<matrix1_rownum;++row){
	for(int col=0;col<matrix1_colnum;++col){
		vector3[row]+=vector1[row*matrix1_colnum+col]*vector2[col];
	}
}
end_t=clock();

矩阵乘法:0.827s

int matrix1_rownum=200;
int matrix1_colnum=5000;
int matrix1_size=matrix1_colnum*matrix1_rownum;
vector<float> vector1(matrix1_size,0.01);

int matrix2_rownum=5000;
int matrix2_colnum=200;
int matrix2_size=matrix2_rownum*matrix2_colnum;
vector<float> vector2(matrix2_size,0.02);

int matrix3_size=matrix1_rownum*matrix2_colnum;
vector<float> vector3(matrix3_size);
start_t=clock();
for(int row1=0;row1<matrix1_rownum;++row1){
	for(int col2=0;col2<matrix2_colnum;++col2){
		for(int col1=0;col1<matrix1_colnum;++col1){
			vector3[row1*matrix2_colnum+col2]+=vector1[row1*matrix1_colnum+col1]*vector2[col1*matrix2_colnum+col2];
		}
	}
}
end_t=clock();

C++ thrust(CPU)

创建全0向量:0.140s

int vect_size=100000000;
thrust::host_vector<float> vector1(vect_size);

创建+填充向量:0.140s

int vect_size=100000000;
thrust::host_vector<float> vector1(vect_size,0.01);

填充向量:0.078s

thrust::fill(vector1.begin(),vector1.end(),0.01);

向量点乘:0.359s

int vect_size=100000000;
thrust::host_vector<float> vector1(vect_size,(float)0.1);
thrust::host_vector<float> vector2(vect_size,(float)0.2);
thrust::host_vector<float> vector3(vect_size,(float)0.2);

start_t=clock();
thrust::transform(vector1.begin(),vector1.end(),vector2.begin(),vector3.begin(),thrust::multiplies<float>());
float sum=thrust::reduce(vector3.begin(),vector3.end(),(float)0,thrust::multiplies<float>());
end_t=clock();

向量相乘:0.187s

int vect_size=100000000;
thrust::host_vector<float> vector1(vect_size,(float)0.1);
thrust::host_vector<float> vector2(vect_size,(float)0.2);
thrust::host_vector<float> vector3(vect_size);
start_t=clock();
thrust::transform(vector1.begin(),vector1.end(),vector2.begin(),vector3.begin(),thrust::multiplies<float>());
end_t=clock();

矩阵乘向量:0.110s

struct matrixXvect_func
{
	thrust::host_vector<float>* matrix;
	thrust::host_vector<float>* vector;
	int matrix_rownum;
	int matrix_colnum;

	__host__ __device__
	float operator()(const int& idx) const{
		float t=0;
		for(int col=0;col<matrix_colnum;++col){
			t+=(*matrix)[idx*matrix_colnum+col]* (*vector)[col];
		}
		return t;
	}
};

int matrix1_colnum=50000;
int matrix1_size=matrix1_colnum*matrix1_rownum;

thrust::host_vector<float> vector1(matrix1_size,(float)0.1);
thrust::host_vector<float> vector2(matrix1_colnum,(float)0.2);
thrust::host_vector<float> vector3(matrix1_rownum);

start_t=clock();

matrixXvect_func fn;
fn.matrix=&vector1;
fn.vector=&vector2;
fn.matrix_rownum=matrix1_rownum;
fn.matrix_colnum=matrix1_colnum;

thrust::transform(
            thrust::counting_iterator<int>(0),
            thrust::counting_iterator<int>(0) + matrix1_rownum,
            vector3.begin(),
            fn
            );

end_t=clock();

矩阵乘矩阵:0.655s

struct matrixXmatrix_func
{
	thrust::host_vector<float>* matrix1;
	thrust::host_vector<float>* matrix2;
	int matrix1_rownum;
	int matrix1_colnum;
	int matrix2_rownum;
	int matrix2_colnum;

	__host__ __device__
	float operator()(const int& idx) const{
		int rownum=idx/matrix2_colnum;
		int colnum=idx%matrix2_colnum;
		float t=0;
		for(int col=0;col<matrix1_colnum;++col){
			t+=(*matrix1)[rownum*matrix1_colnum+col]* (*matrix2)[col*matrix2_colnum+colnum];
		}
		return t;
	}
};

int matrix1_rownum=200;
int matrix1_colnum=5000;
int matrix1_size=matrix1_colnum*matrix1_rownum;
thrust::host_vector<float> vector1(matrix1_size,(float)0.1);

int matrix2_rownum=5000;
int matrix2_colnum=200;
int matrix2_size=matrix2_rownum*matrix2_colnum;
thrust::host_vector<float> vector2(matrix2_size,(float)0.2);

int matrix3_size=matrix1_rownum*matrix2_colnum;
thrust::host_vector<float> vector3(matrix3_size);

start_t=clock();

matrixXmatrix_func fn;
fn.matrix1=&vector1;
fn.matrix2=&vector2;
fn.matrix1_rownum=matrix1_rownum;
fn.matrix1_colnum=matrix1_colnum;
fn.matrix2_rownum=matrix2_rownum;
fn.matrix2_colnum=matrix2_colnum;

thrust::transform(
            thrust::counting_iterator<int>(0),
            thrust::counting_iterator<int>(0) + matrix3_size,
            vector3.begin(),
            fn
            );

end_t=clock();

  

时间: 2024-08-08 22:00:37

C++ vs Python向量运算速度评测的相关文章

【python gensim使用】word2vec词向量处理英文语料

word2vec介绍 word2vec官网:https://code.google.com/p/word2vec/ word2vec是google的一个开源工具,能够根据输入的词的集合计算出词与词之间的距离. 它将term转换成向量形式,可以把对文本内容的处理简化为向量空间中的向量运算,计算出向量空间上的相似度,来表示文本语义上的相似度. word2vec计算的是余弦值,距离范围为0-1之间,值越大代表两个词关联度越高. 词向量:用Distributed Representation表示词,通常

【python gensim使用】word2vec词向量处理中文语料

word2vec介绍 word2vec官网:https://code.google.com/p/word2vec/ word2vec是google的一个开源工具,能够根据输入的词的集合计算出词与词之间的距离. 它将term转换成向量形式,可以把对文本内容的处理简化为向量空间中的向量运算,计算出向量空间上的相似度,来表示文本语义上的相似度. word2vec计算的是余弦值,距离范围为0-1之间,值越大代表两个词关联度越高. 词向量:用Distributed Representation表示词,通常

【ST开发板评测】使用Python来开发STM32F411

前言 板子申请了也有一段时间了,也快到评测截止时间了,想着做点有意思的东西,正好前一段时间看到过可以在MCU上移植MicroPython的示例,就自己尝试一下,记录移植过程. MicroPython是什么 程序猿中有句俗语:人生苦短,我用Python.Python的强大和易用性让它不仅可以写网站,编程序,在嵌入式领域也有一席之地. MicroPython,是Python3编程语言的一个完整软件实现,包括Python标准库的一小部分,用C语言编写,经过优化可在微控制器和受限环境中运行.MicroP

gensim的word2vec如何得出词向量(python)

首先需要具备gensim包,然后需要一个语料库用来训练,这里用到的是skip-gram或CBOW方法,具体细节可以去查查相关资料,这两种方法大致上就是把意思相近的词映射到词空间中相近的位置. 语料库test8下载地址: http://mattmahoney.net/dc/text8.zip 这个语料库是从http://blog.csdn.net/m0_37681914/article/details/73861441这篇文章中找到的. 检查语料是否需要做预处理:将数据下载好了解压出来,在做词向量

Python中怎样统计两个向量对应位置的非0元素个数??

首先看看矩阵中.A操作的结果 1 >>> a=mat([[1,2,3],[2,3,0]]); 2 >>> a 3 matrix([[1, 2, 3], 4 [2, 3, 0]]) 5 >>> a.A 6 array([[1, 2, 3], 7 [2, 3, 0]]) 8 >>> shape(a) 9 (2, 3) 10 >>> shape(a.A) 11 (2, 3) 12 >>> type(a)

Python中怎样计算两个向量的内积??

1 >>> a=mat([[1],[2],[3]]); 2 >>> b=mat([[0],[2],[3]]); 3 >>> a 4 matrix([[1], 5 [2], 6 [3]]) 7 >>> b 8 matrix([[0], 9 [2], 10 [3]]) 11 >>> a.T*b 12 matrix([[13]]) 上面为两个列向量的内积计算,注意列向量的构建a=mat([[1],[2],[3]]); 下面

Python Word2Vec使用训练好的模型生成词向量

# 文本文件必须是utf-8无bom格式 from gensim.models.deprecated.word2vec import Word2Vec model = Word2Vec.load( './model/Word60.model') # 3个文件放在一起:Word60.model Word60.model.syn0.npy Word60.model.syn1neg.npy print("read model successful") word_list = ['了', '不

机器学习经典算法具体解释及Python实现--线性回归(Linear Regression)算法

(一)认识回归 回归是统计学中最有力的工具之中的一个. 机器学习监督学习算法分为分类算法和回归算法两种,事实上就是依据类别标签分布类型为离散型.连续性而定义的. 顾名思义.分类算法用于离散型分布预測,如前面讲过的KNN.决策树.朴素贝叶斯.adaboost.SVM.Logistic回归都是分类算法.回归算法用于连续型分布预測.针对的是数值型的样本,使用回归.能够在给定输入的时候预測出一个数值.这是对分类方法的提升,由于这样能够预測连续型数据而不不过离散的类别标签. 回归的目的就是建立一个回归方程

spark机器学习笔记:(五)用Spark Python构建分类模型(下)

声明:版权所有,转载请联系作者并注明出处  http://blog.csdn.net/u013719780?viewmode=contents 博主简介:风雪夜归子(英文名:Allen),机器学习算法攻城狮,喜爱钻研Meachine Learning的黑科技,对Deep Learning和Artificial Intelligence充满兴趣,经常关注Kaggle数据挖掘竞赛平台,对数据.Machine Learning和Artificial Intelligence有兴趣的童鞋可以一起探讨哦,