BMCPU 插件使用¶
BMCPU提供用户对深度学习的一些TPU不能实现的layer进行CPU编程,并插入到 Caffe/TensorFlow/MxNet/PyTorch等框架的深度学习神经网络中。 插入CPU layer的步骤请见BMNETC/BMNETT/BMNETM/BMNETP说明。 这里介绍用户如何进行CPU Layer编程。
环境构建¶
BMSDK中提供用户CPU Layer的开发环境(bmusercpu),用户可以拷贝该文件夹,并在这个文件夹内开发。 bmusercpu里面提供Makefile和example,该环境面向C++/C编程。用户需要修改Makefile.def里面的 INSTALL_LIB_PATH和INSTALL_INCLUDE_PATH。随着BMSDK的升级,用户CPU Layer的开发环境不受影响, 无需再次拷贝bmusercpu文件夹。
编程说明¶
编程环境中已创建好user cpu layer编程的工厂模式,详细可见user_cpu_layer_factory.h。 所以用户只需要按照工厂模式增加新的CPU Layer代码,以及在user_bmcpu_common.h中增加新CPU Layer 的参数。
这里以example来详细说明。user_bmcpu_common.h中已经有一个exp_layer的CPU Layer参数。当然用户可以删除该 example。添加新CPU Layer的参数设置如下:
typedef enum { USER_EXP = 0, USER_CPU_UNKNOW } USER_CPU_LAYER_TYPE_T; typedef struct user_cpu_exp_param { float inner_scale_; float outer_scale_; } user_cpu_exp_param_t; typedef struct user_cpu_param { int op_type; /* USER_CPU_LAYER_TYPE_T */ union { user_cpu_exp_param_t exp; /* notice: please add other cpu layer param here */ }u; }user_cpu_param_t;
首先需要在USER_CPU_LAYER_TYPE_T这个枚举参数中加入新CPU Layer type编号,这里要求编号要从0开始按顺序设置; 然后定义用户CPU Layer的参数,如user_cpu_exp_param_t;最后在user_cpu_param_t的union中加入用户CPU Layer的 structure参数。这样我们就完成了一个用户CPU Layer的参数设置。
接着按照工厂模式编写一个用户CPU Layer的代码,这里以user_cpu_layer.h和user_cpu_layer.cpp为例。 user_cpu_exp_layer.h代码如下:
#ifndef _USER_CPU_EXP_LAYER_H #define _USER_CPU_EXP_LAYER_H #include "user_cpu_layer.h" namespace usercpu { /* * notice: define new cpu layer, must like xxx_layer * */ class cpu_exp_layer : public user_cpu_layer { public: explicit cpu_exp_layer() {} virtual ~cpu_exp_layer() {} /* dowork */ //virtual void process(); int process(void *parm); void setParam(void *param); virtual string get_layer_name () const { return "USEREXP"; } protected: float inner_scale_; float outer_scale_; }; } /* namespace usercpu */ #endif /* _USER_CPU_EXP_LAYER_H */
user_cpu_exp_layer.cpp代码如下:
#include "user_cpu_exp_layer.h" namespace usercpu { int cpu_exp_layer::process(void *param) { setParam(param); /* Code From caffe */ const float* bottom_data = input_tensors_[0]; float* top_data = output_tensors_[0]; const int count = input_shapes_[0][0] * input_shapes_[0][1] * input_shapes_[0][2] * input_shapes_[0][3]; //Dtype negative_slope = this->layer_param_.exp_param().negative_slope(); //float negative_slope = 0.0f; for (int i = 0; i < count; ++i) { top_data[i] = exp(bottom_data[i] * inner_scale_) * outer_scale_; } printf("user define cpu exp layer, process success!\n"); return 0; } void cpu_exp_layer::setParam(void *param) { layer_param_ = param; user_cpu_exp_param_t *exp_param = (user_cpu_exp_param_t*)layer_param_; inner_scale_ = exp_param->inner_scale_; outer_scale_ = exp_param->outer_scale_; } /* must register user layer * in macro cpu_test##_layer == class cpu_test_layer * */ REGISTER_USER_CPULAYER_CLASS(USER_EXP, cpu_exp) }
其中protected中为该CPU Layer需要的参数,setParam函数用于将void* param指针指向参数赋值给该CPU Layer,param 对应的数据结构对应user_bmcpu_common.h中定义的structure。process函数则是改CPU Layer的实际处理过程。
编译说明¶
用户开发环境中提供的Makefile和Makefile.def,所以用户直接make即可,通过后make install来安装。 这里将生成libusercpu.so,并和必须的.h文件一起安装到Makefile.def制定的安装目录中。 生成的libusercpu.so将作为CPU后端供bmcompiler和bmruntime一起使用。
若用户使用的是SoC,如SA服务器或者SE小盒子,则需要将文件夹copy到SoC的操作系统中,用SoC中的ARM编译器进行编译, 操作相同,不同的是install时可能需要设置Makefile.def里的安装路径。
调试优化¶
用户需要调试的话,可以自行搭建单元测试环境,对用户的CPU Layer进行测试。 若用户需要做性能优化等,则直接在该编程环境下修改即可。