美文网首页
Caffe源码中math_functions文件分析

Caffe源码中math_functions文件分析

作者: RobertY | 来源:发表于2018-01-03 17:14 被阅读620次

    Caffe源码中有一些重要文件,这里介绍下math_functions文件。

    include文件:

    1. <glog/logging.h>:GLog库,它是google的一个开源的日志库,其使用可以参考:http://blog.csdn.net/fengbingchun/article/details/48768039

    2. <caffe/common.hpp>、<caffe/util/device_alternate.hpp>:这两个文件的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/54955236

    caffe/util/mkl_alternate.hpp文件:

    这个文件里包含两种库,一个是Intel MKL,一个是OpenBLAS,这里用的是OpenBLAS。如果商用Intel MKL是需要付费的,下面仅对Intel MKL进行简单介绍。

    Intel MKL(Math Kernel Library)即Intel数学核心函数库,它是一套高度优化和广泛线程安全的数学例程,专为需要极致性能的科学、工程及金融等领域的应用而设计。核心数学函数包括BLAS、LAPACK、ScaLAPACK、Sparse Solver、快速傅里叶变换、矢量数学及其它函数。它可以为当前及下一代英特尔处理器提供性能优化,包括更出色地与Microsoft Visual Studio、Eclipse和XCode相集成。英特尔MKL支持完全集成英特尔兼容性OpenMP运行时库,以实现更出色的Windows/Linux跨平台兼容性。

    关于OpenBLAS的介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/55509764

    在github/fengbingchun/Caffe_Test中<mkl_alternate.hpp>中走的是OpenBLAS分支。

    math_functions文件

    math_functions文件内函数:封装了一些基础的数学运算函数

    (1)、caffe_cpu_gemm:C=alphaAB+beta*C;

    (2)、caffe_cpu_gemv:y=alphaAx+beta*y;

    (3)、caffe_axpy:Y=alpha*X+Y;

    (4)、caffe_cpu_axpby:Y=alphaX+betaY;

    (5)、caffe_copy:从X中拷贝前N个元素到Y中;

    (6)、caffe_set:将X中的前N个元素置为alpha;

    (7)、caffe_add_scalar:给Y中的前N个元素分别加上常数alpha;

    (8)、caffe_scal:X = alpha*X;

    (9)、caffe_sqr/ caffe_exp/caffe_log/caffe_abs:会调用mkl_alternate.hpp中的vsSqr、vsExp、vsLn、vsAbs、vdSqr、vdExp、vdLn、vdAbs函数;

    (10)、caffe_add/caffe_sub/caffe_mul/caffe_div:会调用mkl_alternate.hpp中的vsAdd、vsSub、vsMul、vsDiv、vdAdd、vdSub、vdMul、vdDiv函数;

    (11)、caffe_powx:会调用mkl_alternate.hpp中的vsPowx和vdPowx函数;

    (12)、caffe_rng_rand:返回一个unsignedint类型的随机数;

    (13)、caffe_nextafter:在最大方向上,返回b可以表示的最接近的数值;

    (14)、caffe_rng_uniform:产生指定范围内的均匀分布随机数;

    (15)、caffe_rng_gaussian:产生高斯分布随机数;

    (16)、caffe_rng_bernoulli:产生伯努利分布随机数;

    (17)、caffe_cpu_dot:计算步长为1的内积;

    (18)、caffe_cpu_strided_dot:计算指定步长的内积;

    (19)、caffe_cpu_hamming_distance:计算x、y之间的海明距离;

    (20)、caffe_cpu_asum:计算向量x中前n个元素的绝对值之和;

    (21)、caffe_sign:类似于正负号函数,仅返回-1或1;

    (22)、caffe_cpu_scale:Y=alpha*X 。

    注: 本文的内容参考博客:http://blog.csdn.net/fengbingchun/article/details/56280708

    math_functions.hpp文件源码注释

    #ifndef CAFFE_UTIL_MATH_FUNCTIONS_H_
    #define CAFFE_UTIL_MATH_FUNCTIONS_H_
    
    #include <stdint.h>
    #include <cmath>  // for std::fabs and std::signbit
    
    #include "glog/logging.h"
    
    #include "caffe/common.hpp"
    #include "caffe/util/device_alternate.hpp"
    #include "caffe/util/mkl_alternate.hpp"
    
    namespace caffe {
    
    // Caffe gemm provides a simpler interface to the gemm functions, with the
    // limitation that the data has to be contiguous in memory.
    // C=alpha*A*B+beta*C
    // A,B,C 是输入矩阵(一维数组格式)
    // CblasRowMajor :数据是行主序的(二维数据也是用一维数组储存的)
    // TransA, TransB:是否要对A和B做转置操作(CblasTrans CblasNoTrans)
    // M: A、C 的行数
    // N: B、C 的列数
    // K: A 的列数, B 的行数
    // lda : A的列数(不做转置)行数(做转置)
    // ldb: B的列数(不做转置)行数(做转置)
    template <typename Dtype>
    void caffe_cpu_gemm(const CBLAS_TRANSPOSE TransA,
        const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K,
        const Dtype alpha, const Dtype* A, const Dtype* B, const Dtype beta,
        Dtype* C);
    
    // y=alpha*A*x+beta*y
    // 其中X和Y是向量,A 是矩阵
    // M:A 的行数
    // N:A 的列数
    // cblas_sgemv 中的 参数1 表示对X和Y的每个元素都进行操作
    template <typename Dtype>
    void caffe_cpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, const int N,
        const Dtype alpha, const Dtype* A, const Dtype* x, const Dtype beta,
        Dtype* y);
    
    // Y=alpha*X+Y
    // N:为X和Y中element的个数
    template <typename Dtype>
    void caffe_axpy(const int N, const Dtype alpha, const Dtype* X,
        Dtype* Y);
    
    // Y=alpha*X+beta*Y
    template <typename Dtype>
    void caffe_cpu_axpby(const int N, const Dtype alpha, const Dtype* X,
        const Dtype beta, Dtype* Y);
    
    // 从X中拷贝前N个元素到Y中
    template <typename Dtype>
    void caffe_copy(const int N, const Dtype *X, Dtype *Y);
    
    // 将X中的前N个元素置为alpha
    template <typename Dtype>
    void caffe_set(const int N, const Dtype alpha, Dtype *X);
    
    //  一般为新申请的内存做初始化,功能是将buffer所指向内存中的每个字节的内容全部设置为c指定的ASCII值, count为块的大小
    inline void caffe_memset(const size_t N, const int alpha, void* X) {
      memset(X, alpha, N);  // NOLINT(caffe/alt_fn)
    }
    
    // 给X中的前N个元素分别加上常数alpha
    template <typename Dtype>
    void caffe_add_scalar(const int N, const Dtype alpha, Dtype *X);
    
    // X = alpha*X
    // N: X中element的个数
    template <typename Dtype>
    void caffe_scal(const int N, const Dtype alpha, Dtype *X);
    
    template <typename Dtype>
    void caffe_sqr(const int N, const Dtype* a, Dtype* y);
    
    template <typename Dtype>
    void caffe_add(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    // 会调用mkl_alternate.hpp中的vsAdd、vsSub、vsMul、vsDiv、vdAdd、vdSub、vdMul、vdDiv函数
    // caffe_add、 caffe_sub、 caffe_mul、 caffe_div 函数
    // 这四个函数分别实现element-wise的加减乘除(y[i] = a[i] + - * \ b[i])
    template <typename Dtype>
    void caffe_div(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    // 会调用mkl_alternate.hpp中的vsPowx和vdPowx函数
    // caffe_powx、 caffe_sqr、 caffe_exp、 caffe_abs 函数
    // 同样是element-wise操作,分别是y[i] = a[i] ^ b, y[i] = a[i]^2,y[i] = exp(a[i] ),y[i] = |a[i]|
    template <typename Dtype>
    void caffe_powx(const int n, const Dtype* a, const Dtype b, Dtype* y);
    
    template <typename Dtype>
    void caffe_bound(const int n, const Dtype* a, const Dtype min,
        const Dtype max, Dtype* y);
    
    // 返回一个unsignedint类型的随机数
    unsigned int caffe_rng_rand();
    
    // 在最大方向上,返回b可以表示的最接近的数值
    template <typename Dtype>
    Dtype caffe_nextafter(const Dtype b);
    
    // 产生指定范围内的均匀分布随机数
    template <typename Dtype>
    void caffe_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r);
    
    // 产生高斯分布随机数
    template <typename Dtype>
    void caffe_rng_gaussian(const int n, const Dtype mu, const Dtype sigma,
                            Dtype* r);
    
    // 产生伯努利分布随机数
    template <typename Dtype>
    void caffe_rng_bernoulli(const int n, const Dtype p, int* r);
    
    template <typename Dtype>
    void caffe_rng_bernoulli(const int n, const Dtype p, unsigned int* r);
    
    template <typename Dtype>
    void caffe_exp(const int n, const Dtype* a, Dtype* y);
    
    template <typename Dtype>
    void caffe_log(const int n, const Dtype* a, Dtype* y);
    
    // 会调用mkl_alternate.hpp中的vsSqr、vsExp、vsLn、vsAbs、vdSqr、vdExp、vdLn、vdAbs函数
    template <typename Dtype>
    void caffe_abs(const int n, const Dtype* a, Dtype* y);
    
    // 计算步长为1的内积
    template <typename Dtype>
    Dtype caffe_cpu_dot(const int n, const Dtype* x, const Dtype* y);
    
    // 计算指定步长的内积
    // 功能: 返回 vector X 和 vector Y 的内积。
    // incx, incy : 步长,即每隔incx 或 incy 个element 进行操作。
    template <typename Dtype>
    Dtype caffe_cpu_strided_dot(const int n, const Dtype* x, const int incx,
        const Dtype* y, const int incy);
    
    // Returns the sum of the absolute values of the elements of vector x
    // 计算向量x中前n个元素的绝对值之和
    template <typename Dtype>
    Dtype caffe_cpu_asum(const int n, const Dtype* x);
    
    // the branchless, type-safe version from
    // http://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c
    // 类似于正负号函数,仅返回-1或1
    template<typename Dtype>
    inline int8_t caffe_sign(Dtype val) {
      return (Dtype(0) < val) - (val < Dtype(0));
    }
    
    // The following two macros are modifications of DEFINE_VSL_UNARY_FUNC
    //   in include/caffe/util/mkl_alternate.hpp authored by @Rowland Depp.
    // Please refer to commit 7e8ef25c7 of the boost-eigen branch.
    // Git cherry picking that commit caused a conflict hard to resolve and
    //   copying that file in convenient for code reviewing.
    // So they have to be pasted here temporarily.
    // 一元函数,类似于mkl_alternate.hpp中的宏DEFINE_VSL_UNARY_FUNC,包括:
    //  (1)、caffe_cpu_sign:正负号函数,输出-1、0、1;
    //  (2)、caffe_cpu_sgnbit:作用类似于std::signbit,static_cast<bool>((std::signbit)(x));x为负数输出为1,其它输出为0;
    //  (3)、caffe_cpu_fabs:取绝对值,作用类似于std::fabs。
    #define DEFINE_CAFFE_CPU_UNARY_FUNC(name, operation) \
      template<typename Dtype> \
      void caffe_cpu_##name(const int n, const Dtype* x, Dtype* y) { \
        CHECK_GT(n, 0); CHECK(x); CHECK(y); \
        for (int i = 0; i < n; ++i) { \
          operation; \
        } \
      }
    
    // output is 1 for the positives, 0 for zero, and -1 for the negatives
    DEFINE_CAFFE_CPU_UNARY_FUNC(sign, y[i] = caffe_sign<Dtype>(x[i]));
    
    // This returns a nonzero value if the input has its sign bit set.
    // The name sngbit is meant to avoid conflicts with std::signbit in the macro.
    // The extra parens are needed because CUDA < 6.5 defines signbit as a macro,
    // and we don't want that to expand here when CUDA headers are also included.
    DEFINE_CAFFE_CPU_UNARY_FUNC(sgnbit, \
        y[i] = static_cast<bool>((std::signbit)(x[i])));
    
    DEFINE_CAFFE_CPU_UNARY_FUNC(fabs, y[i] = std::fabs(x[i]));
    
    // Y=alpha*X
    template <typename Dtype>
    void caffe_cpu_scale(const int n, const Dtype alpha, const Dtype *x, Dtype* y);
    
    #ifndef CPU_ONLY  // GPU
    
    // Decaf gpu gemm provides an interface that is almost the same as the cpu
    // gemm function - following the c convention and calling the fortran-order
    // gpu code under the hood.
    template <typename Dtype>
    void caffe_gpu_gemm(const CBLAS_TRANSPOSE TransA,
        const CBLAS_TRANSPOSE TransB, const int M, const int N, const int K,
        const Dtype alpha, const Dtype* A, const Dtype* B, const Dtype beta,
        Dtype* C);
    
    template <typename Dtype>
    void caffe_gpu_gemv(const CBLAS_TRANSPOSE TransA, const int M, const int N,
        const Dtype alpha, const Dtype* A, const Dtype* x, const Dtype beta,
        Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_axpy(const int N, const Dtype alpha, const Dtype* X,
        Dtype* Y);
    
    template <typename Dtype>
    void caffe_gpu_axpby(const int N, const Dtype alpha, const Dtype* X,
        const Dtype beta, Dtype* Y);
    
    void caffe_gpu_memcpy(const size_t N, const void *X, void *Y);
    
    template <typename Dtype>
    void caffe_gpu_set(const int N, const Dtype alpha, Dtype *X);
    
    inline void caffe_gpu_memset(const size_t N, const int alpha, void* X) {
    #ifndef CPU_ONLY
      CUDA_CHECK(cudaMemset(X, alpha, N));  // NOLINT(caffe/alt_fn)
    #else
      NO_GPU;
    #endif
    }
    
    template <typename Dtype>
    void caffe_gpu_add_scalar(const int N, const Dtype alpha, Dtype *X);
    
    template <typename Dtype>
    void caffe_gpu_scal(const int N, const Dtype alpha, Dtype *X);
    
    template <typename Dtype>
    void caffe_gpu_add(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_sub(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_mul(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_div(const int N, const Dtype* a, const Dtype* b, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_abs(const int n, const Dtype* a, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_exp(const int n, const Dtype* a, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_log(const int n, const Dtype* a, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_powx(const int n, const Dtype* a, const Dtype b, Dtype* y);
    
    // caffe_gpu_rng_uniform with two arguments generates integers in the range
    // [0, UINT_MAX].
    void caffe_gpu_rng_uniform(const int n, unsigned int* r);
    
    // caffe_gpu_rng_uniform with four arguments generates floats in the range
    // (a, b] (strictly greater than a, less than or equal to b) due to the
    // specification of curandGenerateUniform.  With a = 0, b = 1, just calls
    // curandGenerateUniform; with other limits will shift and scale the outputs
    // appropriately after calling curandGenerateUniform.
    template <typename Dtype>
    void caffe_gpu_rng_uniform(const int n, const Dtype a, const Dtype b, Dtype* r);
    
    template <typename Dtype>
    void caffe_gpu_rng_gaussian(const int n, const Dtype mu, const Dtype sigma,
                                Dtype* r);
    
    template <typename Dtype>
    void caffe_gpu_rng_bernoulli(const int n, const Dtype p, int* r);
    
    template <typename Dtype>
    void caffe_gpu_dot(const int n, const Dtype* x, const Dtype* y, Dtype* out);
    
    template <typename Dtype>
    void caffe_gpu_asum(const int n, const Dtype* x, Dtype* y);
    
    template<typename Dtype>
    void caffe_gpu_sign(const int n, const Dtype* x, Dtype* y);
    
    template<typename Dtype>
    void caffe_gpu_sgnbit(const int n, const Dtype* x, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_fabs(const int n, const Dtype* x, Dtype* y);
    
    template <typename Dtype>
    void caffe_gpu_scale(const int n, const Dtype alpha, const Dtype *x, Dtype* y);
    
    #define DEFINE_AND_INSTANTIATE_GPU_UNARY_FUNC(name, operation) \
    template<typename Dtype> \
    __global__ void name##_kernel(const int n, const Dtype* x, Dtype* y) { \
      CUDA_KERNEL_LOOP(index, n) { \
        operation; \
      } \
    } \
    template <> \
    void caffe_gpu_##name<float>(const int n, const float* x, float* y) { \
      /* NOLINT_NEXT_LINE(whitespace/operators) */ \
      name##_kernel<float><<<CAFFE_GET_BLOCKS(n), CAFFE_CUDA_NUM_THREADS>>>( \
          n, x, y); \
    } \
    template <> \
    void caffe_gpu_##name<double>(const int n, const double* x, double* y) { \
      /* NOLINT_NEXT_LINE(whitespace/operators) */ \
      name##_kernel<double><<<CAFFE_GET_BLOCKS(n), CAFFE_CUDA_NUM_THREADS>>>( \
          n, x, y); \
    }
    
    #endif  // !CPU_ONLY
    
    }  // namespace caffe
    
    #endif  // CAFFE_UTIL_MATH_FUNCTIONS_H_
    
    

    相关文章

      网友评论

          本文标题:Caffe源码中math_functions文件分析

          本文链接:https://www.haomeiwen.com/subject/lufknxtx.html