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

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

梳理caffe代码math_functions相关推荐

  1. 梳理caffe代码layer(五)

    Layer(层)是Caffe中最庞大最繁杂的模块.由于Caffe强调模块化设计,因此只允许每个layer完成一类特定的计算,例如convolution操作.pooling.非线性变换.内积运算,以及数 ...

  2. 错误 error C2220: 警告被视为错误 - 没有生成“object”文件 (..\..\src\caffe\util\math_functions.cpp)

    在进行Caffe安装时,遇到此问题(错误1error C2220: 警告被视为错误 - 没有生成"object"文件 (..\..\src\caffe\util\math_func ...

  3. Caffe 代码解读之全连接层 inner product layer

    今天来看一下全连接层的代码.首先,我们要知道全连接层在做什么.先来看一下caffe的官方文档,介绍如下: 可以看到,输入为n c h w,输出为n c_o 1 1 那么,它究竟做了什么那? 假设con ...

  4. caffe代码阅读8: Data_layers的实现细节(各个数据读取层的实现细节) 2016.3.25-28

    一.Data_layers.hpp文件的作用简介 Data_layers.hpp在目前caffe的master分支中已经不能存在了,分散到各个文件中去了. 而之前是存在于cafferoot\inclu ...

  5. Caffe 代码解读之 softmax layer

    转自http://zhangliliang.com/2015/05/27/about-caffe-code-softmax-loss-layer/ 关于softmax回归 看过最清晰的关于softma ...

  6. Caffe代码导读(5):对数据集进行Testing

    转载自: Caffe代码导读(5):对数据集进行Testing - 卜居 - 博客频道 - CSDN.NET http://blog.csdn.net/kkk584520/article/detail ...

  7. Caffe代码导读(4):数据集准备

    转载自: Caffe代码导读(4):数据集准备 - 卜居 - 博客频道 - CSDN.NET http://blog.csdn.net/kkk584520/article/details/416492 ...

  8. Caffe代码导读(1):Protobuf例子

    转载自: Caffe代码导读(1):Protobuf例子 - 卜居 - 博客频道 - CSDN.NET http://blog.csdn.net/kkk584520/article/details/4 ...

  9. Caffe代码导读(0):路线图

    转载自: Caffe代码导读(0):路线图 - 卜居 - 博客频道 - CSDN.NET http://blog.csdn.net/kkk584520/article/details/41681085 ...

最新文章

  1. 在桌面右键菜单,停止工作,并提示“资源管理器停止工作”等情况。
  2. 服务器市场严酷竞争下的众生相
  3. AD域管理系列(6)-- 常见处理
  4. 【0729作业】随机生成20个手机号码
  5. Android Studio之gradle的配置与介绍
  6. 排序算法之low B三人组
  7. LVS(11)——wrr
  8. python3打包exe运行没反应_python selenium运行,打包exe常见问题解决方法
  9. 【剑指offer】面试题10- II:青蛙跳台阶问题(Java)
  10. oracle 01304,关于ORA-01034和ORA-27101的解决方法
  11. 第一章 ---- Spring IOC
  12. SparkSQL简介
  13. C语言航空订票系统课程设计
  14. SonarQube代码审查工具
  15. 烽火HG680-KB及其他5款Hi3798MV310芯片盒子刷机固件及教程(当贝桌面)
  16. Vue-网页版音乐播放器实现(网易云音乐源)
  17. 小红书一个月快速涨十万粉的秘籍
  18. 短信通知-阿里大鱼 申请AK 发送Until
  19. 3.6Python之sys模块
  20. 圆面积计算公式,这样理解起来超简单!

热门文章

  1. 关于电工产品的执行标准与认证
  2. 经典视频超分论文总结2
  3. 磁带库加入新磁带(backup exec)
  4. 新品亮相丨美格智能高性能Cat.1 bis模组SLM332X上市
  5. 非法买卖数字证书,这些人被抓了
  6. Android官方模拟器root,Android Studio 自带模拟器获取root权限
  7. Ehcache-xsi:noNamespaceSchemaLocation连接获取错误
  8. processflow利用drawio实现多人协作画流程图功能
  9. iOS自定义表情的实现
  10. 激活UltraEdit 的方法