如果遇到框架不支持的Op,用戶可以自行創建。MACE提供了非常友好的創建自定義Op的操作,只需按照以下步驟執行。
1. 定義Op類
創建新文件mace/ops/my_custom_op.h
,并在文件中定義新的類,例如MyCustomOp
,代碼如下
#ifndef MACE_OPS_MY_CUSTOM_OP_H_
#define MACE_OPS_MY_CUSTOM_OP_H_
#include "mace/core/operator.h"
#include "mace/kernels/my_custom_op.h"
namespace mace {
namespace ops {
template <DeviceType D, typename T>
class MyCustomOp : public Operator<D, T> {
public:
MyCustomOp(const OperatorDef &op_def, Workspace *ws)
: Operator<D, T>(op_def, ws),
functor_() {}
bool Run(StatsFuture *future) override {
const Tensor *input = this->Input(INPUT);
Tensor *output = this->Output(OUTPUT);
functor_(input, output, future);
return true;
}
protected:
OP_INPUT_TAGS(INPUT);
OP_OUTPUT_TAGS(OUTPUT);
private:
kernels::MyCustomOpFunctor<D, T> functor_;
};
} // namespace ops
} // namespace mace
#endif // MACE_OPS_MY_CUSTOM_OP_H_
2. 注冊Op類
創建新文件 mace/ops/my_custom_op.cc
,并在其中注冊新建的類,代碼如下。從代碼里可以看出,注冊代碼提供了CPU和GPU的兩種實現,其中GPU版本包含float
和half
的兩種數據支持。
除此之外,還需要在mace/core/operator.cc
文件的namespace ops
下按模板添加注冊代碼extern void Register_My_Custom_Op(OperatorRegistry *op_registry);
,同時在OperatorRegistry()
構造函數中添加ops::Register_My_Custom_Op(this);
#include "mace/ops/my_custom_op.h"
namespace mace {
namespace ops {
void Register_My_Custom_Op(OperatorRegistry *op_registry) {
REGISTER_OPERATOR(op_registry, OpKeyBuilder("my_custom_op")
.Device(DeviceType::CPU)
.TypeConstraint<float>("T")
.Build(),
Custom_Op<DeviceType::CPU, float>);
REGISTER_OPERATOR(op_registry, OpKeyBuilder("my_custom_op")
.Device(DeviceType::OPENCL)
.TypeConstraint<float>("T")
.Build(),
Custom_Op<DeviceType::OPENCL, float>);
REGISTER_OPERATOR(op_registry, OpKeyBuilder("my_custom_op")
.Device(DeviceType::OPENCL)
.TypeConstraint<half>("T")
.Build(),
Custom_Op<DeviceType::OPENCL, half>);
}
} // namespace ops
} // namespace mace
3. 實現Op的核心代碼
注冊完成Op后,需要實現其核心代碼。創建文件mace/kernels/my_custom_op.h
,這個文件文件實現的是CPU版本的代碼。也可以選擇實現OpenCL版本代碼,這時,需要創建兩個文件:mace/kernels/opencl/my_custom_op_opencl.cc
和 mace/kernels/opencl/cl/ my_custom_op.cl
。也可以對CPU版本的實現進行NEON指令集優化。