梳理caffe代码math_functions(一)

转载 http://blog.csdn.net/langb2014/article/details/50986678

先从caffe中使用的函数入手看看:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <boost/math/special_functions/next.hpp>  
  2. #include <boost/random.hpp>  
  3.   
  4. #include <limits>  
  5.   
  6. #include "caffe/common.hpp"  
  7. #include "caffe/util/math_functions.hpp"  
  8. #include "caffe/util/rng.hpp"  
  9.   
  10. namespace caffe {  
  11. //math_function 定义了caffe 中用到的一些矩阵操作和数值计算的一些函数  
  12. /* 
  13.  *功能: C=alpha*A*B+beta*C 
  14.  *A,B,C 是输入矩阵(一维数组格式) 
  15.  *CblasRowMajor :数据是行主序的(二维数据也是用一维数组储存的) 
  16.  *TransA, TransB:是否要对A和B做转置操作(CblasTrans CblasNoTrans) 
  17.  *M: A、C 的行数 
  18.  *N: B、C 的列数 
  19.  *K: A 的列数, B 的行数 
  20.  *lda : A的列数(不做转置)行数(做转置) 
  21.  *ldb: B的列数(不做转置)行数(做转置) 
  22. */  
  23. template<>  
  24. void caffe_cpu_gemm<float>(const CBLAS_TRANSPOSE TransA,  
  25.     const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K,  
  26.     const float alpha, const float* A, const float* B, const float beta,  
  27.     float* C) {  
  28.   int lda = (TransA == CblasNoTrans) ? K : M;  
  29.   int ldb = (TransB == CblasNoTrans) ? N : K;  
  30.   cblas_sgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B,  
  31.       ldb, beta, C, N);  
  32. }  
  33. /*计算矩阵乘法的函数之一是 cblas_sgemm,使用单精度实数,另外还有对应双精度实数, 
  34. 单精度复数和双精度复数的函数。在此以 cblas_sgemm为例。 
  35. 函数定义为: 
  36. void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, 
  37. const enum CBLAS_TRANSPOSE TransB, const int M, const int N, 
  38. const int K, const float alpha, const float  *A, 
  39. const int lda, const float  *B, const int ldb, 
  40. const float beta, float  *C, const int ldc) 
  41. 得到的结果是: 
  42.  C = alpha*op( A )*op( B ) + beta*C 
  43. const enum CBLAS_ORDER Order,这是指的数据的存储形式,在CBLAS的函数中无论一维还是二维数据 
  44. 都是用一维数组存储,这就要涉及是行主序还是列主序,在C语言中数组是用 行主序,fortran中是列 
  45. 主序。我还是习惯于是用行主序,所以这个参数是用CblasRowMajor,如果是列主序的话就是 CblasColMajor。 
  46. const int M,矩阵A的行,矩阵C的行 
  47. const int N,矩阵B的列,矩阵C的列 
  48. const int K,矩阵A的列,矩阵B的行 
  49. const float alpha, const float beta,计算公式中的两个参数值,如果只是计算C=A*B,则alpha=1,beta=0 
  50. const float  *A, const float  *B, const float  *C,矩阵ABC的数据 
  51. const int lda, const int ldb, const int ldc,在BLAS的文档里,这三个参数分别为ABC的行数, 
  52. 但是实际使用发现,在CBLAS里应该是列数。 
  53. */  
  54. template<>  
  55. void caffe_cpu_gemm<double>(const CBLAS_TRANSPOSE TransA,  
  56.     const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K,  
  57.     const double alpha, const double* A, const double* B, const double beta,  
  58.     double* C) {  
  59.   int lda = (TransA == CblasNoTrans) ? K : M;  
  60.   int ldb = (TransB == CblasNoTrans) ? N : K;  
  61.   cblas_dgemm(CblasRowMajor, TransA, TransB, M, N, K, alpha, A, lda, B,  
  62.       ldb, beta, C, N);  
  63. }  
  64. /* 
  65. 功能: y=alpha*A*x+beta*y 
  66. 其中X和Y是向量,A 是矩阵 
  67. M:A 的行数 
  68. N:A 的列数 
  69. cblas_sgemv 中的 参数1 表示对X和Y的每个元素都进行操作 
  70. */  
  71. template <>  
  72. void caffe_cpu_gemv<float>(const CBLAS_TRANSPOSE TransA, const int M,  
  73.     const int N, const float alpha, const float* A, const float* x,  
  74.     const float beta, float* y) {  
  75.   cblas_sgemv(CblasRowMajor, TransA, M, N, alpha, A, N, x, 1, beta, y, 1);  
  76. }  
  77.   
  78. template <>  
  79. void caffe_cpu_gemv<double>(const CBLAS_TRANSPOSE TransA, const int M,  
  80.     const int N, const double alpha, const double* A, const double* x,  
  81.     const double beta, double* y) {  
  82.   cblas_dgemv(CblasRowMajor, TransA, M, N, alpha, A, N, x, 1, beta, y, 1);  
  83. }  
  84. /* 
  85. 功能: Y=alpha*X+Y 
  86. N:为X和Y中element的个数 
  87. */  
  88. template <>  
  89. void caffe_axpy<float>(const int N, const float alpha, const float* X,  
  90.     float* Y) { cblas_saxpy(N, alpha, X, 1, Y, 1); }  
  91.   
  92. template <>  
  93. void caffe_axpy<double>(const int N, const double alpha, const double* X,  
  94.     double* Y) { cblas_daxpy(N, alpha, X, 1, Y, 1); }  
  95. /* 
  96. 功能:用常数 alpha 对 Y 进行初始化 
  97. 函数 void *memset(void *buffer, char c, unsigned count) 一般为新申请的内存做初始化, 
  98. 功能是将buffer所指向内存中的每个字节的内容全部设置为c指定的ASCII值, count为块的大小, 
  99. 使用memset函数来初始化数组或者结构体比其他初始化方法更快一点 
  100. */  
  101. template <typename Dtype>  
  102. void caffe_set(const int N, const Dtype alpha, Dtype* Y) {  
  103.   if (alpha == 0) {  
  104.     memset(Y, 0, sizeof(Dtype) * N);  // NOLINT(caffe/alt_fn)  
  105.     return;  
  106.   }  
  107.   for (int i = 0; i < N; ++i) {  
  108.     Y[i] = alpha;  
  109.   }  
  110. }  
  111.   
  112. template void caffe_set<int>(const int N, const int alpha, int* Y);  
  113. template void caffe_set<float>(const int N, const float alpha, float* Y);  
  114. template void caffe_set<double>(const int N, const double alpha, double* Y);  
  115. //功能: 给 Y 的每个 element 加上常数 alpha  
  116. template <>  
  117. void caffe_add_scalar(const int N, const float alpha, float* Y) {  
  118.   for (int i = 0; i < N; ++i) {  
  119.     Y[i] += alpha;  
  120.   }  
  121. }  
  122.   
  123. template <>  
  124. void caffe_add_scalar(const int N, const double alpha, double* Y) {  
  125.   for (int i = 0; i < N; ++i) {  
  126.     Y[i] += alpha;  
  127.   }  
  128. }  
  129. /* 
  130. 函数 void *memcpy(void *dest, void *src, unsigned int count) 把src所指向 
  131. 的内存区域 copy到dest所指向的内存区域, count为块的大小 
  132. 表头文件: #include <string.h> 
  133. 定义函数: void *memcpy(void *dest, const void *src, size_t n) 
  134. 函数说明: memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'\0'而结束 
  135. 返回值:   返回指向dest的指针 
  136. */  
  137. template <typename Dtype>  
  138. void caffe_copy(const int N, const Dtype* X, Dtype* Y) {  
  139.   if (X != Y) {  
  140.     if (Caffe::mode() == Caffe::GPU) {  
  141. #ifndef CPU_ONLY  
  142.       // NOLINT_NEXT_LINE(caffe/alt_fn)  
  143.       CUDA_CHECK(cudaMemcpy(Y, X, sizeof(Dtype) * N, cudaMemcpyDefault));  
  144. #else  
  145.       NO_GPU;  
  146. #endif  
  147.     } else {  
  148.       memcpy(Y, X, sizeof(Dtype) * N);  // NOLINT(caffe/alt_fn)  
  149.     }  
  150.   }  
  151. }  
  152.   
  153. template void caffe_copy<int>(const int N, const int* X, int* Y);  
  154. template void caffe_copy<unsigned int>(const int N, const unsigned int* X,  
  155.     unsigned int* Y);  
  156. template void caffe_copy<float>(const int N, const float* X, float* Y);  
  157. template void caffe_copy<double>(const int N, const double* X, double* Y);  
  158. /* 
  159. 功能:X = alpha*X 
  160. N: X中element的个数 
  161. */  
  162. template <>  
  163. void caffe_scal<float>(const int N, const float alpha, float *X) {  
  164.   cblas_sscal(N, alpha, X, 1);  
  165. }  
  166.   
  167. template <>  
  168. void caffe_scal<double>(const int N, const double alpha, double *X) {  
  169.   cblas_dscal(N, alpha, X, 1);  
  170. }  
  171. /* 
  172. 功能:Y= alpha*X+beta*Y 
  173. */  
  174. template <>  
  175. void caffe_cpu_axpby<float>(const int N, const float alpha, const float* X,  
  176.                             const float beta, float* Y) {  
  177.   cblas_saxpby(N, alpha, X, 1, beta, Y, 1);  
  178. }  
  179.   
  180. template <>  
  181. void caffe_cpu_axpby<double>(const int N, const double alpha, const double* X,  
  182.                              const double beta, double* Y) {  
  183.   cblas_daxpby(N, alpha, X, 1, beta, Y, 1);  
  184. }  
  185. /* 
  186. 功能:这四个函数分别实现element-wise的加减乘除(y[i] = a[i] + - * \ b[i]) 
  187. */  
  188. template <>  
  189. void caffe_add<float>(const int n, const float* a, const float* b,  
  190.     float* y) {  
  191.   vsAdd(n, a, b, y);  
  192. }  
  193.   
  194. template <>  
  195. void caffe_add<double>(const int n, const double* a, const double* b,  
  196.     double* y) {  
  197.   vdAdd(n, a, b, y);  
  198. }  
  199.   
  200. template <>  
  201. void caffe_sub<float>(const int n, const float* a, const float* b,  
  202.     float* y) {  
  203.   vsSub(n, a, b, y);  
  204. }  
  205.   
  206. template <>  
  207. void caffe_sub<double>(const int n, const double* a, const double* b,  
  208.     double* y) {  
  209.   vdSub(n, a, b, y);  
  210. }  
  211.   
  212. template <>  
  213. void caffe_mul<float>(const int n, const float* a, const float* b,  
  214.     float* y) {  
  215.   vsMul(n, a, b, y);  
  216. }  
  217.   
  218. template <>  
  219. void caffe_mul<double>(const int n, const double* a, const double* b,  
  220.     double* y) {  
  221.   vdMul(n, a, b, y);  
  222. }  
  223.   
  224. template <>  
  225. void caffe_div<float>(const int n, const float* a, const float* b,  
  226.     float* y) {  
  227.   vsDiv(n, a, b, y);  
  228. }  
  229.   
  230. template <>  
  231. void caffe_div<double>(const int n, const double* a, const double* b,  
  232.     double* y) {  
  233.   vdDiv(n, a, b, y);  
  234. }  
  235. /* 
  236. 功能 : 同样是element-wise操作,分别是y[i] = a[i] ^ b, y[i] = a[i]^2,y[i] = exp(a[i] ),y[i] = |a[i] | 
  237. */  
  238. template <>  
  239. void caffe_powx<float>(const int n, const float* a, const float b,  
  240.     float* y) {  
  241.   vsPowx(n, a, b, y);  
  242. }  
  243.   
  244. template <>  
  245. void caffe_powx<double>(const int n, const double* a, const double b,  
  246.     double* y) {  
  247.   vdPowx(n, a, b, y);  
  248. }  
  249.   
  250. template <>  
  251. void caffe_sqr<float>(const int n, const float* a, float* y) {  
  252.   vsSqr(n, a, y);  
  253. }  
  254.   
  255. template <>  
  256. void caffe_sqr<double>(const int n, const double* a, double* y) {  
  257.   vdSqr(n, a, y);  
  258. }  
  259.   
  260. template <>  
  261. void caffe_exp<float>(const int n, const float* a, float* y) {  
  262.   vsExp(n, a, y);  
  263. }  
  264.   
  265. template <>  
  266. void caffe_exp<double>(const int n, const double* a, double* y) {  
  267.   vdExp(n, a, y);  
  268. }  
  269.   
  270. template <>  
  271. void caffe_log<float>(const int n, const float* a, float* y) {  
  272.   vsLn(n, a, y);  
  273. }  
  274.   
  275. template <>  
  276. void caffe_log<double>(const int n, const double* a, double* y) {  
  277.   vdLn(n, a, y);  
  278. }  
  279.   
  280. template <>  
  281. void caffe_abs<float>(const int n, const float* a, float* y) {  
  282.     vsAbs(n, a, y);  
  283. }  
  284.   
  285. template <>  
  286. void caffe_abs<double>(const int n, const double* a, double* y) {  
  287.     vdAbs(n, a, y);  
  288. }  
  289. /* 
  290. 功能:返回一个随机数 
  291. */  
  292. unsigned int caffe_rng_rand() {  
  293.   return (*caffe_rng())();  
  294. }  
  295. /* 
  296. 功能 : 返回 b 最大方向上可以表示的最接近的数值。 
  297. */  
  298. template <typename Dtype>  
  299. Dtype caffe_nextafter(const Dtype b) {  
  300.   return boost::math::nextafter<Dtype>(  
  301.       b, std::numeric_limits<Dtype>::max());  
  302. }  
  303.   
  304. template  
  305. float caffe_nextafter(const float b);  
  306.   
  307. template  
  308. double caffe_nextafter(const double b);  
  309.   
  310. template <typename Dtype>  
  311. void caffe_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r) {  
  312.   CHECK_GE(n, 0);  
  313.   CHECK(r);  
  314.   CHECK_LE(a, b);  
  315.   boost::uniform_real<Dtype> random_distribution(a, caffe_nextafter<Dtype>(b));  
  316.   boost::variate_generator<caffe::rng_t*, boost::uniform_real<Dtype> >  
  317.       variate_generator(caffe_rng(), random_distribution);  
  318.   for (int i = 0; i < n; ++i) {  
  319.     r[i] = variate_generator();  
  320.   }  
  321. }  
  322.   
  323. template  
  324. void caffe_rng_uniform<float>(const int n, const float a, const float b,  
  325.                               float* r);  
  326.   
  327. template  
  328. void caffe_rng_uniform<double>(const int n, const double a, const double b,  
  329.                                double* r);  
  330.   
  331. template <typename Dtype>  
  332. void caffe_rng_gaussian(const int n, const Dtype a,  
  333.                         const Dtype sigma, Dtype* r) {  
  334.   CHECK_GE(n, 0);  
  335.   CHECK(r);  
  336.   CHECK_GT(sigma, 0);  
  337.   boost::normal_distribution<Dtype> random_distribution(a, sigma);  
  338.   boost::variate_generator<caffe::rng_t*, boost::normal_distribution<Dtype> >  
  339.       variate_generator(caffe_rng(), random_distribution);  
  340.   for (int i = 0; i < n; ++i) {  
  341.     r[i] = variate_generator();  
  342.   }  
  343. }  
  344.   
  345. template  
  346. void caffe_rng_gaussian<float>(const int n, const float mu,  
  347.                                const float sigma, float* r);  
  348.   
  349. template  
  350. void caffe_rng_gaussian<double>(const int n, const double mu,  
  351.                                 const double sigma, double* r);  
  352.   
  353. template <typename Dtype>  
  354. void caffe_rng_bernoulli(const int n, const Dtype p, int* r) {  
  355.   CHECK_GE(n, 0);  
  356.   CHECK(r);  
  357.   CHECK_GE(p, 0);  
  358.   CHECK_LE(p, 1);  
  359.   boost::bernoulli_distribution<Dtype> random_distribution(p);  
  360.   boost::variate_generator<caffe::rng_t*, boost::bernoulli_distribution<Dtype> >  
  361.       variate_generator(caffe_rng(), random_distribution);  
  362.   for (int i = 0; i < n; ++i) {  
  363.     r[i] = variate_generator();  
  364.   }  
  365. }  
  366.   
  367. template  
  368. void caffe_rng_bernoulli<double>(const int n, const double p, int* r);  
  369.   
  370. template  
  371. void caffe_rng_bernoulli<float>(const int n, const float p, int* r);  
  372.   
  373. template <typename Dtype>  
  374. void caffe_rng_bernoulli(const int n, const Dtype p, unsigned int* r) {  
  375.   CHECK_GE(n, 0);  
  376.   CHECK(r);  
  377.   CHECK_GE(p, 0);  
  378.   CHECK_LE(p, 1);  
  379.   boost::bernoulli_distribution<Dtype> random_distribution(p);  
  380.   boost::variate_generator<caffe::rng_t*, boost::bernoulli_distribution<Dtype> >  
  381.       variate_generator(caffe_rng(), random_distribution);  
  382.   for (int i = 0; i < n; ++i) {  
  383.     r[i] = static_cast<unsigned int>(variate_generator());  
  384.   }  
  385. }  
  386.   
  387. template  
  388. void caffe_rng_bernoulli<double>(const int n, const double p, unsigned int* r);  
  389.   
  390. template  
  391. void caffe_rng_bernoulli<float>(const int n, const float p, unsigned int* r);  
  392.   
  393. template <>  
  394. float caffe_cpu_strided_dot<float>(const int n, const float* x, const int incx,  
  395.     const float* y, const int incy) {  
  396.   return cblas_sdot(n, x, incx, y, incy);  
  397. }  
  398. /* 
  399. 功能: 返回 vector X 和 vector Y 的内积。 
  400. incx, incy : 步长,即每隔incx 或 incy 个element 进行操作。 
  401. */  
  402. template <>  
  403. double caffe_cpu_strided_dot<double>(const int n, const double* x,  
  404.     const int incx, const double* y, const int incy) {  
  405.   return cblas_ddot(n, x, incx, y, incy);  
  406. }  
  407.   
  408. template <typename Dtype>  
  409. Dtype caffe_cpu_dot(const int n, const Dtype* x, const Dtype* y) {  
  410.   return caffe_cpu_strided_dot(n, x, 1, y, 1);  
  411. }  
  412.   
  413. template  
  414. float caffe_cpu_dot<float>(const int n, const float* x, const float* y);  
  415.   
  416. template  
  417. double caffe_cpu_dot<double>(const int n, const double* x, const double* y);  
  418. /* 
  419. 功能:返回 x 和 y 之间的海明距离。(两个等长字符串之间的海明距离 
  420. 是两个字符串对应位置的不同字符的个数。) 
  421. */  
  422. template <>  
  423. int caffe_cpu_hamming_distance<float>(const int n, const float* x,  
  424.                                   const float* y) {  
  425.   int dist = 0;  
  426.   for (int i = 0; i < n; ++i) {  
  427.     dist += __builtin_popcount(static_cast<uint32_t>(x[i]) ^  
  428.                                static_cast<uint32_t>(y[i]));  
  429.   }  
  430.   return dist;  
  431. }  
  432.   
  433. template <>  
  434. int caffe_cpu_hamming_distance<double>(const int n, const double* x,  
  435.                                    const double* y) {  
  436.   int dist = 0;  
  437.   for (int i = 0; i < n; ++i) {  
  438.     dist += __builtin_popcountl(static_cast<uint64_t>(x[i]) ^  
  439.                                 static_cast<uint64_t>(y[i]));  
  440.   }  
  441.   return dist;  
  442. }  
  443. /* 
  444. 功能:计算 vector x 的所有element的绝对值之和。 
  445. */  
  446. template <>  
  447. float caffe_cpu_asum<float>(const int n, const float* x) {  
  448.   return cblas_sasum(n, x, 1);  
  449. }  
  450.   
  451. template <>  
  452. double caffe_cpu_asum<double>(const int n, const double* x) {  
  453.   return cblas_dasum(n, x, 1);  
  454. }  
  455.   
  456. template <>  
  457. void caffe_cpu_scale<float>(const int n, const float alpha, const float *x,  
  458.                             float* y) {  
  459.   cblas_scopy(n, x, 1, y, 1);  
  460.   cblas_sscal(n, alpha, y, 1);  
  461. }  
  462.   
  463. template <>  
  464. void caffe_cpu_scale<double>(const int n, const double alpha, const double *x,  
  465.                              double* y) {  
  466.   cblas_dcopy(n, x, 1, y, 1);  
  467.   cblas_dscal(n, alpha, y, 1);  
  468. }  
  469.   
  470. }  // namespace caffe  

看一下cuda的设计技巧:

在common.hpp中用到一个宏定义CUDA_KERNEL_LOOP

#defineCUDA_KERNEL_LOOP(i,n) \
for(inti = blockIdx.x * blockDim.x + threadIdx.x;i < (n);i +=blockDim.x * gridDim.x)
先看看caffe采取的线程格和线程块的维数设计,还是从common.hpp可以看到
CAFFE_CUDA_NUM_THREADS
CAFFE_GET_BLOCKS(constintN)
明显都是一维的。
整理一下CUDA_KERNEL_LOOP格式看看,
for(inti = blockIdx.x * blockDim.x + threadIdx.x;i< (n);i+= blockDim.x * gridDim.x)
blockDim.x* gridDim.x表示的是该线程格所有线程的数量。
n表示核函数总共要处理的元素个数。
有时候,n会大于blockDim.x* gridDim.x,因此并不能一个线程处理一个元素。
由此通过上面的方法,让一个线程串行(for循环)处理几个元素。
再来看一下这个核函数的实现。
template<typename Dtype>
__global__void mul_kernel(const int n, const Dtype* a,
constDtype* b, Dtype* y)
{
  CUDA_KERNEL_LOOP(index,n)
  {
  y[index]= a[index] * b[index];
  }
}
就是算两个向量的点积了。由于向量的维数可能大于该kernel函数线程格的总线程数量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值