提交 50ba205d 编写于 作者: L Liu Yiqun

Merge branch 'develop' into core_fix_openblas_threads

...@@ -70,7 +70,7 @@ RUN localedef -i en_US -f UTF-8 en_US.UTF-8 ...@@ -70,7 +70,7 @@ RUN localedef -i en_US -f UTF-8 en_US.UTF-8
# specify sphinx version as 1.5.6 and remove -U option for [pip install -U # specify sphinx version as 1.5.6 and remove -U option for [pip install -U
# sphinx-rtd-theme] since -U option will cause sphinx being updated to newest # sphinx-rtd-theme] since -U option will cause sphinx being updated to newest
# version(1.7.1 for now), which causes building documentation failed. # version(1.7.1 for now), which causes building documentation failed.
RUN pip install --upgrade pip==9.0.3 && \ RUN easy_install -U pip && \
pip install -U wheel && \ pip install -U wheel && \
pip install -U docopt PyYAML sphinx==1.5.6 && \ pip install -U docopt PyYAML sphinx==1.5.6 && \
pip install sphinx-rtd-theme==0.1.9 recommonmark pip install sphinx-rtd-theme==0.1.9 recommonmark
......
...@@ -159,6 +159,7 @@ def run_benchmark(model, args): ...@@ -159,6 +159,7 @@ def run_benchmark(model, args):
paddle.dataset.mnist.train(), batch_size=args.batch_size) paddle.dataset.mnist.train(), batch_size=args.batch_size)
accuracy = fluid.metrics.Accuracy() accuracy = fluid.metrics.Accuracy()
train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name)
iters, num_samples, start_time = 0, 0, time.time() iters, num_samples, start_time = 0, 0, time.time()
for pass_id in range(args.pass_num): for pass_id in range(args.pass_num):
accuracy.reset() accuracy.reset()
...@@ -175,17 +176,20 @@ def run_benchmark(model, args): ...@@ -175,17 +176,20 @@ def run_benchmark(model, args):
y_data = np.array(map(lambda x: x[1], data)).astype("int64") y_data = np.array(map(lambda x: x[1], data)).astype("int64")
y_data = y_data.reshape([len(y_data), 1]) y_data = y_data.reshape([len(y_data), 1])
outs = exe.run( outs = train_exe.run(
fluid.default_main_program(),
feed={"pixel": img_data, feed={"pixel": img_data,
"label": y_data}, "label": y_data},
fetch_list=[avg_cost, batch_acc, batch_size_tensor] fetch_list=[
avg_cost.name, batch_acc.name, batch_size_tensor.name
]
) # The accuracy is the accumulation of batches, but not the current batch. ) # The accuracy is the accumulation of batches, but not the current batch.
accuracy.update(value=outs[1], weight=outs[2]) accuracy.update(
value=np.array(np.mean(outs[1])),
weight=np.mean(np.array(outs[2])))
iters += 1 iters += 1
num_samples += len(y_data) num_samples += len(y_data)
loss = np.array(outs[0]) loss = np.mean(np.array(outs[0]))
acc = np.array(outs[1]) acc = np.mean(np.array(outs[1]))
train_losses.append(loss) train_losses.append(loss)
train_accs.append(acc) train_accs.append(acc)
print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" % print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" %
......
...@@ -241,6 +241,7 @@ def run_benchmark(model, args): ...@@ -241,6 +241,7 @@ def run_benchmark(model, args):
exe = fluid.Executor(place) exe = fluid.Executor(place)
exe.run(fluid.default_startup_program()) exe.run(fluid.default_startup_program())
accuracy = fluid.average.WeightedAverage() accuracy = fluid.average.WeightedAverage()
train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name)
if args.use_fake_data: if args.use_fake_data:
data = train_reader().next() data = train_reader().next()
image = np.array(map(lambda x: x[0].reshape(dshape), data)).astype( image = np.array(map(lambda x: x[0].reshape(dshape), data)).astype(
...@@ -264,14 +265,17 @@ def run_benchmark(model, args): ...@@ -264,14 +265,17 @@ def run_benchmark(model, args):
data)).astype('float32') data)).astype('float32')
label = np.array(map(lambda x: x[1], data)).astype('int64') label = np.array(map(lambda x: x[1], data)).astype('int64')
label = label.reshape([-1, 1]) label = label.reshape([-1, 1])
loss, acc, weight = exe.run( loss, acc, weight = train_exe.run(
fluid.default_main_program(),
feed={'data': image, feed={'data': image,
'label': label}, 'label': label},
fetch_list=[avg_cost, batch_acc, batch_size_tensor]) fetch_list=[
avg_cost.name, batch_acc.name, batch_size_tensor.name
])
iters += 1 iters += 1
num_samples += len(label) num_samples += len(label)
accuracy.add(value=acc, weight=weight) accuracy.add(value=np.array(np.mean(acc)), weight=np.mean(weight))
loss = np.mean(np.array(loss))
acc = np.mean(np.array(acc))
train_losses.append(loss) train_losses.append(loss)
train_accs.append(acc) train_accs.append(acc)
print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" % print("Pass: %d, Iter: %d, Loss: %f, Accuracy: %f" %
......
...@@ -169,6 +169,7 @@ def main(): ...@@ -169,6 +169,7 @@ def main():
iters, num_samples, start_time = 0, 0, time.time() iters, num_samples, start_time = 0, 0, time.time()
accuracy = fluid.average.WeightedAverage() accuracy = fluid.average.WeightedAverage()
train_exe = fluid.ParallelExecutor(use_cuda=True, loss_name=avg_cost.name)
for pass_id in range(args.pass_num): for pass_id in range(args.pass_num):
accuracy.reset() accuracy.reset()
train_accs = [] train_accs = []
...@@ -184,14 +185,17 @@ def main(): ...@@ -184,14 +185,17 @@ def main():
y_data = np.array(map(lambda x: x[1], data)).astype("int64") y_data = np.array(map(lambda x: x[1], data)).astype("int64")
y_data = y_data.reshape([-1, 1]) y_data = y_data.reshape([-1, 1])
loss, acc, weight = exe.run( loss, acc, weight = train_exe.run(
fluid.default_main_program(),
feed={"pixel": img_data, feed={"pixel": img_data,
"label": y_data}, "label": y_data},
fetch_list=[avg_cost, batch_acc, batch_size_tensor]) fetch_list=[
accuracy.add(value=acc, weight=weight) avg_cost.name, batch_acc.name, batch_size_tensor.name
])
accuracy.add(value=np.array(np.mean(acc)), weight=np.mean(weight))
iters += 1 iters += 1
num_samples += len(y_data) num_samples += len(y_data)
loss = np.mean(np.array(loss))
acc = np.mean(np.array(acc))
print( print(
"Pass = %d, Iter = %d, Loss = %f, Accuracy = %f" % "Pass = %d, Iter = %d, Loss = %f, Accuracy = %f" %
(pass_id, iters, loss, acc) (pass_id, iters, loss, acc)
......
...@@ -24,7 +24,7 @@ set(BOOST_PROJECT "extern_boost") ...@@ -24,7 +24,7 @@ set(BOOST_PROJECT "extern_boost")
# So we use 1.41.0 here. # So we use 1.41.0 here.
set(BOOST_VER "1.41.0") set(BOOST_VER "1.41.0")
set(BOOST_TAR "boost_1_41_0") set(BOOST_TAR "boost_1_41_0")
set(BOOST_URL "http://paddlepaddledeps.bj.bcebos.com/${BOOST_TAR}.tar.gz") set(BOOST_URL "http://paddlepaddledeps.cdn.bcebos.com/${BOOST_TAR}.tar.gz")
set(BOOST_SOURCES_DIR ${THIRD_PARTY_PATH}/boost) set(BOOST_SOURCES_DIR ${THIRD_PARTY_PATH}/boost)
set(BOOST_DOWNLOAD_DIR "${BOOST_SOURCES_DIR}/src/${BOOST_PROJECT}") set(BOOST_DOWNLOAD_DIR "${BOOST_SOURCES_DIR}/src/${BOOST_PROJECT}")
set(BOOST_INCLUDE_DIR "${BOOST_DOWNLOAD_DIR}/${BOOST_TAR}" CACHE PATH "boost include directory." FORCE) set(BOOST_INCLUDE_DIR "${BOOST_DOWNLOAD_DIR}/${BOOST_TAR}" CACHE PATH "boost include directory." FORCE)
......
...@@ -21,11 +21,12 @@ else() ...@@ -21,11 +21,12 @@ else()
ExternalProject_Add( ExternalProject_Add(
extern_eigen3 extern_eigen3
${EXTERNAL_PROJECT_LOG_ARGS} ${EXTERNAL_PROJECT_LOG_ARGS}
GIT_REPOSITORY "https://github.com/RLovelett/eigen.git" GIT_REPOSITORY "https://github.com/eigenteam/eigen-git-mirror"
# eigen on cuda9.1 missing header of math_funtions.hpp # eigen on cuda9.1 missing header of math_funtions.hpp
# https://stackoverflow.com/questions/43113508/math-functions-hpp-not-found-when-using-cuda-with-eigen # https://stackoverflow.com/questions/43113508/math-functions-hpp-not-found-when-using-cuda-with-eigen
GIT_TAG 917060c364181f33a735dc023818d5a54f60e54c GIT_TAG 917060c364181f33a735dc023818d5a54f60e54c
PREFIX ${EIGEN_SOURCE_DIR} PREFIX ${EIGEN_SOURCE_DIR}
DOWNLOAD_NAME "eigen"
UPDATE_COMMAND "" UPDATE_COMMAND ""
CONFIGURE_COMMAND "" CONFIGURE_COMMAND ""
BUILD_COMMAND "" BUILD_COMMAND ""
......
...@@ -53,11 +53,9 @@ ExternalProject_Add( ...@@ -53,11 +53,9 @@ ExternalProject_Add(
${EXTERNAL_PROJECT_LOG_ARGS} ${EXTERNAL_PROJECT_LOG_ARGS}
DEPENDS ${MKLDNN_DEPENDS} DEPENDS ${MKLDNN_DEPENDS}
GIT_REPOSITORY "https://github.com/01org/mkl-dnn.git" GIT_REPOSITORY "https://github.com/01org/mkl-dnn.git"
GIT_TAG "v0.14" GIT_TAG "db3424ad44901513c03a1ea31ccaacdf633fbe9f"
PREFIX ${MKLDNN_SOURCES_DIR} PREFIX ${MKLDNN_SOURCES_DIR}
UPDATE_COMMAND "" UPDATE_COMMAND ""
# Patch MKLDNN to compile with gcc 4.8, the related issue is in intel/mkl-dnn#237.
PATCH_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/patches/mkldnn.hpp ${MKLDNN_SOURCES_DIR}/src/extern_mkldnn/include/mkldnn.hpp
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${MKLDNN_INSTALL_DIR} CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${MKLDNN_INSTALL_DIR}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
CMAKE_ARGS -DMKLROOT=${MKLML_ROOT} CMAKE_ARGS -DMKLROOT=${MKLML_ROOT}
......
...@@ -28,7 +28,7 @@ INCLUDE(ExternalProject) ...@@ -28,7 +28,7 @@ INCLUDE(ExternalProject)
SET(MKLML_PROJECT "extern_mklml") SET(MKLML_PROJECT "extern_mklml")
SET(MKLML_VER "mklml_lnx_2018.0.3.20180406") SET(MKLML_VER "mklml_lnx_2018.0.3.20180406")
SET(MKLML_URL "http://paddlepaddledeps.bj.bcebos.com/${MKLML_VER}.tgz") SET(MKLML_URL "http://paddlepaddledeps.cdn.bcebos.com/${MKLML_VER}.tgz")
SET(MKLML_SOURCE_DIR "${THIRD_PARTY_PATH}/mklml") SET(MKLML_SOURCE_DIR "${THIRD_PARTY_PATH}/mklml")
SET(MKLML_DOWNLOAD_DIR "${MKLML_SOURCE_DIR}/src/${MKLML_PROJECT}") SET(MKLML_DOWNLOAD_DIR "${MKLML_SOURCE_DIR}/src/${MKLML_PROJECT}")
SET(MKLML_DST_DIR "mklml") SET(MKLML_DST_DIR "mklml")
......
...@@ -47,8 +47,6 @@ ExternalProject_Add( ...@@ -47,8 +47,6 @@ ExternalProject_Add(
-DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPY_INSTALL_DIR}/lib -DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPY_INSTALL_DIR}/lib
-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON
-DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE} -DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE}
BUILD_COMMAND make -j8
INSTALL_COMMAND make install
) )
add_library(snappy STATIC IMPORTED GLOBAL) add_library(snappy STATIC IMPORTED GLOBAL)
......
...@@ -46,8 +46,6 @@ ExternalProject_Add( ...@@ -46,8 +46,6 @@ ExternalProject_Add(
-DCMAKE_INSTALL_PREFIX:PATH=${SNAPPYSTREAM_INSTALL_DIR} -DCMAKE_INSTALL_PREFIX:PATH=${SNAPPYSTREAM_INSTALL_DIR}
-DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPYSTREAM_INSTALL_DIR}/lib -DCMAKE_INSTALL_LIBDIR:PATH=${SNAPPYSTREAM_INSTALL_DIR}/lib
-DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE} -DCMAKE_BUILD_TYPE:STRING=${THIRD_PARTY_BUILD_TYPE}
BUILD_COMMAND make -j8
INSTALL_COMMAND make install
DEPENDS snappy DEPENDS snappy
) )
......
...@@ -98,6 +98,14 @@ elseif (WITH_MKLML) ...@@ -98,6 +98,14 @@ elseif (WITH_MKLML)
) )
endif() endif()
if(WITH_MKLDNN)
set(dst_dir "${CMAKE_INSTALL_PREFIX}/third_party/install/mkldnn")
copy(mkldnn_lib
SRCS ${MKLDNN_INC_DIR} ${MKLDNN_SHARED_LIB}
DSTS ${dst_dir} ${dst_dir}/lib
)
endif()
if(NOT MOBILE_INFERENCE AND NOT RPI) if(NOT MOBILE_INFERENCE AND NOT RPI)
set(dst_dir "${CMAKE_INSTALL_PREFIX}/third_party/install/snappy") set(dst_dir "${CMAKE_INSTALL_PREFIX}/third_party/install/snappy")
copy(snappy_lib copy(snappy_lib
...@@ -148,4 +156,10 @@ copy(string_lib ...@@ -148,4 +156,10 @@ copy(string_lib
DSTS ${dst_dir}/${module} ${dst_dir}/${module}/tinyformat DSTS ${dst_dir}/${module} ${dst_dir}/${module}/tinyformat
) )
set(module "pybind")
copy(pybind_lib
SRCS ${CMAKE_CURRENT_BINARY_DIR}/paddle/fluid/${module}/pybind.h
DSTS ${dst_dir}/${module}
)
add_custom_target(inference_lib_dist DEPENDS ${inference_lib_dist_dep}) add_custom_target(inference_lib_dist DEPENDS ${inference_lib_dist_dep})
...@@ -40,7 +40,7 @@ template <typename T> ...@@ -40,7 +40,7 @@ template <typename T>
class FCOp : public OperatorBase { class FCOp : public OperatorBase {
public: public:
void Run(...) { void Run(...) {
add(mul(Input<T>("X"), Input<T>("W")), Input<T>("b"); add(mul(Input<T>("X"), Input<T>("W")), Input<T>("b"));
} }
}; };
REGISTER_OP(FCOp, "fc"); REGISTER_OP(FCOp, "fc");
......
...@@ -24,6 +24,6 @@ if(NOT WITH_FLUID_ONLY) ...@@ -24,6 +24,6 @@ if(NOT WITH_FLUID_ONLY)
endif() endif()
add_subdirectory(testing) add_subdirectory(testing)
if(NOT MOBILE_INFERENCE AND NOT RPI) if(NOT MOBILE_INFERENCE AND NOT RPI AND NOT WITH_C_API)
add_subdirectory(fluid) add_subdirectory(fluid)
endif() endif()
...@@ -36,9 +36,11 @@ void TransDataDevice(const Tensor& in, const platform::Place& dst_place, ...@@ -36,9 +36,11 @@ void TransDataDevice(const Tensor& in, const platform::Place& dst_place,
VLOG(3) << "DeviceTransform in, src_place " << in.place() VLOG(3) << "DeviceTransform in, src_place " << in.place()
<< " dst_place: " << dst_place; << " dst_place: " << dst_place;
auto* dev_ctx = GetDeviceContext(in.place(), dst_place); auto* dev_ctx = GetDeviceContext(in.place(), dst_place);
dev_ctx->Wait();
TensorCopy(in, dst_place, *dev_ctx, out); TensorCopy(in, dst_place, *dev_ctx, out);
dev_ctx->Wait(); if (platform::is_gpu_place(in.place()) && platform::is_cpu_place(dst_place)) {
dev_ctx->Wait();
}
} }
} // namespace framework } // namespace framework
......
...@@ -58,6 +58,7 @@ static DataTypeMap* InitDataTypeMap() { ...@@ -58,6 +58,7 @@ static DataTypeMap* InitDataTypeMap() {
RegType(bool, proto::VarType::BOOL); RegType(bool, proto::VarType::BOOL);
RegType(size_t, proto::VarType::SIZE_T); RegType(size_t, proto::VarType::SIZE_T);
RegType(int16_t, proto::VarType::INT16); RegType(int16_t, proto::VarType::INT16);
RegType(uint8_t, proto::VarType::UINT8);
#undef RegType #undef RegType
return retv; return retv;
......
...@@ -47,8 +47,14 @@ inline void VisitDataType(proto::VarType::Type type, Visitor visitor) { ...@@ -47,8 +47,14 @@ inline void VisitDataType(proto::VarType::Type type, Visitor visitor) {
case proto::VarType::BOOL: case proto::VarType::BOOL:
visitor.template operator()<bool>(); visitor.template operator()<bool>();
break; break;
case proto::VarType::UINT8:
visitor.template operator()<uint8_t>();
break;
case proto::VarType::INT16:
visitor.template operator()<int16_t>();
break;
default: default:
PADDLE_THROW("Not supported"); PADDLE_THROW("Not supported %d", type);
} }
} }
......
...@@ -48,17 +48,18 @@ void FetchOpHandle::RunImpl() { ...@@ -48,17 +48,18 @@ void FetchOpHandle::RunImpl() {
WaitInputVarGenerated(platform::CPUPlace()); WaitInputVarGenerated(platform::CPUPlace());
tensors_.resize(inputs_.size()); tensors_.resize(inputs_.size());
auto *var_handle = static_cast<VarHandle *>(inputs_[0]);
auto &var_name = var_handle->name_;
platform::CPUPlace cpu; platform::CPUPlace cpu;
auto &scopes = *local_scopes_; auto &scopes = *local_scopes_;
for (size_t i = 0; i < scopes.size(); ++i) { for (size_t i = 0; i < inputs_.size(); ++i) {
auto &scope = scopes[i]; auto *var_handle = static_cast<VarHandle *>(inputs_[i]);
auto *var = auto &scope = scopes.at(var_handle->scope_idx_);
scope->FindVar(kLocalExecScopeName)->Get<Scope *>()->FindVar(var_name); auto *var = scope->FindVar(kLocalExecScopeName)
->Get<Scope *>()
->FindVar(var_handle->name_);
PADDLE_ENFORCE_NOT_NULL(var, "Cannot find variable %s in execution scope", PADDLE_ENFORCE_NOT_NULL(var, "Cannot find variable %s in execution scope",
var_name); var_handle->name_);
auto &t = var->Get<framework::LoDTensor>(); auto &t = var->Get<framework::LoDTensor>();
if (platform::is_gpu_place(t.place())) { if (platform::is_gpu_place(t.place())) {
#ifdef PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA
......
...@@ -98,7 +98,7 @@ bool MultiDevSSAGraphBuilder::IsDistTrainOp(const OpDesc &op, ...@@ -98,7 +98,7 @@ bool MultiDevSSAGraphBuilder::IsDistTrainOp(const OpDesc &op,
return false; return false;
}; };
if (op.Type() == "split") { if (op.Type() == "split" || op.Type() == "split_byref") {
return checker(op.OutputArgumentNames(), send_op->InputArgumentNames()); return checker(op.OutputArgumentNames(), send_op->InputArgumentNames());
} else if (op.Type() == "concat") { } else if (op.Type() == "concat") {
return checker(op.InputArgumentNames(), send_op->OutputArgumentNames()); return checker(op.InputArgumentNames(), send_op->OutputArgumentNames());
......
...@@ -70,6 +70,14 @@ class OpHandleBase { ...@@ -70,6 +70,14 @@ class OpHandleBase {
const std::vector<VarHandleBase *> &Inputs() const { return inputs_; } const std::vector<VarHandleBase *> &Inputs() const { return inputs_; }
size_t NoDupInputSize() const {
std::unordered_set<VarHandleBase *> res;
for (auto *var : inputs_) {
res.emplace(var);
}
return res.size();
}
const std::vector<VarHandleBase *> &Outputs() const { return outputs_; } const std::vector<VarHandleBase *> &Outputs() const { return outputs_; }
protected: protected:
......
...@@ -174,7 +174,7 @@ void ThreadedSSAGraphExecutor::InsertFetchOps( ...@@ -174,7 +174,7 @@ void ThreadedSSAGraphExecutor::InsertFetchOps(
void ThreadedSSAGraphExecutor::InsertPendingOp( void ThreadedSSAGraphExecutor::InsertPendingOp(
std::unordered_map<OpHandleBase *, size_t> *pending_ops, std::unordered_map<OpHandleBase *, size_t> *pending_ops,
OpHandleBase *op_instance) const { OpHandleBase *op_instance) const {
pending_ops->insert({op_instance, op_instance->Inputs().size()}); pending_ops->insert({op_instance, op_instance->NoDupInputSize()});
} }
void ThreadedSSAGraphExecutor::InsertPendingVar( void ThreadedSSAGraphExecutor::InsertPendingVar(
......
...@@ -228,7 +228,8 @@ static bool has_fetch_operators( ...@@ -228,7 +228,8 @@ static bool has_fetch_operators(
void Executor::Run(const ProgramDesc& program, Scope* scope, void Executor::Run(const ProgramDesc& program, Scope* scope,
std::map<std::string, const LoDTensor*>* feed_targets, std::map<std::string, const LoDTensor*>* feed_targets,
std::map<std::string, LoDTensor*>* fetch_targets, std::map<std::string, LoDTensor*>* fetch_targets,
bool create_vars, const std::string& feed_holder_name, bool create_local_scope, bool create_vars,
const std::string& feed_holder_name,
const std::string& fetch_holder_name) { const std::string& fetch_holder_name) {
platform::RecordBlock b(kProgramId); platform::RecordBlock b(kProgramId);
bool has_feed_ops = bool has_feed_ops =
...@@ -290,8 +291,9 @@ void Executor::Run(const ProgramDesc& program, Scope* scope, ...@@ -290,8 +291,9 @@ void Executor::Run(const ProgramDesc& program, Scope* scope,
} }
auto ctx = Prepare(*copy_program, 0); auto ctx = Prepare(*copy_program, 0);
RunPreparedContext(ctx.get(), scope, feed_targets, fetch_targets, create_vars, RunPreparedContext(ctx.get(), scope, feed_targets, fetch_targets,
feed_holder_name, fetch_holder_name); create_local_scope, create_vars, feed_holder_name,
fetch_holder_name);
} }
std::unique_ptr<ExecutorPrepareContext> Executor::Prepare( std::unique_ptr<ExecutorPrepareContext> Executor::Prepare(
...@@ -366,8 +368,9 @@ void Executor::RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope, ...@@ -366,8 +368,9 @@ void Executor::RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope,
void Executor::RunPreparedContext( void Executor::RunPreparedContext(
ExecutorPrepareContext* ctx, Scope* scope, ExecutorPrepareContext* ctx, Scope* scope,
std::map<std::string, const LoDTensor*>* feed_targets, std::map<std::string, const LoDTensor*>* feed_targets,
std::map<std::string, LoDTensor*>* fetch_targets, bool create_vars, std::map<std::string, LoDTensor*>* fetch_targets, bool create_local_scope,
const std::string& feed_holder_name, const std::string& fetch_holder_name) { bool create_vars, const std::string& feed_holder_name,
const std::string& fetch_holder_name) {
auto& global_block = ctx->prog_.Block(ctx->block_id_); auto& global_block = ctx->prog_.Block(ctx->block_id_);
PADDLE_ENFORCE( PADDLE_ENFORCE(
...@@ -387,7 +390,7 @@ void Executor::RunPreparedContext( ...@@ -387,7 +390,7 @@ void Executor::RunPreparedContext(
} }
} }
RunPreparedContext(ctx, scope, create_vars, create_vars); RunPreparedContext(ctx, scope, create_local_scope, create_vars);
// obtain the data of fetch_targets from fetch_holder // obtain the data of fetch_targets from fetch_holder
for (auto* op : global_block.AllOps()) { for (auto* op : global_block.AllOps()) {
......
...@@ -57,7 +57,7 @@ class Executor { ...@@ -57,7 +57,7 @@ class Executor {
void Run(const ProgramDesc& program, Scope* scope, void Run(const ProgramDesc& program, Scope* scope,
std::map<std::string, const LoDTensor*>* feed_targets, std::map<std::string, const LoDTensor*>* feed_targets,
std::map<std::string, LoDTensor*>* fetch_targets, std::map<std::string, LoDTensor*>* fetch_targets,
bool create_vars = true, bool create_local_scope = true, bool create_vars = true,
const std::string& feed_holder_name = "feed", const std::string& feed_holder_name = "feed",
const std::string& fetch_holder_name = "fetch"); const std::string& fetch_holder_name = "fetch");
...@@ -76,6 +76,7 @@ class Executor { ...@@ -76,6 +76,7 @@ class Executor {
void RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope, void RunPreparedContext(ExecutorPrepareContext* ctx, Scope* scope,
std::map<std::string, const LoDTensor*>* feed_targets, std::map<std::string, const LoDTensor*>* feed_targets,
std::map<std::string, LoDTensor*>* fetch_targets, std::map<std::string, LoDTensor*>* fetch_targets,
bool create_local_scope = true,
bool create_vars = true, bool create_vars = true,
const std::string& feed_holder_name = "feed", const std::string& feed_holder_name = "feed",
const std::string& fetch_holder_name = "fetch"); const std::string& fetch_holder_name = "fetch");
......
...@@ -103,6 +103,7 @@ message VarType { ...@@ -103,6 +103,7 @@ message VarType {
FP64 = 6; FP64 = 6;
// Tensor<size_t> is used in C++. // Tensor<size_t> is used in C++.
SIZE_T = 19; SIZE_T = 19;
UINT8 = 20;
// Other types that may need additional descriptions // Other types that may need additional descriptions
LOD_TENSOR = 7; LOD_TENSOR = 7;
......
...@@ -228,11 +228,12 @@ TEST(LoD, CheckAbsLoD) { ...@@ -228,11 +228,12 @@ TEST(LoD, CheckAbsLoD) {
ASSERT_FALSE(CheckAbsLoD(abs_lod0)); ASSERT_FALSE(CheckAbsLoD(abs_lod0));
} }
TEST(LoDTensor, RecordIO) { template <typename T>
static void TestRecordIO() {
LoDTensor tensor; LoDTensor tensor;
int* tmp = tensor.mutable_data<int>(make_ddim({4, 5}), platform::CPUPlace()); T* tmp = tensor.mutable_data<T>(make_ddim({4, 5}), platform::CPUPlace());
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
tmp[i] = i; tmp[i] = static_cast<T>(i);
} }
std::stringstream* stream = new std::stringstream(); std::stringstream* stream = new std::stringstream();
...@@ -247,7 +248,7 @@ TEST(LoDTensor, RecordIO) { ...@@ -247,7 +248,7 @@ TEST(LoDTensor, RecordIO) {
auto assert_tensor_ok = [](const LoDTensor& tensor) { auto assert_tensor_ok = [](const LoDTensor& tensor) {
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
ASSERT_EQ(tensor.data<int>()[i], i); ASSERT_EQ(tensor.data<T>()[i], static_cast<T>(i));
} }
}; };
...@@ -265,5 +266,13 @@ TEST(LoDTensor, RecordIO) { ...@@ -265,5 +266,13 @@ TEST(LoDTensor, RecordIO) {
} }
} }
TEST(LoDTensor, RecordIO) {
TestRecordIO<int>();
TestRecordIO<int16_t>();
TestRecordIO<uint8_t>();
TestRecordIO<float>();
TestRecordIO<double>();
}
} // namespace framework } // namespace framework
} // namespace paddle } // namespace paddle
...@@ -49,7 +49,7 @@ class OpConverter { ...@@ -49,7 +49,7 @@ class OpConverter {
// convert fluid block to tensorrt network // convert fluid block to tensorrt network
void ConvertBlock(const framework::proto::BlockDesc& block, void ConvertBlock(const framework::proto::BlockDesc& block,
TensorRTEngine* engine) { TensorRTEngine* engine) {
for (size_t i = 0; i < block.ops_size(); i++) { for (int i = 0; i < block.ops_size(); i++) {
const auto& op = block.ops(i); const auto& op = block.ops(i);
OpConverter::Run(op, engine); OpConverter::Run(op, engine);
} }
......
...@@ -149,7 +149,7 @@ void TestInference(const std::string& dirname, ...@@ -149,7 +149,7 @@ void TestInference(const std::string& dirname,
state = paddle::platform::ProfilerState::kCPU; state = paddle::platform::ProfilerState::kCPU;
} else { } else {
#ifdef PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA
state = paddle::platform::ProfilerState::kCUDA; state = paddle::platform::ProfilerState::kAll;
// The default device_id of paddle::platform::CUDAPlace is 0. // The default device_id of paddle::platform::CUDAPlace is 0.
// Users can get the device_id using: // Users can get the device_id using:
// int device_id = place.GetDeviceId(); // int device_id = place.GetDeviceId();
...@@ -172,7 +172,7 @@ void TestInference(const std::string& dirname, ...@@ -172,7 +172,7 @@ void TestInference(const std::string& dirname,
} }
// Disable the profiler and print the timing information // Disable the profiler and print the timing information
paddle::platform::DisableProfiler(paddle::platform::EventSortingKey::kDefault, paddle::platform::DisableProfiler(paddle::platform::EventSortingKey::kDefault,
"load_program_profiler.txt"); "load_program_profiler");
paddle::platform::ResetProfiler(); paddle::platform::ResetProfiler();
// 3. Get the feed_target_names and fetch_target_names // 3. Get the feed_target_names and fetch_target_names
...@@ -208,10 +208,10 @@ void TestInference(const std::string& dirname, ...@@ -208,10 +208,10 @@ void TestInference(const std::string& dirname,
if (PrepareContext) { if (PrepareContext) {
ctx = executor.Prepare(*inference_program, 0); ctx = executor.Prepare(*inference_program, 0);
executor.RunPreparedContext(ctx.get(), scope, &feed_targets, executor.RunPreparedContext(ctx.get(), scope, &feed_targets,
&fetch_targets, CreateVars); &fetch_targets, true, CreateVars);
} else { } else {
executor.Run(*inference_program, scope, &feed_targets, &fetch_targets, executor.Run(*inference_program, scope, &feed_targets, &fetch_targets,
CreateVars); true, CreateVars);
} }
// Enable the profiler // Enable the profiler
...@@ -236,8 +236,7 @@ void TestInference(const std::string& dirname, ...@@ -236,8 +236,7 @@ void TestInference(const std::string& dirname,
// Disable the profiler and print the timing information // Disable the profiler and print the timing information
paddle::platform::DisableProfiler( paddle::platform::DisableProfiler(
paddle::platform::EventSortingKey::kDefault, paddle::platform::EventSortingKey::kDefault, "run_inference_profiler");
"run_inference_profiler.txt");
paddle::platform::ResetProfiler(); paddle::platform::ResetProfiler();
} }
......
...@@ -186,11 +186,7 @@ endif() ...@@ -186,11 +186,7 @@ endif()
add_subdirectory(detail) add_subdirectory(detail)
if(WITH_DISTRIBUTE) if(WITH_DISTRIBUTE)
if(WITH_GPU)
op_library(gen_nccl_id_op DEPS nccl_common)
else()
set(DEPS_OPS ${DEPS_OPS} gen_nccl_id_op)
endif()
set(DISTRIBUTE_DEPS sendrecvop_grpc grpc++_unsecure grpc_unsecure gpr cares zlib protobuf) set(DISTRIBUTE_DEPS sendrecvop_grpc grpc++_unsecure grpc_unsecure gpr cares zlib protobuf)
set(DISTRIBUTE_COMPILE_FLAGS "-Wno-non-virtual-dtor -Wno-error=non-virtual-dtor -Wno-error=delete-non-virtual-dtor") set(DISTRIBUTE_COMPILE_FLAGS "-Wno-non-virtual-dtor -Wno-error=non-virtual-dtor -Wno-error=delete-non-virtual-dtor")
op_library(send_op DEPS ${DISTRIBUTE_DEPS}) op_library(send_op DEPS ${DISTRIBUTE_DEPS})
...@@ -207,7 +203,13 @@ if(WITH_DISTRIBUTE) ...@@ -207,7 +203,13 @@ if(WITH_DISTRIBUTE)
set_source_files_properties(send_barrier_op.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) set_source_files_properties(send_barrier_op.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS})
set_source_files_properties(send_recv_op_test.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS}) set_source_files_properties(send_recv_op_test.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS})
cc_test(test_send_recv SRCS send_recv_op_test.cc DEPS prefetch_op send_op listen_and_serv_op sum_op executor) cc_test(test_send_recv SRCS send_recv_op_test.cc DEPS prefetch_op send_op listen_and_serv_op sum_op executor)
cc_test(test_send_nccl_id SRCS test_send_nccl_id.cc DEPS send_op listen_and_serv_op executor) if(WITH_GPU)
cc_test(test_send_nccl_id SRCS test_send_nccl_id.cc DEPS send_op listen_and_serv_op executor)
op_library(gen_nccl_id_op DEPS nccl_common sendrecvop_grpc)
set_source_files_properties(gen_nccl_id_op.cc PROPERTIES COMPILE_FLAGS ${DISTRIBUTE_COMPILE_FLAGS})
else()
set(DEPS_OPS ${DEPS_OPS} gen_nccl_id_op)
endif()
else() else()
set(DEPS_OPS ${DEPS_OPS} send_op prefetch_op recv_op listen_and_serv_op send_vars_op send_barrier_op gen_nccl_id_op) set(DEPS_OPS ${DEPS_OPS} send_op prefetch_op recv_op listen_and_serv_op send_vars_op send_barrier_op gen_nccl_id_op)
endif() endif()
......
...@@ -14,10 +14,6 @@ limitations under the License. */ ...@@ -14,10 +14,6 @@ limitations under the License. */
#pragma once #pragma once
#ifdef PADDLE_WITH_TESTING
#include "gtest/gtest.h"
#endif
#include <string> #include <string>
#include <vector> #include <vector>
#include "paddle/fluid/framework/lod_tensor.h" #include "paddle/fluid/framework/lod_tensor.h"
......
...@@ -184,7 +184,7 @@ class RequestPrefetch final : public RequestBase { ...@@ -184,7 +184,7 @@ class RequestPrefetch final : public RequestBase {
framework::Scope* local_scope = &scope_->NewScope(); framework::Scope* local_scope = &scope_->NewScope();
auto* var = local_scope->FindVar(var_name); auto* var = local_scope->FindVar(var_name);
InitializeVariable(var, var_desc->GetType()); InitializeVariable(var, var_desc->GetType());
executor_->RunPreparedContext(prefetch_ctx_, scope_, false, false); executor_->RunPreparedContext(prefetch_ctx_, scope_);
SerializeToByteBuffer(var_name, var, *dev_ctx_, &reply); SerializeToByteBuffer(var_name, var, *dev_ctx_, &reply);
......
...@@ -57,8 +57,7 @@ static void ParallelExecuteBlocks( ...@@ -57,8 +57,7 @@ static void ParallelExecuteBlocks(
framework::Async([&executor, &prepared, &program, &scope, idx]() { framework::Async([&executor, &prepared, &program, &scope, idx]() {
int run_block = idx; // thread local int run_block = idx; // thread local
try { try {
executor->RunPreparedContext(prepared[run_block].get(), scope, executor->RunPreparedContext(prepared[run_block].get(), scope);
false, false);
} catch (std::exception &e) { } catch (std::exception &e) {
LOG(ERROR) << "run sub program error " << e.what(); LOG(ERROR) << "run sub program error " << e.what();
} }
...@@ -211,8 +210,8 @@ static void AsyncUpdateThread( ...@@ -211,8 +210,8 @@ static void AsyncUpdateThread(
} }
auto fs = framework::Async([var_name, &executor, &v, prepared] { auto fs = framework::Async([var_name, &executor, &v, prepared] {
try { try {
executor->RunPreparedContext(prepared, v.second->GetMutableLocalScope(), executor->RunPreparedContext(prepared,
false, false); v.second->GetMutableLocalScope());
} catch (std::exception &e) { } catch (std::exception &e) {
LOG(ERROR) << "run sub program error " << e.what(); LOG(ERROR) << "run sub program error " << e.what();
} }
......
...@@ -38,7 +38,9 @@ template struct SetConstant<platform::CPUDeviceContext, bool>; ...@@ -38,7 +38,9 @@ template struct SetConstant<platform::CPUDeviceContext, bool>;
template struct Transpose<platform::CPUDeviceContext, double, RANK>; \ template struct Transpose<platform::CPUDeviceContext, double, RANK>; \
template struct Transpose<platform::CPUDeviceContext, int, RANK>; \ template struct Transpose<platform::CPUDeviceContext, int, RANK>; \
template struct Transpose<platform::CPUDeviceContext, int64_t, RANK>; \ template struct Transpose<platform::CPUDeviceContext, int64_t, RANK>; \
template struct Transpose<platform::CPUDeviceContext, bool, RANK>; template struct Transpose<platform::CPUDeviceContext, bool, RANK>; \
template struct Transpose<platform::CPUDeviceContext, int16_t, RANK>; \
template struct Transpose<platform::CPUDeviceContext, uint8_t, RANK>;
DEFINE_CPU_TRANS(1); DEFINE_CPU_TRANS(1);
DEFINE_CPU_TRANS(2); DEFINE_CPU_TRANS(2);
......
...@@ -38,10 +38,10 @@ __global__ void GPUROIPoolForward( ...@@ -38,10 +38,10 @@ __global__ void GPUROIPoolForward(
int index = blockIdx.x * blockDim.x + threadIdx.x; int index = blockIdx.x * blockDim.x + threadIdx.x;
int offset = blockDim.x * gridDim.x; int offset = blockDim.x * gridDim.x;
for (size_t i = index; i < nthreads; i += offset) { for (size_t i = index; i < nthreads; i += offset) {
int pw = index % pooled_width; int pw = i % pooled_width;
int ph = (index / pooled_width) % pooled_height; int ph = (i / pooled_width) % pooled_height;
int c = (index / pooled_width / pooled_height) % channels; int c = (i / pooled_width / pooled_height) % channels;
int n = index / pooled_width / pooled_height / channels; int n = i / pooled_width / pooled_height / channels;
const int64_t* offset_input_rois = input_rois + n * kROISize; const int64_t* offset_input_rois = input_rois + n * kROISize;
int roi_batch_ind = roi_batch_id_data[n]; int roi_batch_ind = roi_batch_id_data[n];
...@@ -52,14 +52,19 @@ __global__ void GPUROIPoolForward( ...@@ -52,14 +52,19 @@ __global__ void GPUROIPoolForward(
int roi_width = max(roi_end_w - roi_start_w + 1, 1); int roi_width = max(roi_end_w - roi_start_w + 1, 1);
int roi_height = max(roi_end_h - roi_start_h + 1, 1); int roi_height = max(roi_end_h - roi_start_h + 1, 1);
T bin_size_h = static_cast<T>(roi_height) / static_cast<T>(pooled_height);
T bin_size_w = static_cast<T>(roi_width) / static_cast<T>(pooled_width);
int hstart = static_cast<int>(floor(static_cast<T>(ph) * bin_size_h));
int wstart = static_cast<int>(floor(static_cast<T>(pw) * bin_size_w));
int hend = static_cast<int>(ceil(static_cast<T>(ph + 1) * bin_size_h));
int wend = static_cast<int>(ceil(static_cast<T>(pw + 1) * bin_size_w));
int hstart = static_cast<int>(floor(static_cast<double>(ph) *
static_cast<double>(roi_height) /
static_cast<double>(pooled_height)));
int wstart = static_cast<int>(floor(static_cast<double>(pw) *
static_cast<double>(roi_width) /
static_cast<double>(pooled_width)));
int hend = static_cast<int>(ceil(static_cast<double>(ph + 1) *
static_cast<double>(roi_height) /
static_cast<double>(pooled_height)));
int wend = static_cast<int>(ceil(static_cast<double>(pw + 1) *
static_cast<double>(roi_width) /
static_cast<double>(pooled_width)));
hstart = min(max(hstart + roi_start_h, 0), height); hstart = min(max(hstart + roi_start_h, 0), height);
hend = min(max(hend + roi_start_h, 0), height); hend = min(max(hend + roi_start_h, 0), height);
wstart = min(max(wstart + roi_start_w, 0), width); wstart = min(max(wstart + roi_start_w, 0), width);
...@@ -79,9 +84,9 @@ __global__ void GPUROIPoolForward( ...@@ -79,9 +84,9 @@ __global__ void GPUROIPoolForward(
} }
} }
} }
output_data[index] = maxval; output_data[i] = maxval;
if (argmax_data) { if (argmax_data) {
argmax_data[index] = maxidx; argmax_data[i] = maxidx;
} }
} }
} }
...@@ -96,10 +101,10 @@ __global__ void GPUROIPoolBackward( ...@@ -96,10 +101,10 @@ __global__ void GPUROIPoolBackward(
int index = blockIdx.x * blockDim.x + threadIdx.x; int index = blockIdx.x * blockDim.x + threadIdx.x;
int offset = blockDim.x * gridDim.x; int offset = blockDim.x * gridDim.x;
for (int i = index; i < nthreads; i += offset) { for (int i = index; i < nthreads; i += offset) {
int pw = index % pooled_width; int pw = i % pooled_width;
int ph = (index / pooled_width) % pooled_height; int ph = (i / pooled_width) % pooled_height;
int c = (index / pooled_width / pooled_height) % channels; int c = (i / pooled_width / pooled_height) % channels;
int n = index / pooled_width / pooled_height / channels; int n = i / pooled_width / pooled_height / channels;
int roi_batch_ind = roi_batch_id_data[n]; int roi_batch_ind = roi_batch_id_data[n];
int input_offset = (roi_batch_ind * channels + c) * height * width; int input_offset = (roi_batch_ind * channels + c) * height * width;
...@@ -138,6 +143,7 @@ class GPUROIPoolOpKernel : public framework::OpKernel<T> { ...@@ -138,6 +143,7 @@ class GPUROIPoolOpKernel : public framework::OpKernel<T> {
int width = in_dims[3]; int width = in_dims[3];
int rois_num = rois->dims()[0]; int rois_num = rois->dims()[0];
if (rois_num == 0) return; if (rois_num == 0) return;
int output_size = out->numel(); int output_size = out->numel();
......
...@@ -92,12 +92,16 @@ void InitSelectedRowsInScope(const p::CPUPlace &place, f::Scope *scope) { ...@@ -92,12 +92,16 @@ void InitSelectedRowsInScope(const p::CPUPlace &place, f::Scope *scope) {
void AddOp(const std::string &type, const f::VariableNameMap &inputs, void AddOp(const std::string &type, const f::VariableNameMap &inputs,
const f::VariableNameMap &outputs, f::AttributeMap attrs, const f::VariableNameMap &outputs, f::AttributeMap attrs,
f::BlockDesc *block) { f::BlockDesc *block, bool is_sparse) {
// insert output // insert output
for (auto kv : outputs) { for (auto kv : outputs) {
for (auto v : kv.second) { for (auto v : kv.second) {
auto var = block->Var(v); auto var = block->Var(v);
var->SetDataType(f::proto::VarType::FP32); var->SetDataType(f::proto::VarType::FP32);
var->SetPersistable(true);
if (is_sparse) {
var->SetType(f::proto::VarType::SELECTED_ROWS);
}
} }
} }
...@@ -128,7 +132,8 @@ void StartServerNet(bool is_sparse, std::atomic<bool> *initialized) { ...@@ -128,7 +132,8 @@ void StartServerNet(bool is_sparse, std::atomic<bool> *initialized) {
auto *optimize_block = program.AppendBlock(root_block); auto *optimize_block = program.AppendBlock(root_block);
auto *prefetch_block = program.AppendBlock(root_block); auto *prefetch_block = program.AppendBlock(root_block);
// X for server side tensors, RX for received tensors, must be of same shape. // X for server side tensors, RX for received tensors, must be of same shape.
AddOp("sum", {{"X", {"x0", "x1"}}}, {{"Out", {"Out"}}}, {}, optimize_block); AddOp("sum", {{"X", {"x0", "x1"}}}, {{"Out", {"Out"}}}, {}, optimize_block,
is_sparse);
f::AttributeMap attrs; f::AttributeMap attrs;
attrs.insert({"endpoint", std::string("127.0.0.1:0")}); attrs.insert({"endpoint", std::string("127.0.0.1:0")});
attrs.insert({"Fanin", 1}); attrs.insert({"Fanin", 1});
......
...@@ -105,7 +105,7 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel { ...@@ -105,7 +105,7 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel {
using framework::OperatorWithKernel::OperatorWithKernel; using framework::OperatorWithKernel::OperatorWithKernel;
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
auto in_dims = ctx->GetInputDim("X"); auto in_dims = ctx->GetInputDim("Diff");
auto out_dims = ctx->GetInputDim(framework::GradVarName("Out")); auto out_dims = ctx->GetInputDim(framework::GradVarName("Out"));
PADDLE_ENFORCE_GE(out_dims.size(), 2, PADDLE_ENFORCE_GE(out_dims.size(), 2,
...@@ -127,12 +127,33 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel { ...@@ -127,12 +127,33 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel {
} }
}; };
class SmoothL1LossGradMaker : public framework::SingleGradOpDescMaker {
public:
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
protected:
std::unique_ptr<framework::OpDesc> Apply() const override {
auto* op = new framework::OpDesc();
op->SetType("smooth_l1_loss_grad");
op->SetInput("InsideWeight", Input("InsideWeight"));
op->SetInput("OutsideWeight", Input("OutsideWeight"));
op->SetInput("Diff", Output("Diff"));
op->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
op->SetAttrMap(Attrs());
op->SetOutput(framework::GradVarName("X"), InputGrad("X"));
op->SetOutput(framework::GradVarName("Y"), InputGrad("Y"));
return std::unique_ptr<framework::OpDesc>(op);
}
};
} // namespace operators } // namespace operators
} // namespace paddle } // namespace paddle
namespace ops = paddle::operators; namespace ops = paddle::operators;
REGISTER_OPERATOR(smooth_l1_loss, ops::SmoothL1LossOp, ops::SmoothL1LossOpMaker, REGISTER_OPERATOR(smooth_l1_loss, ops::SmoothL1LossOp, ops::SmoothL1LossOpMaker,
paddle::framework::DefaultGradOpDescMaker<true>); ops::SmoothL1LossGradMaker);
REGISTER_OPERATOR(smooth_l1_loss_grad, ops::SmoothL1LossGradOp); REGISTER_OPERATOR(smooth_l1_loss_grad, ops::SmoothL1LossGradOp);
REGISTER_OP_CPU_KERNEL( REGISTER_OP_CPU_KERNEL(
smooth_l1_loss, smooth_l1_loss,
......
proto_library(profiler_proto SRCS profiler.proto) proto_library(profiler_proto SRCS profiler.proto DEPS framework_proto)
py_proto_compile(profiler_py_proto SRCS profiler.proto) py_proto_compile(profiler_py_proto SRCS profiler.proto)
add_custom_target(profiler_py_proto_init ALL COMMAND ${CMAKE_COMMAND} -E touch __init__.py) add_custom_target(profiler_py_proto_init ALL COMMAND ${CMAKE_COMMAND} -E touch __init__.py)
...@@ -49,7 +49,7 @@ nv_test(device_context_test SRCS device_context_test.cu DEPS device_context gpu_ ...@@ -49,7 +49,7 @@ nv_test(device_context_test SRCS device_context_test.cu DEPS device_context gpu_
nv_test(cudnn_helper_test SRCS cudnn_helper_test.cc DEPS dynload_cuda) nv_test(cudnn_helper_test SRCS cudnn_helper_test.cc DEPS dynload_cuda)
nv_test(transform_test SRCS transform_test.cu DEPS memory place device_context) nv_test(transform_test SRCS transform_test.cu DEPS memory place device_context)
cc_library(device_tracer SRCS device_tracer.cc DEPS boost profiler_proto ${GPU_CTX_DEPS}) cc_library(device_tracer SRCS device_tracer.cc DEPS boost profiler_proto framework_proto ${GPU_CTX_DEPS})
cc_library(profiler SRCS profiler.cc DEPS device_context device_tracer) cc_library(profiler SRCS profiler.cc DEPS device_context device_tracer)
cc_test(profiler_test SRCS profiler_test.cc DEPS profiler) cc_test(profiler_test SRCS profiler_test.cc DEPS profiler)
......
...@@ -173,8 +173,9 @@ void PopEvent(const std::string& name, const DeviceContext* dev_ctx) { ...@@ -173,8 +173,9 @@ void PopEvent(const std::string& name, const DeviceContext* dev_ctx) {
} }
RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx) RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx)
: start_ns_(PosixInNsec()) { : is_enabled_(false), start_ns_(PosixInNsec()) {
if (g_state == ProfilerState::kDisabled) return; if (g_state == ProfilerState::kDisabled) return;
is_enabled_ = true;
dev_ctx_ = dev_ctx; dev_ctx_ = dev_ctx;
name_ = name; name_ = name;
PushEvent(name_, dev_ctx_); PushEvent(name_, dev_ctx_);
...@@ -183,7 +184,7 @@ RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx) ...@@ -183,7 +184,7 @@ RecordEvent::RecordEvent(const std::string& name, const DeviceContext* dev_ctx)
} }
RecordEvent::~RecordEvent() { RecordEvent::~RecordEvent() {
if (g_state == ProfilerState::kDisabled) return; if (g_state == ProfilerState::kDisabled || !is_enabled_) return;
DeviceTracer* tracer = GetDeviceTracer(); DeviceTracer* tracer = GetDeviceTracer();
if (tracer) { if (tracer) {
tracer->AddCPURecords(CurAnnotation(), start_ns_, PosixInNsec(), tracer->AddCPURecords(CurAnnotation(), start_ns_, PosixInNsec(),
...@@ -193,14 +194,16 @@ RecordEvent::~RecordEvent() { ...@@ -193,14 +194,16 @@ RecordEvent::~RecordEvent() {
PopEvent(name_, dev_ctx_); PopEvent(name_, dev_ctx_);
} }
RecordBlock::RecordBlock(int block_id) : start_ns_(PosixInNsec()) { RecordBlock::RecordBlock(int block_id)
: is_enabled_(false), start_ns_(PosixInNsec()) {
if (g_state == ProfilerState::kDisabled) return; if (g_state == ProfilerState::kDisabled) return;
is_enabled_ = true;
SetCurBlock(block_id); SetCurBlock(block_id);
name_ = string::Sprintf("block_%d", block_id); name_ = string::Sprintf("block_%d", block_id);
} }
RecordBlock::~RecordBlock() { RecordBlock::~RecordBlock() {
if (g_state == ProfilerState::kDisabled) return; if (g_state == ProfilerState::kDisabled || !is_enabled_) return;
DeviceTracer* tracer = GetDeviceTracer(); DeviceTracer* tracer = GetDeviceTracer();
if (tracer) { if (tracer) {
// We try to put all blocks at the same nested depth in the // We try to put all blocks at the same nested depth in the
......
...@@ -74,6 +74,7 @@ struct RecordEvent { ...@@ -74,6 +74,7 @@ struct RecordEvent {
~RecordEvent(); ~RecordEvent();
bool is_enabled_;
uint64_t start_ns_; uint64_t start_ns_;
// The device context is used by Event to get the current cuda stream. // The device context is used by Event to get the current cuda stream.
const DeviceContext* dev_ctx_; const DeviceContext* dev_ctx_;
...@@ -89,6 +90,7 @@ struct RecordBlock { ...@@ -89,6 +90,7 @@ struct RecordBlock {
~RecordBlock(); ~RecordBlock();
private: private:
bool is_enabled_;
std::string name_; std::string name_;
uint64_t start_ns_; uint64_t start_ns_;
}; };
......
...@@ -198,7 +198,7 @@ EOF ...@@ -198,7 +198,7 @@ EOF
# run paddle version to install python packages first # run paddle version to install python packages first
RUN apt-get update &&\ RUN apt-get update &&\
${NCCL_DEPS}\ ${NCCL_DEPS}\
apt-get install -y wget python-pip dmidecode python-tk && pip install -U pip==9.0.3 && \ apt-get install -y wget python-pip dmidecode python-tk && easy_install -U pip && \
pip install /*.whl; apt-get install -f -y && \ pip install /*.whl; apt-get install -f -y && \
apt-get clean -y && \ apt-get clean -y && \
rm -f /*.whl && \ rm -f /*.whl && \
......
...@@ -20,19 +20,15 @@ ...@@ -20,19 +20,15 @@
#================================================= #=================================================
function print_usage() { function print_usage() {
RED='\033[0;31m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NONE='\033[0m'
echo -e "\n${RED}Usage${NONE}: echo -e "\n${RED}Usage${NONE}:
${BOLD}$0${NONE} [OPTION]" ${BOLD}${SCRIPT_NAME}${NONE} [OPTION]"
echo -e "\n${RED}Options${NONE}: echo -e "\n${RED}Options${NONE}:
${BLUE}build${NONE}: run build for x86 platform ${BLUE}build${NONE}: run build for x86 platform
${BLUE}build_android${NONE}: run build for android platform ${BLUE}build_android${NONE}: run build for android platform
${BLUE}build_ios${NONE}: run build for ios platform ${BLUE}build_ios${NONE}: run build for ios platform
${BLUE}test${NONE}: run all unit tests ${BLUE}test${NONE}: run all unit tests
${BLUE}single_test${NONE}: run a single unit test
${BLUE}bind_test${NONE}: parallel tests bind to different GPU ${BLUE}bind_test${NONE}: parallel tests bind to different GPU
${BLUE}doc${NONE}: generate paddle documents ${BLUE}doc${NONE}: generate paddle documents
${BLUE}html${NONE}: convert C++ source code into HTML ${BLUE}html${NONE}: convert C++ source code into HTML
...@@ -45,7 +41,15 @@ function print_usage() { ...@@ -45,7 +41,15 @@ function print_usage() {
} }
function init() { function init() {
RED='\033[0;31m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NONE='\033[0m'
PADDLE_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}")/../../" && pwd )" PADDLE_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}")/../../" && pwd )"
if [ -z "${SCRIPT_NAME}" ]; then
SCRIPT_NAME=$0
fi
} }
function cmake_gen() { function cmake_gen() {
...@@ -91,7 +95,6 @@ function cmake_gen() { ...@@ -91,7 +95,6 @@ function cmake_gen() {
-DWITH_AVX=${WITH_AVX:-OFF} -DWITH_AVX=${WITH_AVX:-OFF}
-DWITH_GOLANG=${WITH_GOLANG:-OFF} -DWITH_GOLANG=${WITH_GOLANG:-OFF}
-DCUDA_ARCH_NAME=${CUDA_ARCH_NAME:-All} -DCUDA_ARCH_NAME=${CUDA_ARCH_NAME:-All}
-DWITH_SWIG_PY=ON
-DWITH_C_API=${WITH_C_API:-OFF} -DWITH_C_API=${WITH_C_API:-OFF}
-DWITH_PYTHON=${WITH_PYTHON:-ON} -DWITH_PYTHON=${WITH_PYTHON:-ON}
-DWITH_SWIG_PY=${WITH_SWIG_PY:-ON} -DWITH_SWIG_PY=${WITH_SWIG_PY:-ON}
...@@ -309,6 +312,25 @@ EOF ...@@ -309,6 +312,25 @@ EOF
fi fi
} }
function single_test() {
TEST_NAME=$1
if [ -z "${TEST_NAME}" ]; then
echo -e "${RED}Usage:${NONE}"
echo -e "${BOLD}${SCRIPT_NAME}${NONE} ${BLUE}single_test${NONE} [test_name]"
exit 1
fi
mkdir -p ${PADDLE_ROOT}/build
cd ${PADDLE_ROOT}/build
if [ ${WITH_TESTING:-ON} == "ON" ] ; then
cat <<EOF
========================================
Running ${TEST_NAME} ...
========================================
EOF
ctest --output-on-failure -R ${TEST_NAME}
fi
}
function bind_test() { function bind_test() {
# the number of process to run tests # the number of process to run tests
NUM_PROC=6 NUM_PROC=6
...@@ -383,17 +405,19 @@ EOF ...@@ -383,17 +405,19 @@ EOF
function gen_dockerfile() { function gen_dockerfile() {
# Set BASE_IMAGE according to env variables # Set BASE_IMAGE according to env variables
CUDA_MAJOR="$(echo $CUDA_VERSION | cut -d '.' -f 1).$(echo $CUDA_VERSION | cut -d '.' -f 2)"
CUDNN_MAJOR=$(echo $CUDNN_VERSION | cut -d '.' -f 1)
if [[ ${WITH_GPU} == "ON" ]]; then if [[ ${WITH_GPU} == "ON" ]]; then
BASE_IMAGE="nvidia/cuda:8.0-cudnn5-runtime-ubuntu16.04" BASE_IMAGE="nvidia/cuda:${CUDA_MAJOR}-cudnn${CUDNN_MAJOR}-runtime-ubuntu16.04"
else else
BASE_IMAGE="ubuntu:16.04" BASE_IMAGE="ubuntu:16.04"
fi fi
DOCKERFILE_GPU_ENV="" DOCKERFILE_GPU_ENV=""
DOCKERFILE_CUDNN_DSO="" DOCKERFILE_CUDNN_DSO=""
if [[ ${WITH_GPU:-OFF} == 'ON' ]]; then if [[ ${WITH_GPU:-OFF} == 'ON' ]]; then
DOCKERFILE_GPU_ENV="ENV LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu:\${LD_LIBRARY_PATH}" DOCKERFILE_GPU_ENV="ENV LD_LIBRARY_PATH /usr/lib/x86_64-linux-gnu:\${LD_LIBRARY_PATH}"
DOCKERFILE_CUDNN_DSO="RUN ln -s /usr/lib/x86_64-linux-gnu/libcudnn.so.5 /usr/lib/x86_64-linux-gnu/libcudnn.so" DOCKERFILE_CUDNN_DSO="RUN ln -s /usr/lib/x86_64-linux-gnu/libcudnn.so.${CUDNN_MAJOR} /usr/lib/x86_64-linux-gnu/libcudnn.so"
fi fi
cat <<EOF cat <<EOF
...@@ -427,7 +451,7 @@ EOF ...@@ -427,7 +451,7 @@ EOF
# run paddle version to install python packages first # run paddle version to install python packages first
RUN apt-get update &&\ RUN apt-get update &&\
${NCCL_DEPS}\ ${NCCL_DEPS}\
apt-get install -y wget python-pip dmidecode python-tk && pip install -U pip==9.0.3 && \ apt-get install -y wget python-pip dmidecode python-tk && easy_install -U pip && \
pip install /*.whl; apt-get install -f -y && \ pip install /*.whl; apt-get install -f -y && \
apt-get clean -y && \ apt-get clean -y && \
rm -f /*.whl && \ rm -f /*.whl && \
...@@ -468,7 +492,7 @@ function gen_fluid_inference_lib() { ...@@ -468,7 +492,7 @@ function gen_fluid_inference_lib() {
Deploying fluid inference library ... Deploying fluid inference library ...
======================================== ========================================
EOF EOF
make inference_lib_dist make -j `nproc` inference_lib_dist
fi fi
} }
...@@ -480,6 +504,7 @@ function main() { ...@@ -480,6 +504,7 @@ function main() {
build) build)
cmake_gen ${PYTHON_ABI:-""} cmake_gen ${PYTHON_ABI:-""}
build build
gen_dockerfile
;; ;;
build_android) build_android)
build_android build_android
...@@ -490,6 +515,9 @@ function main() { ...@@ -490,6 +515,9 @@ function main() {
test) test)
run_test run_test
;; ;;
single_test)
single_test $2
;;
bind_test) bind_test)
bind_test bind_test
;; ;;
...@@ -504,6 +532,7 @@ function main() { ...@@ -504,6 +532,7 @@ function main() {
;; ;;
capi) capi)
cmake_gen ${PYTHON_ABI:-""} cmake_gen ${PYTHON_ABI:-""}
build
gen_capi_package gen_capi_package
;; ;;
fluid_inference_lib) fluid_inference_lib)
......
...@@ -63,6 +63,7 @@ EOL ...@@ -63,6 +63,7 @@ EOL
${DOCKER_CMD} run -it \ ${DOCKER_CMD} run -it \
--name $CONTAINER_ID \ --name $CONTAINER_ID \
${DOCKER_ENV} \ ${DOCKER_ENV} \
-e SCRIPT_NAME=$0 \
-v $PADDLE_ROOT:/paddle \ -v $PADDLE_ROOT:/paddle \
-v ${HOME}/.ccache:/root/.ccache \ -v ${HOME}/.ccache:/root/.ccache \
-w /paddle \ -w /paddle \
......
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* Copyright 2016-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
#ifndef MKLDNN_HPP
#define MKLDNN_HPP
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <stdlib.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include "mkldnn.h"
#endif
namespace mkldnn {
/// @addtogroup cpp_api C++ API
/// @{
/// @addtogroup cpp_api_utils Utils
/// @{
/// A class that provides the destructor for an Intel(R) MKL-DNN C handle
template <typename T>
class handle_traits {};
/// A class for wrapping an Intel(R) MKL-DNN handle. It is used as the base
/// class for primitive (#mkldnn_primitive_t), engine (#mkldnn_engine_t), and
/// stream (#mkldnn_stream_t) handles. An object of the #mkldnn::handle class
/// can be passed by value. This class enables wrapping:
/// - Newly constructed handles.
/// @n In this case, the constructed handle uses reference counting provided
/// by @p std::shared_ptr with a proper deleter function specified through
/// the @p handle_traits class.
/// - Pre-existing handles returned by the Intel(R) MKL-DNN C API (for
/// example, through #mkldnn_primitive_get_output()).
/// @n In this case, an Intel(R) MKL-DNN C API handle is wrapped without a
/// deleter because it is assumed that the handle wrapper for the original
/// object deletes the handle (this model is similar to @p std::weak_ptr).
template <typename T, typename traits = handle_traits<T>>
class handle {
private:
std::shared_ptr<typename std::remove_pointer<T>::type> _data;
handle(const handle &&) = delete;
handle &operator=(const handle &&other) = delete;
protected:
/// Constructs a C handle wrapper.
/// @param t The C handle to wrap.
/// @param weak A flag to specify whether to construct a weak wrapper.
handle(T t = 0, bool weak = false) : _data(0) { reset(t, weak); }
bool operator==(const T other) const { return other == _data.get(); }
bool operator!=(const T other) const { return !(*this == other); }
public:
handle(const handle &other) : _data(other._data) {}
handle &operator=(const handle &other) {
_data = other._data;
return *this;
}
/// Resets the value of a C handle.
/// @param t The new value of the C handle.
/// @param weak A flag to specify whether the wrapper should be weak.
void reset(T t, bool weak = false) {
auto dummy_destructor = [](T) {
return decltype(traits::destructor(0))(0);
};
_data.reset(t, weak ? dummy_destructor : traits::destructor);
}
/// Returns the value of the underlying C handle.
T get() const { return _data.get(); }
bool operator==(const handle &other) const {
return other._data.get() == _data.get();
}
bool operator!=(const handle &other) const { return !(*this == other); }
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
struct handle_traits<mkldnn_primitive_desc_t> {
static constexpr auto destructor = &mkldnn_primitive_desc_destroy;
};
template <>
struct handle_traits<mkldnn_primitive_t> {
static constexpr auto destructor = &mkldnn_primitive_destroy;
};
#endif
/// Base class for all computational primitives.
class primitive : public handle<mkldnn_primitive_t> {
friend struct error;
friend struct stream;
friend class primitive_at;
using handle::handle;
public:
/// A proxy to C primitive kind enum
enum class kind {
undefined_primitive = mkldnn_undefined_primitive,
memory = mkldnn_memory,
view = mkldnn_view,
reorder = mkldnn_reorder,
concat = mkldnn_concat,
concat_inplace = mkldnn_concat_inplace,
sum = mkldnn_sum,
convolution = mkldnn_convolution,
deconvolution = mkldnn_deconvolution,
eltwise = mkldnn_eltwise,
relu = mkldnn_relu,
softmax = mkldnn_softmax,
pooling = mkldnn_pooling,
lrn = mkldnn_lrn,
batch_normalization = mkldnn_batch_normalization,
inner_product = mkldnn_inner_product,
convolution_relu = mkldnn_convolution_relu,
rnn = mkldnn_rnn,
};
/// A wrapper structure to specify a particular output of a primitive.
struct at {
/// The underlying C API structure.
mkldnn_primitive_at_t data;
/// Constructs a wrapper specifying @p aprimitive output with index @p
/// at.
///
/// @param aprimitive The target primitive.
/// @param at The output index.
at(const primitive &aprimitive, size_t at = 0)
: data(mkldnn_primitive_at(aprimitive.get(), at)) {}
/// Returns the specified output.
inline operator primitive() const;
};
/// Returns the descriptor of the underlying C API primitive
inline const_mkldnn_primitive_desc_t get_primitive_desc() const;
// TODO: use the C++ API wrapper structure.
};
inline mkldnn_primitive_kind_t convert_to_c(primitive::kind akind) {
return static_cast<mkldnn_primitive_kind_t>(akind);
}
/// Intel(R) MKL-DNN exception class.
///
/// This class captures the status returned by the failed C API function, error
/// message, and, optionally, handle of the primitive that caused the error.
struct error : public std::exception {
mkldnn_status_t status;
std::string message;
primitive error_primitive;
/// Constructs an error instance.
///
/// @param astatus The error status returned by the C API.
/// @param amessage The error message.
/// @param aerror_primitive (optional) A C handle of the primitive that
/// caused the error.
error(mkldnn_status_t astatus,
std::string amessage,
mkldnn_primitive_t aerror_primitive = 0)
: status(astatus),
message(amessage),
error_primitive(aerror_primitive, true) {}
/// A convenience function for wrapping calls to the C API. Checks the
/// return status and throws an #error in case of failure.
///
/// @param status The error status returned by the C API.
/// @param message The error message.
/// @param error_primitive (optional) A C handle of the primitive that
/// caused the error.
static void wrap_c_api(mkldnn_status_t status,
std::string message,
mkldnn_primitive_t *error_primitive = 0) {
if (status != mkldnn_success) {
if (nullptr != error_primitive)
throw error(status, message, *error_primitive);
else
throw error(status, message, nullptr);
}
}
};
inline primitive::at::operator primitive() const {
const_mkldnn_primitive_t output;
error::wrap_c_api(
mkldnn_primitive_get_output(data.primitive, data.output_index, &output),
"could not get an output primitive");
return primitive(const_cast<mkldnn_primitive_t>(output), true);
}
const_mkldnn_primitive_desc_t primitive::get_primitive_desc() const {
const_mkldnn_primitive_desc_t pd;
error::wrap_c_api(mkldnn_primitive_get_primitive_desc(get(), &pd),
"could not get primitive descriptor by primitive");
return pd;
}
/// @}
/// @addtogroup cpp_api_enums Common data types and enumerations
/// @{
enum round_mode {
round_nearest = mkldnn_round_nearest,
round_down = mkldnn_round_down,
};
inline mkldnn_round_mode_t convert_to_c(round_mode mode) {
return static_cast<mkldnn_round_mode_t>(mode);
}
enum padding_kind { zero = mkldnn_padding_zero };
inline mkldnn_padding_kind_t convert_to_c(padding_kind kind) {
return static_cast<mkldnn_padding_kind_t>(kind);
}
enum prop_kind {
forward_training = mkldnn_forward_training,
forward_scoring = mkldnn_forward_scoring,
forward_inference = mkldnn_forward_inference,
forward = mkldnn_forward,
backward = mkldnn_backward,
backward_data = mkldnn_backward_data,
backward_weights = mkldnn_backward_weights,
backward_bias = mkldnn_backward_bias
};
inline mkldnn_prop_kind_t convert_to_c(prop_kind kind) {
return static_cast<mkldnn_prop_kind_t>(kind);
}
enum algorithm {
algorithm_undef = mkldnn_alg_kind_undef,
convolution_direct = mkldnn_convolution_direct,
convolution_winograd = mkldnn_convolution_winograd,
deconvolution_direct = mkldnn_deconvolution_direct,
deconvolution_winograd = mkldnn_deconvolution_winograd,
eltwise_relu = mkldnn_eltwise_relu,
eltwise_tanh = mkldnn_eltwise_tanh,
eltwise_elu = mkldnn_eltwise_elu,
eltwise_square = mkldnn_eltwise_square,
eltwise_abs = mkldnn_eltwise_abs,
eltwise_sqrt = mkldnn_eltwise_sqrt,
eltwise_linear = mkldnn_eltwise_linear,
eltwise_bounded_relu = mkldnn_eltwise_bounded_relu,
eltwise_soft_relu = mkldnn_eltwise_soft_relu,
eltwise_logistic = mkldnn_eltwise_logistic,
lrn_across_channels = mkldnn_lrn_across_channels,
lrn_within_channel = mkldnn_lrn_within_channel,
pooling_max = mkldnn_pooling_max,
pooling_avg = mkldnn_pooling_avg,
pooling_avg_include_padding = mkldnn_pooling_avg_include_padding,
pooling_avg_exclude_padding = mkldnn_pooling_avg_exclude_padding,
vanilla_rnn = mkldnn_vanilla_rnn,
vanilla_lstm = mkldnn_vanilla_lstm,
vanilla_gru = mkldnn_vanilla_gru,
};
inline mkldnn_alg_kind_t convert_to_c(algorithm aalgorithm) {
return static_cast<mkldnn_alg_kind_t>(aalgorithm);
}
enum batch_normalization_flag {
use_global_stats = mkldnn_use_global_stats,
use_scale_shift = mkldnn_use_scaleshift,
omit_stats = mkldnn_omit_stats,
fuse_bn_relu = mkldnn_fuse_bn_relu
};
inline mkldnn_batch_normalization_flag_t convert_to_c(
batch_normalization_flag aflag) {
return static_cast<mkldnn_batch_normalization_flag_t>(aflag);
}
enum rnn_direction {
unidirectional_left2right = mkldnn_unidirectional_left2right,
unidirectional_right2left = mkldnn_unidirectional_right2left,
unidirectional = mkldnn_unidirectional,
bidirectional_concat = mkldnn_bidirectional_concat,
bidirectional_sum = mkldnn_bidirectional_sum,
};
inline mkldnn_rnn_direction_t convert_to_c(rnn_direction adir) {
return static_cast<mkldnn_rnn_direction_t>(adir);
}
enum query {
undef = mkldnn_query_undef,
eengine = mkldnn_query_engine,
primitive_kind = mkldnn_query_primitive_kind,
num_of_inputs_s32 = mkldnn_query_num_of_inputs_s32,
num_of_outputs_s32 = mkldnn_query_num_of_outputs_s32,
time_estimate_f64 = mkldnn_query_time_estimate_f64,
memory_consumption_s64 = mkldnn_query_memory_consumption_s64,
impl_info_str = mkldnn_query_impl_info_str,
memory_d = mkldnn_query_memory_d,
convolution_d = mkldnn_query_convolution_d,
deconvolution_d = mkldnn_query_deconvolution_d,
eltwise_d = mkldnn_query_eltwise_d,
relu_d = mkldnn_query_relu_d,
softmax_d = mkldnn_query_softmax_d,
pooling_d = mkldnn_query_pooling_d,
lrn_d = mkldnn_query_lrn_d,
batch_normalization_d = mkldnn_query_batch_normalization_d,
inner_product_d = mkldnn_query_inner_product_d,
convolution_relu_d = mkldnn_query_convolution_relu_d,
rnn_d = mkldnn_query_rnn_d,
input_pd = mkldnn_query_input_pd,
output_pd = mkldnn_query_output_pd,
src_pd = mkldnn_query_src_pd,
diff_src_pd = mkldnn_query_diff_src_pd,
weights_pd = mkldnn_query_weights_pd,
diff_weights_pd = mkldnn_query_diff_weights_pd,
dst_pd = mkldnn_query_dst_pd,
diff_dst_pd = mkldnn_query_diff_dst_pd,
workspace_pd = mkldnn_query_workspace_pd,
};
inline mkldnn_query_t convert_to_c(query aquery) {
return static_cast<mkldnn_query_t>(aquery);
}
/// @}
/// @addtogroup cpp_api_attr Attributes
/// @{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
struct handle_traits<mkldnn_post_ops_t> {
static constexpr auto destructor = &mkldnn_post_ops_destroy;
};
#endif
struct post_ops : public handle<mkldnn_post_ops_t> {
post_ops() {
mkldnn_post_ops_t result;
error::wrap_c_api(mkldnn_post_ops_create(&result),
"could not create post operation sequence");
reset(result);
}
int len() const { return mkldnn_post_ops_len(get()); }
primitive::kind kind(int index) const {
error::wrap_c_api(index < len() ? mkldnn_success : mkldnn_invalid_arguments,
"post_ops index is out of range");
return static_cast<primitive::kind>(mkldnn_post_ops_get_kind(get(), index));
}
void append_sum(float scale = 1.) {
error::wrap_c_api(mkldnn_post_ops_append_sum(get(), scale),
"could not append sum");
}
void get_params_sum(int index, float &scale) const {
error::wrap_c_api(mkldnn_post_ops_get_params_sum(get(), index, &scale),
"could not get sum params");
}
void append_eltwise(float scale, algorithm alg, float alpha, float beta) {
error::wrap_c_api(mkldnn_post_ops_append_eltwise(
get(), scale, convert_to_c(alg), alpha, beta),
"could not append eltwise");
}
void get_params_eltwise(int index,
float &scale,
algorithm &alg,
float &alpha,
float &beta) const {
mkldnn_alg_kind_t c_alg;
error::wrap_c_api(mkldnn_post_ops_get_params_eltwise(
get(), index, &scale, &c_alg, &alpha, &beta),
"could not get eltwise params");
alg = static_cast<algorithm>(c_alg);
}
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
struct handle_traits<mkldnn_primitive_attr_t> {
static constexpr auto destructor = &mkldnn_primitive_attr_destroy;
};
#endif
struct primitive_attr : public handle<mkldnn_primitive_attr_t> {
primitive_attr() {
mkldnn_primitive_attr_t result;
error::wrap_c_api(mkldnn_primitive_attr_create(&result),
"could not create a primitive attr");
reset(result);
}
round_mode get_int_output_round_mode() const {
mkldnn_round_mode_t result;
error::wrap_c_api(
mkldnn_primitive_attr_get_int_output_round_mode(get(), &result),
"could not get int output round mode");
return round_mode(result);
}
void set_int_output_round_mode(round_mode mode) {
error::wrap_c_api(mkldnn_primitive_attr_set_int_output_round_mode(
get(), mkldnn::convert_to_c(mode)),
"could not set int output round mode");
}
void get_output_scales(int &mask, std::vector<float> &scales) const {
int count, c_mask;
const float *c_scales;
error::wrap_c_api(mkldnn_primitive_attr_get_output_scales(
get(), &count, &c_mask, &c_scales),
"could not get int output scales");
scales.resize(count);
mask = c_mask;
for (int c = 0; c < count; ++c) scales[c] = c_scales[c];
}
void set_output_scales(int mask, const std::vector<float> &scales) {
error::wrap_c_api(mkldnn_primitive_attr_set_output_scales(
get(), (int)scales.size(), mask, &scales[0]),
"could not set int output scales");
}
const post_ops get_post_ops() const {
post_ops result;
const_mkldnn_post_ops_t c_result;
error::wrap_c_api(mkldnn_primitive_attr_get_post_ops(get(), &c_result),
"could not get post operation sequence");
result.reset(const_cast<mkldnn_post_ops_t>(c_result), true);
return result;
}
void set_post_ops(post_ops ops) {
error::wrap_c_api(mkldnn_primitive_attr_set_post_ops(get(), ops.get()),
"could not set post operation sequence");
}
};
/// @}
/// @addtogroup cpp_api_engine Engine
/// @{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
struct handle_traits<mkldnn_engine_t> {
static constexpr auto destructor = &mkldnn_engine_destroy;
};
#endif
/// An execution engine.
struct engine : public handle<mkldnn_engine_t> {
friend class primitive;
// gcc bug??? using handle::handle;
/// Kinds of engines
enum kind {
/// An unspecified engine
any = mkldnn_any_engine,
/// CPU engine
cpu = mkldnn_cpu,
};
/// Returns the number of engines of a certain kind.
///
/// @param akind The kind of engines to count.
static size_t get_count(kind akind) {
return mkldnn_engine_get_count(convert_to_c(akind));
}
/// Constructs an engine.
///
/// @param akind The kind of engine to construct.
/// @param index The index of the engine. Must be less than the value
/// returned by #get_count() for this particular kind of engine.
engine(kind akind, size_t index) {
mkldnn_engine_t aengine;
error::wrap_c_api(
mkldnn_engine_create(&aengine, convert_to_c(akind), index),
"could not create an engine");
reset(aengine);
}
explicit engine(const mkldnn_engine_t &aengine) : handle(aengine, true) {}
engine(const handle<mkldnn_primitive_desc_t> &pd) {
mkldnn_engine_t engine_q;
error::wrap_c_api(
mkldnn_primitive_desc_query(
pd.get(), mkldnn::convert_to_c(eengine), 0, &engine_q),
"could not get engine from primitive_desc");
reset(engine_q, true);
}
template <class primitive_desc>
static engine query(const primitive_desc &pd) {
mkldnn_engine_t engine_q;
error::wrap_c_api(
mkldnn_primitive_desc_query(
pd.get(), mkldnn::convert_to_c(eengine), 0, &engine_q),
"could not get engine from primitive_desc");
return engine(engine_q);
}
private:
static mkldnn_engine_kind_t convert_to_c(kind akind) {
return static_cast<mkldnn_engine_kind_t>(akind);
}
};
/// @}
/// @addtogroup cpp_api_primitives Primitives
/// @{
/// @addtogroup cpp_api_memory Memory
/// @{
/// Memory primitive that describes the data.
struct memory : public primitive {
private:
std::shared_ptr<char> _handle;
public:
typedef std::vector<std::remove_extent<mkldnn_dims_t>::type> dims;
template <typename T>
static void validate_dims(std::vector<T> v) {
if (v.size() > TENSOR_MAX_DIMS)
throw error(mkldnn_invalid_arguments, "invalid dimensions");
}
/// Data type specification. See #mkldnn_data_type_t for a detailed
/// description.
enum data_type {
data_undef = mkldnn_data_type_undef,
f32 = mkldnn_f32,
s32 = mkldnn_s32,
s16 = mkldnn_s16,
s8 = mkldnn_s8,
u8 = mkldnn_u8,
};
/// Memory format specification. See #mkldnn_memory_format_t
/// for a detailed description.
enum format {
format_undef = mkldnn_format_undef,
any = mkldnn_any,
blocked = mkldnn_blocked,
x = mkldnn_x,
nc = mkldnn_nc,
nchw = mkldnn_nchw,
nhwc = mkldnn_nhwc,
chwn = mkldnn_chwn,
nChw8c = mkldnn_nChw8c,
nChw16c = mkldnn_nChw16c,
ncdhw = mkldnn_ncdhw,
ndhwc = mkldnn_ndhwc,
nCdhw16c = mkldnn_nCdhw16c,
oi = mkldnn_oi,
io = mkldnn_io,
oihw = mkldnn_oihw,
ihwo = mkldnn_ihwo,
hwio = mkldnn_hwio,
oidhw = mkldnn_oidhw,
OIdhw16i16o = mkldnn_OIdhw16i16o,
OIdhw16o16i = mkldnn_OIdhw16o16i,
Oidhw16o = mkldnn_Oidhw16o,
Odhwi16o = mkldnn_Odhwi16o,
oIhw8i = mkldnn_oIhw8i,
oIhw16i = mkldnn_oIhw16i,
OIhw8i8o = mkldnn_OIhw8i8o,
OIhw16i16o = mkldnn_OIhw16i16o,
OIhw8o8i = mkldnn_OIhw8o8i,
OIhw16o16i = mkldnn_OIhw16o16i,
IOhw16o16i = mkldnn_IOhw16o16i,
OIhw8i16o2i = mkldnn_OIhw8i16o2i,
OIhw8o16i2o = mkldnn_OIhw8o16i2o,
OIhw4i16o4i = mkldnn_OIhw4i16o4i,
Oihw8o = mkldnn_Oihw8o,
Oihw16o = mkldnn_Oihw16o,
Ohwi8o = mkldnn_Ohwi8o,
Ohwi16o = mkldnn_Ohwi16o,
OhIw16o4i = mkldnn_OhIw16o4i,
goihw = mkldnn_goihw,
hwigo = mkldnn_hwigo,
gOIhw8i8o = mkldnn_gOIhw8i8o,
gOIhw16i16o = mkldnn_gOIhw16i16o,
gOIhw8i16o2i = mkldnn_gOIhw8i16o2i,
gOIhw8o16i2o = mkldnn_gOIhw8o16i2o,
gOIhw4i16o4i = mkldnn_gOIhw4i16o4i,
gOihw8o = mkldnn_gOihw8o,
gOihw16o = mkldnn_gOihw16o,
gOhwi8o = mkldnn_gOhwi8o,
gOhwi16o = mkldnn_gOhwi16o,
Goihw8g = mkldnn_Goihw8g,
Goihw16g = mkldnn_Goihw16g,
gOIhw8o8i = mkldnn_gOIhw8o8i,
gOIhw16o16i = mkldnn_gOIhw16o16i,
gIOhw16o16i = mkldnn_gIOhw16o16i,
gOhIw16o4i = mkldnn_gOhIw16o4i,
goidhw = mkldnn_goidhw,
gOIdhw16i16o = mkldnn_gOIdhw16i16o,
gOIdhw16o16i = mkldnn_gOIdhw16o16i,
gOidhw16o = mkldnn_gOidhw16o,
gOdhwi16o = mkldnn_gOdhwi16o,
ntc = mkldnn_ntc,
tnc = mkldnn_tnc,
ldsnc = mkldnn_ldsnc,
ldigo = mkldnn_ldigo,
ldigo_p = mkldnn_ldigo_p,
ldgoi = mkldnn_ldgoi,
ldgoi_p = mkldnn_ldgoi_p,
ldgo = mkldnn_ldgo,
wino_fmt = mkldnn_wino_fmt,
format_last = mkldnn_format_last,
};
/// A memory descriptor.
struct desc {
friend struct memory;
/// The underlying C API data structure.
mkldnn_memory_desc_t data;
/// Constructs a memory descriptor.
///
/// @param adims Data dimensions
/// @param adata_type Data precision/type.
/// @param aformat Data layout format.
desc(dims adims, data_type adata_type, format aformat) {
validate_dims(adims);
error::wrap_c_api(
mkldnn_memory_desc_init(&data,
(int)adims.size(),
adims.size() == 0 ? nullptr : &adims[0],
convert_to_c(adata_type),
convert_to_c(aformat)),
"could not initialize a memory descriptor");
}
/// Constructs a memory descriptor from a C API data structure.
///
/// @param adata A C API #mkldnn_memory_desc_t structure.
desc(const mkldnn_memory_desc_t &adata) : data(adata) {}
};
/// A memory primitive descriptor.
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
friend struct memory;
// TODO: make private
primitive_desc() {}
/// Constructs a memory primitive descriptor.
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_memory_primitive_desc_create(
&result, &adesc.data, aengine.get()),
"could not initialize a memory primitive descriptor");
reset(result);
}
/// Returns the memory primitive descriptor.
memory::desc desc() {
auto memory_d = mkldnn_primitive_desc_query_memory_d(get());
return memory::desc(*memory_d);
}
/// Returns the number of bytes required to allocate the memory described
/// including the padding area.
size_t get_size() const {
return mkldnn_memory_primitive_desc_get_size(get());
}
bool operator==(const primitive_desc &other) const {
return mkldnn_memory_primitive_desc_equal(get(), other.get());
}
bool operator!=(const primitive_desc &other) const {
return !operator==(other);
}
engine get_engine() { return engine::query(*this); }
};
/// Constructs a memory primitive from a generic primitive.
///
/// @param aprimitive The primitive to treat as memory.
memory(const primitive &aprimitive) : primitive(aprimitive) {}
/// Constructs a memory primitive.
///
/// @param adesc Memory primitive descriptor.
memory(const primitive_desc &adesc) {
mkldnn_primitive_t result;
error::wrap_c_api(
mkldnn_primitive_create(&result, adesc.get(), nullptr, nullptr),
"could not create a memory primitive");
reset(result);
auto _malloc = [](size_t size, int alignment) {
void *ptr;
#ifdef _WIN32
ptr = _aligned_malloc(size, alignment);
int rc = ((ptr) ? 0 : errno);
#else
int rc = ::posix_memalign(&ptr, alignment, size);
#endif /* _WIN32 */
return (rc == 0) ? (char *)ptr : nullptr;
};
auto _free = [](char *p) {
#ifdef _WIN32
_aligned_free((void *)p);
#else
::free((void *)p);
#endif /* _WIN32 */
};
_handle.reset(_malloc(adesc.get_size(), 4096), _free);
set_data_handle(_handle.get());
}
memory(const primitive_desc &adesc, void *ahandle) {
mkldnn_primitive_t result;
error::wrap_c_api(
mkldnn_primitive_create(&result, adesc.get(), nullptr, nullptr),
"could not create a memory primitive");
reset(result);
set_data_handle(ahandle);
}
/// Returns the descriptor of the memory primitive.
primitive_desc get_primitive_desc() const {
primitive_desc adesc;
const_mkldnn_primitive_desc_t cdesc;
error::wrap_c_api(
mkldnn_primitive_get_primitive_desc(get(), &cdesc),
"could not get primitive descriptor from a memory primitive");
/* FIXME: no const_cast should be here */
adesc.reset(const_cast<mkldnn_primitive_desc_t>(cdesc), true);
return adesc;
}
/// Returns a handle of the data contained in the memory primitive. On
/// the CPU engine, this is a pointer to the allocated memory.
inline void *get_data_handle() const {
void *handle;
error::wrap_c_api(mkldnn_memory_get_data_handle(get(), &handle),
"could not get native handle");
return handle;
}
inline void set_data_handle(void *handle) const {
error::wrap_c_api(mkldnn_memory_set_data_handle(get(), handle),
"could not set native handle");
}
// Must go away or be private:
static mkldnn_data_type_t convert_to_c(data_type adata_type) {
return static_cast<mkldnn_data_type_t>(adata_type);
}
static mkldnn_memory_format_t convert_to_c(format aformat) {
return static_cast<mkldnn_memory_format_t>(aformat);
}
};
inline memory::desc zero_md() {
mkldnn_memory_desc_t zero;
zero.primitive_kind = mkldnn_memory;
return memory::desc(zero);
}
inline memory null_memory(engine eng) {
mkldnn::memory::desc zero = zero_md();
return memory({zero, eng}, nullptr);
}
inline bool is_null_memory(const const_mkldnn_primitive_t &aprimitive) {
const_mkldnn_primitive_desc_t aprimitive_pd;
mkldnn_primitive_get_primitive_desc(aprimitive, &aprimitive_pd);
const mkldnn_memory_desc_t *aprimitive_md =
mkldnn_primitive_desc_query_memory_d(aprimitive_pd);
return ((aprimitive_md != nullptr) && (aprimitive_md->ndims == 0));
}
inline bool operator==(mkldnn_data_type_t a, memory::data_type b) {
return a == memory::convert_to_c(b);
}
inline bool operator!=(mkldnn_data_type_t a, memory::data_type b) {
return !(a == b);
}
inline bool operator==(memory::data_type a, mkldnn_data_type_t b) {
return b == a;
}
inline bool operator!=(memory::data_type a, mkldnn_data_type_t b) {
return !(a == b);
}
inline bool operator==(mkldnn_memory_format_t a, memory::format b) {
return a == memory::convert_to_c(b);
}
inline bool operator!=(mkldnn_memory_format_t a, memory::format b) {
return !(a == b);
}
inline bool operator==(memory::format a, mkldnn_memory_format_t b) {
return b == a;
}
inline bool operator!=(memory::format a, mkldnn_memory_format_t b) {
return !(a == b);
}
/// @}
/// @addtogroup cpp_api_reorder Reorder
/// @{
struct reorder : public primitive {
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const memory::primitive_desc &input,
const memory::primitive_desc &output) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_reorder_primitive_desc_create(
&result, input.get(), output.get()),
"could not create a reorder primitive descriptor");
reset(result);
}
primitive_desc(const memory::primitive_desc &input,
const memory::primitive_desc &output,
const primitive_attr &aattr) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_reorder_primitive_desc_create_v2(
&result, input.get(), output.get(), aattr.get()),
"could not create a reorder primitive descriptor");
reset(result);
}
engine get_engine() { return engine::query(*this); }
};
reorder(const primitive_desc &aprimitive_desc,
const primitive::at &input,
const memory &output) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {input.data};
const_mkldnn_primitive_t outputs[] = {output.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a reorder primitive");
reset(result);
}
reorder(const primitive::at &input, const memory &output) {
auto input_mpd = memory(input).get_primitive_desc();
auto output_mpd = output.get_primitive_desc();
auto reorder_d = primitive_desc(input_mpd, output_mpd);
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {input.data};
const_mkldnn_primitive_t outputs[] = {output.get()};
error::wrap_c_api(
mkldnn_primitive_create(&result, reorder_d.get(), inputs, outputs),
"could not create a reorder primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_view View
/// @{
struct view : public primitive {
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const memory::primitive_desc &input,
memory::dims dims,
memory::dims offsets) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_view_primitive_desc_create(
&result, input.get(), &dims[0], &offsets[0]),
"could not create a view primitive descriptor");
reset(result);
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
view(const primitive_desc &view_pd, primitive::at input) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {input.data};
error::wrap_c_api(
mkldnn_primitive_create(&result, view_pd.get(), inputs, nullptr),
"could not create a view primitive");
reset(result);
}
view(memory input, memory::dims dims, memory::dims offsets) {
mkldnn_primitive_t result;
primitive_desc view_pd(input.get_primitive_desc(), dims, offsets);
mkldnn_primitive_at_t inputs[] = {primitive::at(input).data};
error::wrap_c_api(
mkldnn_primitive_create(&result, view_pd.get(), inputs, nullptr),
"could not create a view primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_concat Concat
/// @{
struct concat : public primitive {
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
std::vector<const_mkldnn_primitive_desc_t> cpp_to_c(
std::vector<memory::primitive_desc> inputs) {
std::vector<const_mkldnn_primitive_desc_t> c_api_inputs;
c_api_inputs.reserve(inputs.size());
auto convert_to_c = [](memory::primitive_desc d) { return d.get(); };
std::transform(inputs.begin(),
inputs.end(),
std::back_inserter(c_api_inputs),
convert_to_c);
return c_api_inputs;
}
primitive_desc(const memory::desc &output,
int concat_dimension,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
error::wrap_c_api(
mkldnn_concat_primitive_desc_create(&result,
&output.data,
(int)c_api_inputs.size(),
concat_dimension,
&c_api_inputs[0]),
"could not create a concat primitive descriptor");
reset(result);
}
primitive_desc(int concat_dimension,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
error::wrap_c_api(
mkldnn_concat_primitive_desc_create(&result,
nullptr,
(int)c_api_inputs.size(),
concat_dimension,
&c_api_inputs[0]),
"could not create a concat primitive descriptor");
reset(result);
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
concat(const primitive_desc &concat_pd,
std::vector<primitive::at> &inputs,
const memory &output) {
mkldnn_primitive_t result;
std::vector<mkldnn_primitive_at_t> p_inputs;
for (size_t i = 0; i < inputs.size(); i++)
p_inputs.push_back(inputs[i].data);
const_mkldnn_primitive_t outputs[] = {output.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, concat_pd.get(), &p_inputs[0], outputs),
"could not create a concat primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_sum Sum
/// @{
struct sum : public primitive {
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
std::vector<const_mkldnn_primitive_desc_t> cpp_to_c(
std::vector<memory::primitive_desc> inputs) {
std::vector<const_mkldnn_primitive_desc_t> c_api_inputs;
c_api_inputs.reserve(inputs.size());
auto convert_to_c = [](memory::primitive_desc d) { return d.get(); };
std::transform(inputs.begin(),
inputs.end(),
std::back_inserter(c_api_inputs),
convert_to_c);
return c_api_inputs;
}
primitive_desc(const memory::desc &output,
const std::vector<float> &scales,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
error::wrap_c_api(
mkldnn_sum_primitive_desc_create(&result,
&output.data,
(int)c_api_inputs.size(),
&scales[0],
&c_api_inputs[0]),
"could not create a sum primitive descriptor");
reset(result);
}
primitive_desc(const std::vector<float> &scales,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
error::wrap_c_api(
mkldnn_sum_primitive_desc_create(&result,
nullptr,
(int)c_api_inputs.size(),
&scales[0],
&c_api_inputs[0]),
"could not create a sum primitive descriptor");
reset(result);
}
/** @deprecated: api backwards compatibility for double scales type */
MKLDNN_DEPRECATED
primitive_desc(const memory::desc &output,
std::vector<double> scale,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
auto scale_f = scale_to_float(scale);
error::wrap_c_api(
mkldnn_sum_primitive_desc_create(&result,
&output.data,
(int)c_api_inputs.size(),
&scale_f[0],
&c_api_inputs[0]),
"could not create a sum primitive descriptor");
reset(result);
}
/** @deprecated: api backwards compatibility for double scales type */
MKLDNN_DEPRECATED
primitive_desc(std::vector<double> scale,
std::vector<memory::primitive_desc> inputs) {
mkldnn_primitive_desc_t result;
auto c_api_inputs = cpp_to_c(inputs);
auto scale_f = scale_to_float(scale);
error::wrap_c_api(
mkldnn_sum_primitive_desc_create(&result,
nullptr,
(int)c_api_inputs.size(),
&scale_f[0],
&c_api_inputs[0]),
"could not create a sum primitive descriptor");
reset(result);
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
sum(const primitive_desc &sum_pd,
std::vector<primitive::at> &inputs,
const memory &output) {
mkldnn_primitive_t result;
std::vector<mkldnn_primitive_at_t> p_inputs;
for (size_t i = 0; i < inputs.size(); i++)
p_inputs.push_back(inputs[i].data);
const_mkldnn_primitive_t outputs[] = {output.get()};
error::wrap_c_api(
mkldnn_primitive_create(&result, sum_pd.get(), &p_inputs[0], outputs),
"could not create a sum primitive");
reset(result);
}
private:
static std::vector<float> scale_to_float(const std::vector<double> &vd) {
std::vector<float> vf(vd.size());
std::transform(
vd.begin(), vd.end(), vf.begin(), [=](double x) { return (float)x; });
return vf;
}
};
/// @}
/// @addtogroup cpp_api_convolution Convolution
/// @{
struct convolution_forward : public primitive {
struct desc {
mkldnn_convolution_desc_t data;
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &bias_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(mkldnn_convolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
&bias_desc.data,
&dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution forward descriptor");
}
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(mkldnn_convolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
nullptr,
&dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution forward descriptor");
}
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &bias_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims dilates,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(dilates);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_dilated_convolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
&bias_desc.data,
&dst_desc.data,
&strides[0],
&dilates[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a dilated convolution forward descriptor");
}
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims dilates,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(dilates);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_dilated_convolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
nullptr,
&dst_desc.data,
&strides[0],
&dilates[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a dilated convolution forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a convolution forward primitive descriptor");
reset(result);
}
primitive_desc(const desc &adesc,
const primitive_attr &aattr,
const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create_v2(
&result, &adesc.data, aattr.get(), aengine.get(), nullptr),
"could not create a convolution forward primitive descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
convolution_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const primitive::at &bias,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution forward bias primitive");
reset(result);
}
convolution_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution forward primitive");
reset(result);
}
};
struct convolution_backward_data : public primitive {
struct desc {
mkldnn_convolution_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &diff_src_desc,
const memory::desc &weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_convolution_backward_data_desc_init(
&data,
convert_to_c(aalgorithm),
&diff_src_desc.data,
&weights_desc.data,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward data descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &diff_src_desc,
const memory::desc &weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims dilates,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(dilates);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_dilated_convolution_backward_data_desc_init(
&data,
convert_to_c(aalgorithm),
&diff_src_desc.data,
&weights_desc.data,
&diff_dst_desc.data,
&strides[0],
&dilates[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward data descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const convolution_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a convolution backward data primitive descriptor");
reset(result);
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
convolution_backward_data(const primitive_desc &aprimitive_desc,
const primitive::at &diff_dst,
const primitive::at &weights,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution backward data primitive");
reset(result);
}
};
struct convolution_backward_weights : public primitive {
struct desc {
mkldnn_convolution_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_bias_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_convolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
&diff_bias_desc.data,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward weights descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_convolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
nullptr,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward weights descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_bias_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims dilates,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(dilates);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_dilated_convolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
&diff_bias_desc.data,
&diff_dst_desc.data,
&strides[0],
&dilates[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward weights descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims dilates,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(dilates);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_dilated_convolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
nullptr,
&diff_dst_desc.data,
&strides[0],
&dilates[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a convolution backward weights descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const convolution_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a convolution backward weights primitive "
"descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
convolution_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_weights,
const memory &diff_bias) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution backward weights primitive");
reset(result);
}
convolution_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_weights) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution backward weights primitive");
reset(result);
}
};
struct convolution_relu_forward : public primitive {
struct desc {
mkldnn_convolution_relu_desc_t data;
desc(const convolution_forward::desc conv_desc,
const float negative_slope) {
error::wrap_c_api(
mkldnn_convolution_relu_desc_init(
&data, &conv_desc.data, negative_slope),
"could not create a convolution_relu_forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a convolution relu forward descriptor");
reset(result);
}
engine get_engine() { return engine::query(*this); }
};
convolution_relu_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const primitive::at &bias,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution relu forward primitive");
reset(result);
}
convolution_relu_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a convolution relu forward primitive");
reset(result);
}
};
/// @}
//
/// @addtogroup cpp_api_deconvolution Deconvolution
/// @{
struct deconvolution_forward : public primitive {
struct desc {
mkldnn_deconvolution_desc_t data;
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &bias_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(mkldnn_deconvolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
&bias_desc.data,
&dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a deconvolution forward descriptor");
}
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(mkldnn_deconvolution_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&weights_desc.data,
nullptr,
&dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a deconvolution forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a deconvolution forward primitive descriptor");
reset(result);
}
primitive_desc(const desc &adesc,
const primitive_attr &aattr,
const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create_v2(
&result, &adesc.data, aattr.get(), aengine.get(), nullptr),
"could not create a deconvolution forward primitive descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
deconvolution_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const primitive::at &bias,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a deconvolution forward bias primitive");
reset(result);
}
deconvolution_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a deconvolution forward primitive");
reset(result);
}
};
struct deconvolution_backward_data : public primitive {
struct desc {
mkldnn_deconvolution_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &diff_src_desc,
const memory::desc &weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_deconvolution_backward_data_desc_init(
&data,
convert_to_c(aalgorithm),
&diff_src_desc.data,
&weights_desc.data,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a deconvolution backward data descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const deconvolution_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a deconvolution backward data primitive "
"descriptor");
reset(result);
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
deconvolution_backward_data(const primitive_desc &aprimitive_desc,
const primitive::at &diff_dst,
const primitive::at &weights,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a deconvolution backward data primitive");
reset(result);
}
};
struct deconvolution_backward_weights : public primitive {
struct desc {
mkldnn_deconvolution_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_bias_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_deconvolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
&diff_bias_desc.data,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a deconvolution backward weights descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_dst_desc,
const memory::dims strides,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_deconvolution_backward_weights_desc_init(
&data,
convert_to_c(aalgorithm),
&src_desc.data,
&diff_weights_desc.data,
nullptr,
&diff_dst_desc.data,
&strides[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not create a deconvolution backward weights descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const deconvolution_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a deconvolution backward weights primitive "
"descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
deconvolution_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_weights,
const memory &diff_bias) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a deconvolution backward weights primitive");
reset(result);
}
deconvolution_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_weights) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a deconvolution backward weights primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_lrn LRN
/// @{
struct lrn_forward : public primitive {
struct desc {
mkldnn_lrn_desc_t data;
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
int local_size,
float alpha,
float beta,
float k) {
error::wrap_c_api(
mkldnn_lrn_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
local_size,
alpha,
beta,
k),
"could not create a lrn forward descriptor");
}
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
int local_size,
float alpha,
float beta) {
error::wrap_c_api(
mkldnn_lrn_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
local_size,
alpha,
beta,
float(1.0)),
"could not create a lrn forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a lrn forward primitive descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t ldesc;
const_mkldnn_primitive_desc_t const_ldesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc),
"could not clone a workspace primitive descriptor");
adesc.reset(ldesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
lrn_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &workspace,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get(), workspace.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a lrn forward primitive");
reset(result);
}
lrn_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a lrn forward primitive");
reset(result);
}
};
struct lrn_backward : public primitive {
struct desc {
mkldnn_lrn_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &data_desc,
const memory::desc &diff_data_desc,
int local_size,
float alpha,
float beta,
float k) {
error::wrap_c_api(mkldnn_lrn_backward_desc_init(&data,
convert_to_c(aalgorithm),
&diff_data_desc.data,
&data_desc.data,
local_size,
alpha,
beta,
k),
"could not create a lrn backward descriptor");
}
desc(algorithm aalgorithm,
const memory::desc &data_desc,
const memory::desc &diff_data_desc,
int local_size,
float alpha,
float beta) {
error::wrap_c_api(mkldnn_lrn_backward_desc_init(&data,
convert_to_c(aalgorithm),
&diff_data_desc.data,
&data_desc.data,
local_size,
alpha,
beta,
float(1.0)),
"could not create a lrn backward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc,
const engine &aengine,
const lrn_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a backward lrn primitive descriptor");
reset(result);
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t ldesc;
const_mkldnn_primitive_desc_t const_ldesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc),
"could not clone a workspace primitive descriptor");
adesc.reset(ldesc);
return adesc;
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff_dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
lrn_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const primitive::at &workspace,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data, workspace.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a lrn backward primitive");
reset(result);
}
lrn_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a lrn backward primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_pooling Pooling
/// @{
struct pooling_forward : public primitive {
struct desc {
mkldnn_pooling_desc_t data;
desc(prop_kind aprop_kind,
algorithm aalgorithm,
const memory::desc &src_desc,
const memory::desc &dst_desc,
const memory::dims strides,
const memory::dims kernel,
const memory::dims padding_l,
const memory::dims padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(kernel);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(
mkldnn_pooling_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
convert_to_c(aalgorithm),
&src_desc.data,
&dst_desc.data,
&strides[0],
&kernel[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not init a forward pooling descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a forward pooling primitive descriptor");
reset(result);
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a workspace primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
pooling_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get(), nullptr};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a pooling forward primitive");
reset(result);
}
pooling_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst,
const memory &workspace) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get(), workspace.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a pooling forward primitive");
reset(result);
}
};
struct pooling_backward : public primitive {
struct desc {
mkldnn_pooling_desc_t data;
desc(algorithm aalgorithm,
const memory::desc &diff_src_desc,
const memory::desc &diff_dst_desc,
const memory::dims &strides,
const memory::dims &kernel,
const memory::dims &padding_l,
const memory::dims &padding_r,
const padding_kind apadding_kind) {
memory::validate_dims(strides);
memory::validate_dims(kernel);
memory::validate_dims(padding_l);
memory::validate_dims(padding_r);
error::wrap_c_api(mkldnn_pooling_backward_desc_init(
&data,
convert_to_c(aalgorithm),
&diff_src_desc.data,
&diff_dst_desc.data,
&strides[0],
&kernel[0],
&padding_l[0],
&padding_r[0],
mkldnn::convert_to_c(apadding_kind)),
"could not init a backward pooling descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const pooling_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a backward pooling primitive descriptor");
reset(result);
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
pooling_backward(const primitive_desc &aprimitive_desc,
const primitive::at &diff_dst,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a pooling backward primitive");
reset(result);
}
pooling_backward(const primitive_desc &aprimitive_desc,
const primitive::at &diff_dst,
const primitive::at &workspace,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {diff_dst.data, workspace.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a pooling backward primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_eltwise Eltwise
/// @{
struct eltwise_forward : public primitive {
struct desc {
mkldnn_eltwise_desc_t data;
template <typename T>
desc(prop_kind aprop_kind,
algorithm alg_kind,
const memory::desc &src_desc,
T alpha = 0,
T beta = 0) {
error::wrap_c_api(
mkldnn_eltwise_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
mkldnn::convert_to_c(alg_kind),
&src_desc.data,
static_cast<float>(alpha),
static_cast<float>(beta)),
"could not create a eltwise forward descriptor");
}
/** @deprecated: api backward compatibility for relu */
template <typename T>
MKLDNN_DEPRECATED desc(prop_kind aprop_kind,
const memory::desc &src_desc,
T negative_slope)
: desc(aprop_kind, eltwise_relu, src_desc, negative_slope) {}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a eltwise forward primitive descriptor");
reset(result);
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
eltwise_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a eltwise forward primitive");
reset(result);
}
};
typedef eltwise_forward relu_forward;
struct eltwise_backward : public primitive {
struct desc {
mkldnn_eltwise_desc_t data;
template <typename T>
desc(algorithm alg_kind,
const memory::desc &diff_data_desc,
const memory::desc &data_desc,
T alpha = 0,
T beta = 0) {
error::wrap_c_api(
mkldnn_eltwise_backward_desc_init(&data,
mkldnn::convert_to_c(alg_kind),
&diff_data_desc.data,
&data_desc.data,
static_cast<float>(alpha),
static_cast<float>(beta)),
"could not create a eltwise backward descriptor");
}
/** @deprecated: api backward compatibility for relu */
template <typename T>
MKLDNN_DEPRECATED desc(const memory::desc &diff_data_desc,
const memory::desc &data_desc,
T negative_slope)
: desc(eltwise_relu, diff_data_desc, data_desc, negative_slope) {}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const eltwise_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a eltwise backward primitive descriptor");
reset(result);
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
eltwise_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &diff_dst,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a eltwise backward primitive");
reset(result);
}
};
typedef eltwise_backward relu_backward;
/// @}
/// @addtogroup cpp_api_softmax Softmax
/// @{
struct softmax_forward : public primitive {
struct desc {
mkldnn_softmax_desc_t data;
desc(prop_kind aprop_kind,
const memory::desc &data_desc,
int softmax_axis) {
error::wrap_c_api(
mkldnn_softmax_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
&data_desc.data,
softmax_axis),
"could not create a softmax forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a softmax forward primitive descriptor");
reset(result);
}
engine get_engine() { return engine::query(*this); }
};
softmax_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a softmax forward primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_batch_norm Batch normalization
/// @{
struct batch_normalization_forward : public primitive {
struct desc {
mkldnn_batch_normalization_desc_t data;
template <typename T>
desc(prop_kind aprop_kind,
const memory::desc &src_desc,
T epsilon,
unsigned flags) {
error::wrap_c_api(
mkldnn_batch_normalization_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
&src_desc.data,
static_cast<float>(epsilon),
flags),
"could not create a batch normalization forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a batch normalization forward "
"primitive descriptor");
reset(result);
}
primitive_desc(const desc &adesc,
const primitive_attr &aattr,
const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create_v2(
&result, &adesc.data, aattr.get(), aengine.get(), nullptr),
"could not create a batch normalization forward "
"primitive descriptor");
reset(result);
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t bndesc;
const_mkldnn_primitive_desc_t const_bndesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a weights primitive descriptor");
adesc.reset(bndesc);
return adesc;
}
memory::primitive_desc mean_primitive_desc() const {
memory::primitive_desc aprimitive_desc;
mkldnn_primitive_desc_t bndesc;
mkldnn_batch_normalization_desc_t *p;
error::wrap_c_api(
mkldnn_primitive_desc_query(
get(), mkldnn::convert_to_c(batch_normalization_d), 0, &p),
"could not get a batch-normalization descriptor");
const_mkldnn_primitive_desc_t const_bndesc =
(p->flags & use_global_stats)
? mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 1)
: mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a mean primitive descriptor");
aprimitive_desc.reset(bndesc);
return aprimitive_desc;
}
memory::primitive_desc variance_primitive_desc() const {
memory::primitive_desc aprimitive_desc;
mkldnn_primitive_desc_t bndesc;
mkldnn_batch_normalization_desc_t *p;
error::wrap_c_api(
mkldnn_primitive_desc_query(
get(), mkldnn::convert_to_c(batch_normalization_d), 0, &p),
"could not get a batch-normalization descriptor");
const_mkldnn_primitive_desc_t const_bndesc =
(p->flags & use_global_stats)
? mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 2)
: mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 2);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a variance primitive descriptor");
aprimitive_desc.reset(bndesc);
return aprimitive_desc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a workspace primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const primitive::at &weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {
src.data, mean.data, variance.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, mean.data, variance.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
/// @warning batch_normalization_forward has 2 constructors with very
/// similar signatures:
/// - (pd, src, weights, dst, mean, variance) // 2 in, 3 out
/// - (pd, src, dst, mean, variance, workspace) // 1 in, 4 out
/// The only way to distinguish between those is to explicitly
/// cast all input parameters to their type, i.e. to
/// const primitive:at &.
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst,
const memory &mean,
const memory &variance) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {
dst.get(), mean.get(), variance.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst,
const memory &mean,
const memory &variance,
const memory &workspace) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {
dst.get(), mean.get(), variance.get(), workspace.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst,
const memory &mean,
const memory &variance) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {
dst.get(), mean.get(), variance.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
/// @warning batch_normalization_forward has 2 constructors with very
/// similar signatures:
/// - (pd, src, weights, dst, mean, variance) // 2 in, 3 out
/// - (pd, src, dst, mean, variance, workspace) // 1 in, 4 out
/// The only way to distinguish between those is to explicitly
/// cast all input parameters to their type, i.e. to
/// const primitive:at &.
/// @note to make users' experience a little bit better this constructor
/// checks if whether parameters match corresponding primitive
/// descriptor, and if they are not -- call the other (proper)
/// constructor. Yeah, this is still very ugly...
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst,
const memory &mean,
const memory &variance,
const memory &workspace) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[2] = {src.data};
const_mkldnn_primitive_t outputs[4] = {
dst.get(), mean.get(), variance.get(), workspace.get()};
if (1) { // check whether this is the `wrong` constructor
const int n_inputs_expected = mkldnn_primitive_desc_query_s32(
aprimitive_desc.get(), mkldnn_query_num_of_inputs_s32, 0);
const int n_outputs_expected = mkldnn_primitive_desc_query_s32(
aprimitive_desc.get(), mkldnn_query_num_of_outputs_s32, 0);
if (n_inputs_expected == 2 && n_outputs_expected == 3) {
// shift parameters, get rid of workspace, and add weights...
auto _weights = dst;
inputs[1] = {_weights.get(), 0};
auto _dst = mean, _mean = variance, _variance = workspace;
outputs[0] = _dst.get();
outputs[1] = _mean.get();
outputs[2] = _variance.get();
outputs[3] = nullptr;
}
}
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
batch_normalization_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization forward primitive");
reset(result);
}
};
struct batch_normalization_backward : public primitive {
struct desc {
mkldnn_batch_normalization_desc_t data;
template <typename T>
desc(prop_kind aprop_kind,
const memory::desc &diff_data_desc,
const memory::desc &data_desc,
T epsilon,
unsigned flags) {
error::wrap_c_api(
mkldnn_batch_normalization_backward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
&diff_data_desc.data,
&data_desc.data,
static_cast<float>(epsilon),
flags),
"could not create a batch normalization backward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc,
const engine &aengine,
const batch_normalization_forward::primitive_desc
&hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a batch normalization backward primitive "
"descriptor");
reset(result);
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t bndesc;
const_mkldnn_primitive_desc_t const_bndesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a weights primitive descriptor");
adesc.reset(bndesc);
return adesc;
}
memory::primitive_desc diff_weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t bndesc;
const_mkldnn_primitive_desc_t const_bndesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a diff_weights primitive descriptor");
adesc.reset(bndesc);
return adesc;
}
memory::primitive_desc mean_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t bndesc;
const_mkldnn_primitive_desc_t const_bndesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a mean primitive descriptor");
adesc.reset(bndesc);
return adesc;
}
memory::primitive_desc variance_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t bndesc;
const_mkldnn_primitive_desc_t const_bndesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 2);
error::wrap_c_api(mkldnn_primitive_desc_clone(&bndesc, const_bndesc),
"could not clone a variance primitive descriptor");
adesc.reset(bndesc);
return adesc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a workspace primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
// Prop_kind == backward
batch_normalization_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const primitive::at &diff_dst,
const primitive::at &weights,
const memory &diff_src,
const memory &diff_weights) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {
src.data, mean.data, variance.data, diff_dst.data, weights.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get(), diff_weights.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization backward primitive");
reset(result);
}
// Prop_kind == backward (+ws)
batch_normalization_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const primitive::at &diff_dst,
const primitive::at &weights,
const primitive::at &workspace,
const memory &diff_src,
const memory &diff_weights) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data,
mean.data,
variance.data,
diff_dst.data,
weights.data,
workspace.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get(), diff_weights.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization backward primitive");
reset(result);
}
// Prop_kind == backward_data (+ws or +weights)
/// @warning This constructor works for backward_data propagation
/// - w/ weights but w/o workspace, or
/// - w/ workspace but w/o weights
batch_normalization_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const primitive::at &diff_dst,
const primitive::at &weights_or_workspace,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data,
mean.data,
variance.data,
diff_dst.data,
weights_or_workspace.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization backward primitive");
reset(result);
}
// Prop_kind == backward_data
batch_normalization_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at &mean,
const primitive::at &variance,
const primitive::at &diff_dst,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {
src.data, mean.data, variance.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a batch normalization backward primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_inner_product Inner Product
/// @{
struct inner_product_forward : public primitive {
struct desc {
mkldnn_inner_product_desc_t data;
desc(prop_kind aprop_kind,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &bias_desc,
const memory::desc &dst_desc) {
error::wrap_c_api(mkldnn_inner_product_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
&src_desc.data,
&weights_desc.data,
&bias_desc.data,
&dst_desc.data),
"could not create a inner product forward descriptor");
}
desc(prop_kind aprop_kind,
const memory::desc &src_desc,
const memory::desc &weights_desc,
const memory::desc &dst_desc) {
error::wrap_c_api(mkldnn_inner_product_forward_desc_init(
&data,
mkldnn::convert_to_c(aprop_kind),
&src_desc.data,
&weights_desc.data,
nullptr,
&dst_desc.data),
"could not create a inner product forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create a inner product forward primitive descriptor");
reset(result);
}
primitive_desc(const desc &adesc,
const primitive_attr &aattr,
const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create_v2(
&result, &adesc.data, aattr.get(), aengine.get(), nullptr),
"could not create a inner product "
"forward primitive descriptor");
reset(result);
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
inner_product_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at weights,
const primitive::at &bias,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data, bias.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a inner product forward primitive");
reset(result);
}
inner_product_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at weights,
const memory &dst) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, weights.data};
const_mkldnn_primitive_t outputs[] = {dst.get()};
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a inner product forward primitive");
reset(result);
}
};
struct inner_product_backward_data : public primitive {
struct desc {
mkldnn_inner_product_desc_t data;
desc(const memory::desc &diff_src_desc,
const memory::desc &weights_desc,
const memory::desc &diff_dst_desc) {
error::wrap_c_api(
mkldnn_inner_product_backward_data_desc_init(&data,
&diff_src_desc.data,
&weights_desc.data,
&diff_dst_desc.data),
"could not create a inner product backward data descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const inner_product_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a inner product backward data primitive "
"descriptor");
reset(result);
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff dst primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
inner_product_backward_data(const primitive_desc &aprimitive_desc,
const primitive::at &diff_dst,
const primitive::at weights,
const memory &diff_src) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {diff_dst.data, weights.data};
const_mkldnn_primitive_t outputs[] = {diff_src.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a inner product backward data primitive");
reset(result);
}
};
struct inner_product_backward_weights : public primitive {
struct desc {
mkldnn_inner_product_desc_t data;
desc(const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_bias_desc,
const memory::desc &diff_dst_desc) {
error::wrap_c_api(
mkldnn_inner_product_backward_weights_desc_init(
&data,
&src_desc.data,
&diff_weights_desc.data,
&diff_bias_desc.data,
&diff_dst_desc.data),
"could not create a inner product backward weights descriptor");
}
desc(const memory::desc &src_desc,
const memory::desc &diff_weights_desc,
const memory::desc &diff_dst_desc) {
error::wrap_c_api(
mkldnn_inner_product_backward_weights_desc_init(
&data,
&src_desc.data,
&diff_weights_desc.data,
nullptr,
&diff_dst_desc.data),
"could not create a inner product backward weights descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(
const desc &adesc,
const engine &aengine,
const inner_product_forward::primitive_desc &hint_fwd_primitive_desc) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(&result,
&adesc.data,
aengine.get(),
hint_fwd_primitive_desc.get()),
"could not create a inner product backward weights primitive "
"descriptor");
reset(result);
}
memory::primitive_desc diff_dst_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff dst primititve descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_weights_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a diff bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc src_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
inner_product_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at diff_dst,
const memory &diff_weights) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a inner product backward weights primitive");
reset(result);
}
inner_product_backward_weights(const primitive_desc &aprimitive_desc,
const primitive::at &src,
const primitive::at diff_dst,
const memory &diff_weights,
const memory &diff_bias) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[] = {src.data, diff_dst.data};
const_mkldnn_primitive_t outputs[] = {diff_weights.get(), diff_bias.get()};
error::wrap_c_api(
mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create a inner product backward weights primitive");
reset(result);
}
};
/// @}
/// @addtogroup cpp_api_rnn RNN
/// @{
struct rnn_cell {
struct desc {
mkldnn_rnn_cell_desc_t c_rnn_cell_;
desc(algorithm kind, algorithm activation_f) {
error::wrap_c_api(
mkldnn_rnn_cell_desc_init(&c_rnn_cell_,
mkldnn::convert_to_c(kind),
mkldnn::convert_to_c(activation_f),
0U,
0,
0),
"could not init an rnn cell descriptor");
}
desc(algorithm kind) : desc(kind, algorithm::algorithm_undef) {}
operator const mkldnn_rnn_cell_desc_t *() const { return &c_rnn_cell_; }
algorithm get_cell_kind() const { return algorithm(c_rnn_cell_.cell_kind); }
algorithm get_activation() const {
return algorithm(c_rnn_cell_.activation_kind);
}
float get_alpha() const { return c_rnn_cell_.alpha; }
void set_alpha(float alpha) {
c_rnn_cell_.flags |= mkldnn_rnn_cell_with_relu;
c_rnn_cell_.alpha = alpha;
}
float get_clipping() const { return c_rnn_cell_.clipping; }
void set_clipping(float clipping) {
c_rnn_cell_.flags |= mkldnn_rnn_cell_with_clipping;
c_rnn_cell_.clipping = clipping;
}
int get_gates_count() const {
return mkldnn_rnn_cell_get_gates_count(&c_rnn_cell_);
}
int get_state_count() const {
return mkldnn_rnn_cell_get_states_count(&c_rnn_cell_);
}
};
};
struct rnn_forward : public primitive {
struct desc {
mkldnn_rnn_desc_t data;
desc(prop_kind aprop_kind,
rnn_cell::desc cell,
const rnn_direction direction,
const memory::desc &src_layer_desc,
const memory::desc &src_iter_desc,
const memory::desc &weights_layer_desc,
const memory::desc &weights_iter_desc,
const memory::desc &bias_desc,
const memory::desc &dst_layer_desc,
const memory::desc &dst_iter_desc) {
error::wrap_c_api(
mkldnn_rnn_forward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
cell,
mkldnn::convert_to_c(direction),
&src_layer_desc.data,
&src_iter_desc.data,
&weights_layer_desc.data,
&weights_iter_desc.data,
&bias_desc.data,
&dst_layer_desc.data,
&dst_iter_desc.data),
"could not create an RNN forward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create an RNN forward primitive descriptor");
reset(result);
}
memory::primitive_desc src_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone an src layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc src_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src iter primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_src_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 2);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t ldesc;
const_mkldnn_primitive_desc_t const_ldesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc),
"could not clone a workspace primitive descriptor");
adesc.reset(ldesc);
return adesc;
}
memory::primitive_desc dst_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 1);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last iteration primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
rnn_forward(const primitive_desc &aprimitive_desc,
const primitive::at &src_layer,
const primitive::at &src_iter,
const primitive::at &weights_layer,
const primitive::at &weights_iter,
const primitive::at &bias,
const memory &dst_layer,
const memory &dst_iter,
const memory &workspace) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[5];
const_mkldnn_primitive_t outputs[3];
int idx = 0;
inputs[idx++] = src_layer.data;
if (!is_null_memory(src_iter.data.primitive)) inputs[idx++] = src_iter.data;
inputs[idx++] = weights_layer.data;
inputs[idx++] = weights_iter.data;
if (!is_null_memory(bias.data.primitive)) inputs[idx++] = bias.data;
idx = 0;
outputs[idx++] = dst_layer.get();
if (!is_null_memory(dst_iter.get())) outputs[idx++] = dst_iter.get();
if (!is_null_memory(workspace.get())) outputs[idx++] = workspace.get();
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create an RNN forward primitive");
reset(result);
}
};
struct rnn_backward : public primitive {
struct desc {
mkldnn_rnn_desc_t data;
desc(prop_kind aprop_kind,
rnn_cell::desc cell,
const rnn_direction direction,
const memory::desc &src_layer_desc,
const memory::desc &src_iter_desc,
const memory::desc &weights_layer_desc,
const memory::desc &weights_iter_desc,
const memory::desc &bias_desc,
const memory::desc &dst_layer_desc,
const memory::desc &dst_iter_desc,
const memory::desc &diff_src_layer_desc,
const memory::desc &diff_src_iter_desc,
const memory::desc &diff_weights_layer_desc,
const memory::desc &diff_weights_iter_desc,
const memory::desc &diff_bias_desc,
const memory::desc &diff_dst_layer_desc,
const memory::desc &diff_dst_iter_desc) {
error::wrap_c_api(
mkldnn_rnn_backward_desc_init(&data,
mkldnn::convert_to_c(aprop_kind),
cell,
mkldnn::convert_to_c(direction),
&src_layer_desc.data,
&src_iter_desc.data,
&weights_layer_desc.data,
&weights_iter_desc.data,
&bias_desc.data,
&dst_layer_desc.data,
&dst_iter_desc.data,
&diff_src_layer_desc.data,
&diff_src_iter_desc.data,
&diff_weights_layer_desc.data,
&diff_weights_iter_desc.data,
&diff_bias_desc.data,
&diff_dst_layer_desc.data,
&diff_dst_iter_desc.data),
"could not create an RNN backward descriptor");
}
};
struct primitive_desc : public handle<mkldnn_primitive_desc_t> {
primitive_desc(const desc &adesc, const engine &aengine) {
mkldnn_primitive_desc_t result;
error::wrap_c_api(
mkldnn_primitive_desc_create(
&result, &adesc.data, aengine.get(), nullptr),
"could not create an RNN backward primitive descriptor");
reset(result);
}
memory::primitive_desc src_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone an src layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc src_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(src_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src iter primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc weights_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(weights_pd), 2);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 0);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc dst_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(dst_pd), 1);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last iteration primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_src_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone an src_layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_src_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_src_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a src iter primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_weights_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_weights_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 1);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a weights primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_bias_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_weights_pd), 2);
error::wrap_c_api(mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a bias primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_layer_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 0);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last layer primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc diff_dst_iter_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t cdesc;
const_mkldnn_primitive_desc_t const_cdesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(diff_dst_pd), 1);
error::wrap_c_api(
mkldnn_primitive_desc_clone(&cdesc, const_cdesc),
"could not clone a dst last iteration primitive descriptor");
adesc.reset(cdesc);
return adesc;
}
memory::primitive_desc workspace_primitive_desc() const {
memory::primitive_desc adesc;
mkldnn_primitive_desc_t ldesc;
const_mkldnn_primitive_desc_t const_ldesc =
mkldnn_primitive_desc_query_pd(
get(), mkldnn::convert_to_c(workspace_pd), 0);
error::wrap_c_api(mkldnn_primitive_desc_clone(&ldesc, const_ldesc),
"could not clone a workspace primitive descriptor");
adesc.reset(ldesc);
return adesc;
}
engine get_engine() { return engine::query(*this); }
};
// With last iteration (with and without input src_iter)
rnn_backward(const primitive_desc &aprimitive_desc,
const primitive::at &src_layer,
const primitive::at &src_iter,
const primitive::at &weights_layer,
const primitive::at &weights_iter,
const primitive::at &bias,
const primitive::at &dst_layer,
const primitive::at &dst_iter,
const memory &diff_src_layer,
const memory &diff_src_iter,
const memory &diff_weights_layer,
const memory &diff_weights_iter,
const memory &diff_bias,
const primitive::at &diff_dst_layer,
const primitive::at &diff_dst_iter,
const primitive::at &workspace) {
mkldnn_primitive_t result;
mkldnn_primitive_at_t inputs[10];
const_mkldnn_primitive_t outputs[5];
int idx = 0;
inputs[idx] = src_layer.data;
if (!is_null_memory(src_iter.data.primitive)) inputs[idx++] = src_iter.data;
inputs[idx++] = weights_layer.data;
inputs[idx++] = weights_iter.data;
if (!is_null_memory(bias.data.primitive)) inputs[idx++] = bias.data;
inputs[idx] = dst_layer.data;
if (!is_null_memory(dst_iter.data.primitive)) inputs[idx++] = dst_iter.data;
inputs[idx] = diff_dst_layer.data;
if (!is_null_memory(diff_dst_iter.data.primitive))
inputs[idx++] = diff_dst_iter.data;
inputs[idx] = workspace.data;
idx = 0;
outputs[idx] = diff_src_layer.get();
if (!is_null_memory(diff_src_iter.get()))
outputs[idx++] = diff_src_iter.get();
outputs[idx] = diff_weights_layer.get();
outputs[idx] = diff_weights_iter.get();
if (!is_null_memory(diff_bias.get())) outputs[idx] = diff_bias.get();
error::wrap_c_api(mkldnn_primitive_create(
&result, aprimitive_desc.get(), inputs, outputs),
"could not create an RNN backward primitive");
reset(result);
}
};
/// @}
/// @} Primitives
/// @addtogroup cpp_api_stream Stream
/// @{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <>
struct handle_traits<mkldnn_stream_t> {
static constexpr auto destructor = &mkldnn_stream_destroy;
};
#endif
struct stream : public handle<mkldnn_stream_t> {
using handle::handle;
enum kind {
any = mkldnn_stream_kind_t::mkldnn_any_stream,
eager = mkldnn_stream_kind_t::mkldnn_eager,
lazy = mkldnn_stream_kind_t::mkldnn_lazy
};
static mkldnn_stream_kind_t convert_to_c(kind akind) {
return static_cast<mkldnn_stream_kind_t>(akind);
}
/// Constructs a stream.
stream(kind akind) {
mkldnn_stream_t astream;
error::wrap_c_api(mkldnn_stream_create(&astream, convert_to_c(akind)),
"could not create a stream");
reset(astream);
}
/// Submits a vector of primitives to a stream for computations.
///
/// @param primitives The vector of primitives to submit.
/// @returns The stream.
stream &submit(std::vector<primitive> primitives) {
// TODO: find a proper way to convert vector<primitive> to
// vector<mkldnn_primitive_t>
if (primitives.size() == 0) return *this;
std::vector<mkldnn_primitive_t> c_api_primitives;
c_api_primitives.reserve(primitives.size());
auto convert_to_c = [](primitive p) { return p.get(); };
std::transform(primitives.begin(),
primitives.end(),
std::back_inserter(c_api_primitives),
convert_to_c);
mkldnn_primitive_t c_api_error_primitive;
error::wrap_c_api(mkldnn_stream_submit(get(),
c_api_primitives.size(),
&c_api_primitives[0],
&c_api_error_primitive),
"could not submit primitives to a stream",
&c_api_error_primitive);
return *this;
}
/// Waits for all computations submitted to the stream to complete.
///
/// @param block Specifies whether the operation should wait indefinitely or
/// return
/// immediately.
/// @returns @c true if all computations completed.
/// @returns @c false if not all computations completed.
bool wait(bool block = true) {
mkldnn_primitive_t c_api_error_primitive;
mkldnn_status_t status =
mkldnn_stream_wait(get(), block, &c_api_error_primitive);
if (status != mkldnn_success && status != mkldnn_try_again)
error::wrap_c_api(
status, "could not wait on a stream", &c_api_error_primitive);
return (status == mkldnn_success);
}
stream &rerun() {
mkldnn_primitive_t c_api_error_primitive;
error::wrap_c_api(mkldnn_stream_rerun(get(), &c_api_error_primitive),
"could not rerun a stream",
&c_api_error_primitive);
return *this;
}
};
/// @}
/// @} C++ API
} // namespace mkldnn
#endif
...@@ -54,9 +54,9 @@ class DataToLoDTensorConverter(object): ...@@ -54,9 +54,9 @@ class DataToLoDTensorConverter(object):
self.data.append(data) self.data.append(data)
else: else:
cur_lod_len = len(data) cur_lod_len = len(data)
lod[-1].append(lod[-1][-1] + cur_lod_len) lod[0].append(lod[0][-1] + cur_lod_len)
for each_data in data: for each_data in data:
self._feed_impl_(each_data, lod[:-1], lod_level - 1) self._feed_impl_(each_data, lod[1:], lod_level - 1)
def done(self): def done(self):
arr = numpy.array(self.data, dtype=self.dtype).reshape(self.shape) arr = numpy.array(self.data, dtype=self.dtype).reshape(self.shape)
......
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import contextlib
import core import core
import executor import executor
import framework import framework
import io import io
import parallel_executor
import unique_name import unique_name
from trainer import check_and_get_place from trainer import check_and_get_place
...@@ -24,40 +27,53 @@ __all__ = ['Inferencer', ] ...@@ -24,40 +27,53 @@ __all__ = ['Inferencer', ]
class Inferencer(object): class Inferencer(object):
def __init__(self, infer_func, param_path, place=None): def __init__(self, infer_func, param_path, place=None, parallel=False):
""" """
:param infer_func: a function that will return predict Variable :param infer_func: a function that will return predict Variable
:param param_path: the path where the inference model is saved by fluid.io.save_params :param param_path: the path where the inference model is saved by fluid.io.save_params
:param place: place to do the inference :param place: place to do the inference
:param parallel: use parallel_executor to run the inference, it will use multi CPU/GPU.
""" """
self.param_path = param_path self.param_path = param_path
self.scope = core.Scope() self.scope = core.Scope()
self.parallel = parallel
self.place = check_and_get_place(place)
self.inference_program = framework.Program() self.inference_program = framework.Program()
with framework.program_guard(self.inference_program): with framework.program_guard(self.inference_program):
with unique_name.guard(): with unique_name.guard():
self.predict_var = infer_func() self.predict_var = infer_func()
self.exe = executor.Executor(check_and_get_place(place)) with self._prog_and_scope_guard():
with executor.scope_guard(self.scope):
# load params from param_path into scope # load params from param_path into scope
io.load_params(self.exe, param_path, self.inference_program) io.load_params(executor.Executor(self.place), param_path)
if parallel:
with self._prog_and_scope_guard():
self.exe = parallel_executor.ParallelExecutor(
use_cuda=isinstance(self.place, core.CUDAPlace),
loss_name=self.predict_var.name)
else:
self.exe = executor.Executor(self.place)
def infer(self, inputs, return_numpy=True): def infer(self, inputs):
""" """
:param inputs: a map of {"input_name": input_var} that will be feed into the inference program :param inputs: a map of {"input_name": input_var} that will be feed into the inference program
to get the predict value to get the predict value
:param return_numpy: if return numpy value for row tensor
:return: the predict value of the inference model :return: the predict value of the inference model
""" """
if not isinstance(inputs, dict): if not isinstance(inputs, dict):
raise ValueError( raise ValueError(
"inputs should be a map of {'input_name': input_var}") "inputs should be a map of {'input_name': input_var}")
with executor.scope_guard(self.scope): with self._prog_and_scope_guard():
results = self.exe.run(self.inference_program, results = self.exe.run(feed=inputs,
feed=inputs, fetch_list=[self.predict_var.name])
fetch_list=[self.predict_var],
return_numpy=return_numpy)
return results return results
@contextlib.contextmanager
def _prog_and_scope_guard(self):
with framework.program_guard(main_program=self.inference_program):
with executor.scope_guard(self.scope):
yield
...@@ -23,6 +23,7 @@ import nn ...@@ -23,6 +23,7 @@ import nn
import math import math
__all__ = [ __all__ = [
'prior_box',
'multi_box_head', 'multi_box_head',
'bipartite_match', 'bipartite_match',
'target_assign', 'target_assign',
...@@ -564,6 +565,98 @@ def ssd_loss(location, ...@@ -564,6 +565,98 @@ def ssd_loss(location,
return loss return loss
def prior_box(input,
image,
min_sizes,
max_sizes=None,
aspect_ratios=None,
variance=[0.1, 0.1, 0.2, 0.2],
flip=False,
clip=False,
steps=[0.0, 0.0],
offset=0.5,
name=None):
"""
**Prior box operator**
Generate prior boxes for SSD(Single Shot MultiBox Detector) algorithm.
Each position of the input produce N prior boxes, N is determined by
the count of min_sizes, max_sizes and aspect_ratios, The size of the
box is in range(min_size, max_size) interval, which is generated in
sequence according to the aspect_ratios.
Args:
input(Variable): The Input Variables, the format is NCHW.
image(Variable): The input image data of PriorBoxOp,
the layout is NCHW.
min_sizes(list|tuple): min sizes of generated prior boxes.
max_sizes(list|tuple|None): max sizes of generated prior boxes.
Default: None.
aspect_ratios(list|tuple): the aspect ratios of generated prior
boxes. Default: None.
variance(list|tuple): the variances to be encoded in prior boxes.
Default:[0.1, 0.1, 0.2, 0.2].
flip(bool): Whether to flip aspect ratios. Default:False.
clip(bool): Whether to clip out-of-boundary boxes. Default: False.
step(list|turple): Prior boxes step across weight and height, If
step[0] == 0.0/step[1] == 0.0, the prior boxes step across
height/weight of the input will be automatically calculated.
Default: [0.0]
offset(float): Prior boxes center offset. Default: 0.5
name(str): Name of the prior box op. Default: None.
Returns:
boxes(Variable): the output prior boxes of PriorBox.
The layout is [H, W, num_priors, 4].
H is the height of input, W is the width of input,
num_priors is the total
box count of each position of input.
Variances(Variable): the expanded variances of PriorBox.
The layout is [H, W, num_priors, 4].
H is the height of input, W is the width of input
num_priors is the total
box count of each position of input
Examples:
.. code-block:: python
box, var = prior_box(
input=conv1,
image=images,
min_sizes=[100.],
flip=True,
clip=True)
"""
helper = LayerHelper("prior_box", **locals())
dtype = helper.input_dtype()
attrs = {
'min_sizes': min_sizes,
'aspect_ratios': aspect_ratios,
'variances': variance,
'flip': flip,
'clip': clip,
'step_w': steps[0],
'step_h': steps[1],
'offset': offset
}
if max_sizes is not None and len(max_sizes) > 0 and max_sizes[0] > 0:
attrs['max_sizes'] = max_sizes
box = helper.create_tmp_variable(dtype)
var = helper.create_tmp_variable(dtype)
helper.append_op(
type="prior_box",
inputs={"Input": input,
"Image": image},
outputs={"Boxes": box,
"Variances": var},
attrs=attrs, )
box.stop_gradient = True
var.stop_gradient = True
return box, var
def multi_box_head(inputs, def multi_box_head(inputs,
image, image,
base_size, base_size,
...@@ -660,47 +753,6 @@ def multi_box_head(inputs, ...@@ -660,47 +753,6 @@ def multi_box_head(inputs,
clip=True) clip=True)
""" """
def _prior_box_(input,
image,
min_sizes,
max_sizes,
aspect_ratios,
variance,
flip=False,
clip=False,
step_w=0.0,
step_h=0.0,
offset=0.5,
name=None):
helper = LayerHelper("prior_box", **locals())
dtype = helper.input_dtype()
attrs = {
'min_sizes': min_sizes,
'aspect_ratios': aspect_ratios,
'variances': variance,
'flip': flip,
'clip': clip,
'step_w': step_w,
'step_h': step_h,
'offset': offset
}
if len(max_sizes) > 0 and max_sizes[0] > 0:
attrs['max_sizes'] = max_sizes
box = helper.create_tmp_variable(dtype)
var = helper.create_tmp_variable(dtype)
helper.append_op(
type="prior_box",
inputs={"Input": input,
"Image": image},
outputs={"Boxes": box,
"Variances": var},
attrs=attrs, )
box.stop_gradient = True
var.stop_gradient = True
return box, var
def _reshape_with_axis_(input, axis=1): def _reshape_with_axis_(input, axis=1):
if not (axis > 0 and axis < len(input.shape)): if not (axis > 0 and axis < len(input.shape)):
raise ValueError("The axis should be smaller than " raise ValueError("The axis should be smaller than "
...@@ -777,11 +829,10 @@ def multi_box_head(inputs, ...@@ -777,11 +829,10 @@ def multi_box_head(inputs,
aspect_ratio = aspect_ratios[i] aspect_ratio = aspect_ratios[i]
if not _is_list_or_tuple_(aspect_ratio): if not _is_list_or_tuple_(aspect_ratio):
aspect_ratio = [aspect_ratio] aspect_ratio = [aspect_ratio]
step = [step_w[i] if step_w else 0.0, step_h[i] if step_w else 0.0]
box, var = _prior_box_(input, image, min_size, max_size, aspect_ratio, box, var = prior_box(input, image, min_size, max_size, aspect_ratio,
variance, flip, clip, step_w[i] variance, flip, clip, step, offset)
if step_w else 0.0, step_h[i]
if step_w else 0.0, offset)
box_results.append(box) box_results.append(box)
var_results.append(var) var_results.append(var)
......
...@@ -1329,6 +1329,8 @@ def sequence_pool(input, pool_type): ...@@ -1329,6 +1329,8 @@ def sequence_pool(input, pool_type):
sqrt : out.data = [2.82, 6.93, 4.24], where 2.82=(1+3)/sqrt(2), sqrt : out.data = [2.82, 6.93, 4.24], where 2.82=(1+3)/sqrt(2),
6.93=(2+4+6)/sqrt(3), 4.24=(5+1)/sqrt(2) 6.93=(2+4+6)/sqrt(3), 4.24=(5+1)/sqrt(2)
max : out.data = [3, 6, 5], where 3=max(1,3), 6=max(2,4,6), 5=max(5,1) max : out.data = [3, 6, 5], where 3=max(1,3), 6=max(2,4,6), 5=max(5,1)
last : out.data = [3, 6, 1], where 3=last(1,3), 6=last(2,4,6), 1=last(5,1)
first : out.data = [1, 2, 5], where 1=first(1,3), 2=first(2,4,6), 5=first(5,1)
Args: Args:
input(variable): The input variable which is a LoDTensor. input(variable): The input variable which is a LoDTensor.
...@@ -1348,6 +1350,8 @@ def sequence_pool(input, pool_type): ...@@ -1348,6 +1350,8 @@ def sequence_pool(input, pool_type):
sum_x = fluid.layers.sequence_pool(input=x, pool_type='sum') sum_x = fluid.layers.sequence_pool(input=x, pool_type='sum')
sqrt_x = fluid.layers.sequence_pool(input=x, pool_type='sqrt') sqrt_x = fluid.layers.sequence_pool(input=x, pool_type='sqrt')
max_x = fluid.layers.sequence_pool(input=x, pool_type='max') max_x = fluid.layers.sequence_pool(input=x, pool_type='max')
last_x = fluid.layers.sequence_pool(input=x, pool_type='last')
first_x = fluid.layers.sequence_pool(input=x, pool_type='first')
""" """
helper = LayerHelper('sequence_pool', **locals()) helper = LayerHelper('sequence_pool', **locals())
dtype = helper.input_dtype() dtype = helper.input_dtype()
...@@ -3263,35 +3267,35 @@ def smooth_l1(x, y, inside_weight=None, outside_weight=None, sigma=None): ...@@ -3263,35 +3267,35 @@ def smooth_l1(x, y, inside_weight=None, outside_weight=None, sigma=None):
""" """
**Smooth L1 Loss Operator. ** **Smooth L1 Loss Operator. **
This operator computes the smooth l1 loss for X and Y. This operator computes the smooth L1 loss for X and Y.
The operator takes the first dimension of X and Y as batch size. The operator takes the first dimension of X and Y as batch size.
For each instance, it computes the smooth l1 loss element by element first For each instance, it computes the smooth L1 loss element by element first
and then sums all the losses. So the shape of Out is [batch_size, 1]. and then sums all the losses. So the shape of Out is [batch_size, 1].
Args: Args:
x (Variable): A tensor with rank at least 2. The input value of smooth x (Variable): A tensor with rank at least 2. The input value of smooth
l1 loss op with shape [batch_size, dim1, ..., dimN]. L1 loss op with shape [batch_size, dim1, ..., dimN].
y (Variable): A tensor with rank at least 2. The target value of smooth y (Variable): A tensor with rank at least 2. The target value of smooth
l1 loss op with same shape as x. L1 loss op with same shape as x.
inside_weight (Variable|None): A tensor with rank at least 2. This inside_weight (Variable|None): A tensor with rank at least 2. This
input is optional and should have same shape with x. If provided, input is optional and should have same shape with x. If provided,
the result of (x - y) will be multiplied by this tensor element by the result of (x - y) will be multiplied by this tensor element by
element. element.
outside_weight (Variable|None): A tensor with rank at least 2. This outside_weight (Variable|None): A tensor with rank at least 2. This
input is optional and should have same shape with x. If provided, input is optional and should have same shape with x. If provided,
the out smooth l1 loss will be multiplied by this tensor element the out smooth L1 loss will be multiplied by this tensor element
by element. by element.
sigma (float|None): Hyper parameter of smooth l1 loss op. A float scalar sigma (float|None): Hyper parameter of smooth L1 loss op. A float scalar
with default value 1.0. with default value 1.0.
Returns: Returns:
Variable: A tensor with rank be 2. The output smooth l1 loss with Variable: A tensor with rank be 2. The output smooth L1 loss with
shape [batch_size, 1]. shape [batch_size, 1].
Examples: Examples:
.. code-block:: python .. code-block:: python
data = fluid.layers.data(name='data', shape=[128], dtype='float32') data = fluid.layers.data(name='data', shape=[128], dtype='float32')
label = fluid.layers.data(name='label', shape=[100], dtype='int64') label = fluid.layers.data(name='label', shape=[100], dtype='float32')
fc = fluid.layers.fc(input=data, size=100) fc = fluid.layers.fc(input=data, size=100)
out = fluid.layers.smooth_l1(x=fc, y=label) out = fluid.layers.smooth_l1(x=fc, y=label)
""" """
...@@ -3769,13 +3773,13 @@ def label_smooth(label, ...@@ -3769,13 +3773,13 @@ def label_smooth(label,
def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0):
""" """
Region of interest pooling (also known as RoI pooling) is to perform Region of interest pooling (also known as RoI pooling) is to perform
is to perform max pooling on inputs of nonuniform sizes to obtain is to perform max pooling on inputs of nonuniform sizes to obtain
fixed-size feature maps (e.g. 7*7). fixed-size feature maps (e.g. 7*7).
The operator has three steps: The operator has three steps:
1. Dividing each region proposal into equal-sized sections with 1. Dividing each region proposal into equal-sized sections with
the pooled_width and pooled_height the pooled_width and pooled_height
2. Finding the largest value in each section 2. Finding the largest value in each section
3. Copying these max values to the output buffer 3. Copying these max values to the output buffer
Args: Args:
...@@ -3783,8 +3787,8 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): ...@@ -3783,8 +3787,8 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0):
rois (Variable): ROIs (Regions of Interest) to pool over. It should rois (Variable): ROIs (Regions of Interest) to pool over. It should
be a 2-D one level LoTensor of shape [num_rois, 4]. be a 2-D one level LoTensor of shape [num_rois, 4].
The layout is [x1, y1, x2, y2], where (x1, y1) The layout is [x1, y1, x2, y2], where (x1, y1)
is the top left coordinates, and (x2, y2) is the is the top left coordinates, and (x2, y2) is the
bottom right coordinates. The num_rois is the bottom right coordinates. The num_rois is the
total number of ROIs in this batch data. total number of ROIs in this batch data.
pooled_height (integer): The pooled output height. Default: 1 pooled_height (integer): The pooled output height. Default: 1
pooled_width (integer): The pooled output width. Default: 1 pooled_width (integer): The pooled output width. Default: 1
...@@ -3793,11 +3797,11 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0): ...@@ -3793,11 +3797,11 @@ def roi_pool(input, rois, pooled_height=1, pooled_width=1, spatial_scale=1.0):
to the scale used when pooling. Default: 1.0 to the scale used when pooling. Default: 1.0
Returns: Returns:
pool_out (Variable): The output is a 4-D tensor of the shape pool_out (Variable): The output is a 4-D tensor of the shape
(num_rois, channels, pooled_h, pooled_w). (num_rois, channels, pooled_h, pooled_w).
Examples: Examples:
pool_out = fluid.layers.roi_pool(input=x, rois=rois, 7, 7, 1.0) pool_out = fluid.layers.roi_pool(input=x, rois=rois, 7, 7, 1.0)
""" """
helper = LayerHelper('roi_pool', **locals()) helper = LayerHelper('roi_pool', **locals())
dtype = helper.input_dtype() dtype = helper.input_dtype()
......
...@@ -8,3 +8,4 @@ endforeach() ...@@ -8,3 +8,4 @@ endforeach()
add_subdirectory(fit_a_line) add_subdirectory(fit_a_line)
add_subdirectory(recognize_digits) add_subdirectory(recognize_digits)
add_subdirectory(image_classification)
...@@ -57,22 +57,20 @@ def train(use_cuda, train_program, save_dirname): ...@@ -57,22 +57,20 @@ def train(use_cuda, train_program, save_dirname):
optimizer=fluid.optimizer.SGD(learning_rate=0.001)) optimizer=fluid.optimizer.SGD(learning_rate=0.001))
def event_handler(event): def event_handler(event):
if isinstance(event, fluid.EndEpochEvent): if isinstance(event, fluid.EndStepEvent):
test_metrics = trainer.test( if event.step == 10:
reader=test_reader, feed_order=['x', 'y']) test_metrics = trainer.test(
print test_metrics reader=test_reader, feed_order=['x', 'y'])
''' print test_metrics
'''
... ...
['25.768919467926025'] ['25.768919467926025']
['15.343549569447836'] ['15.343549569447836']
... ...
'''
'''
if float(test_metrics[0]) < 20.0:
if save_dirname is not None: if save_dirname is not None:
trainer.save_params(save_dirname) trainer.save_params(save_dirname)
return trainer.stop()
trainer.train( trainer.train(
reader=train_reader, reader=train_reader,
...@@ -94,7 +92,7 @@ def infer(use_cuda, inference_program, save_dirname=None): ...@@ -94,7 +92,7 @@ def infer(use_cuda, inference_program, save_dirname=None):
tensor_x = numpy.random.uniform(0, 10, [batch_size, 13]).astype("float32") tensor_x = numpy.random.uniform(0, 10, [batch_size, 13]).astype("float32")
results = inferencer.infer({'x': tensor_x}) results = inferencer.infer({'x': tensor_x})
print("infer results: ", results[0]) print("infer results: ", numpy.array(results[0]))
def main(use_cuda): def main(use_cuda):
......
file(GLOB TEST_OPS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "test_*.py")
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
# default test
foreach(src ${TEST_OPS})
py_test(${src} SRCS ${src}.py)
endforeach()
# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
CIFAR dataset.
This module will download dataset from
https://www.cs.toronto.edu/~kriz/cifar.html and parse train/test set into
paddle reader creators.
The CIFAR-10 dataset consists of 60000 32x32 colour images in 10 classes,
with 6000 images per class. There are 50000 training images and 10000 test
images.
The CIFAR-100 dataset is just like the CIFAR-10, except it has 100 classes
containing 600 images each. There are 500 training images and 100 testing
images per class.
"""
import cPickle
import itertools
import numpy
import paddle.v2.dataset.common
import tarfile
__all__ = ['train10']
URL_PREFIX = 'https://www.cs.toronto.edu/~kriz/'
CIFAR10_URL = URL_PREFIX + 'cifar-10-python.tar.gz'
CIFAR10_MD5 = 'c58f30108f718f92721af3b95e74349a'
def reader_creator(filename, sub_name, batch_size=None):
def read_batch(batch):
data = batch['data']
labels = batch.get('labels', batch.get('fine_labels', None))
assert labels is not None
for sample, label in itertools.izip(data, labels):
yield (sample / 255.0).astype(numpy.float32), int(label)
def reader():
with tarfile.open(filename, mode='r') as f:
names = (each_item.name for each_item in f
if sub_name in each_item.name)
batch_count = 0
for name in names:
batch = cPickle.load(f.extractfile(name))
for item in read_batch(batch):
if isinstance(batch_size, int) and batch_count > batch_size:
break
batch_count += 1
yield item
return reader
def train10(batch_size=None):
"""
CIFAR-10 training set creator.
It returns a reader creator, each sample in the reader is image pixels in
[0, 1] and label in [0, 9].
:return: Training reader creator
:rtype: callable
"""
return reader_creator(
paddle.v2.dataset.common.download(CIFAR10_URL, 'cifar', CIFAR10_MD5),
'data_batch',
batch_size=batch_size)
...@@ -17,6 +17,7 @@ from __future__ import print_function ...@@ -17,6 +17,7 @@ from __future__ import print_function
import paddle import paddle
import paddle.fluid as fluid import paddle.fluid as fluid
import numpy import numpy
import cifar10_small_test_set
def resnet_cifar10(input, depth=32): def resnet_cifar10(input, depth=32):
...@@ -81,46 +82,50 @@ def train_network(): ...@@ -81,46 +82,50 @@ def train_network():
cost = fluid.layers.cross_entropy(input=predict, label=label) cost = fluid.layers.cross_entropy(input=predict, label=label)
avg_cost = fluid.layers.mean(cost) avg_cost = fluid.layers.mean(cost)
accuracy = fluid.layers.accuracy(input=predict, label=label) accuracy = fluid.layers.accuracy(input=predict, label=label)
return avg_cost, accuracy return [avg_cost, accuracy]
def train(use_cuda, save_path): def train(use_cuda, train_program, save_dirname):
BATCH_SIZE = 128 BATCH_SIZE = 128
EPOCH_NUM = 1 EPOCH_NUM = 1
train_reader = paddle.batch( train_reader = paddle.batch(
paddle.reader.shuffle( paddle.reader.shuffle(
paddle.dataset.cifar.train10(), buf_size=128 * 10), cifar10_small_test_set.train10(batch_size=10), buf_size=128 * 10),
batch_size=BATCH_SIZE) batch_size=BATCH_SIZE)
test_reader = paddle.batch( test_reader = paddle.batch(
paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE) paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE)
def event_handler(event): def event_handler(event):
if isinstance(event, fluid.EndIteration): if isinstance(event, fluid.EndStepEvent):
if (event.batch_id % 10) == 0: avg_cost, accuracy = trainer.test(
avg_cost, accuracy = trainer.test(reader=test_reader) reader=test_reader, feed_order=['pixel', 'label'])
print('BatchID {1:04}, Loss {2:2.2}, Acc {3:2.2}'.format( print('Loss {0:2.2}, Acc {1:2.2}'.format(avg_cost, accuracy))
event.batch_id + 1, avg_cost, accuracy))
if accuracy > 0.01: # Low threshold for speeding up CI if accuracy > 0.01: # Low threshold for speeding up CI
trainer.params.save(save_path) if save_dirname is not None:
return trainer.save_params(save_dirname)
return
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer( trainer = fluid.Trainer(
train_network, train_func=train_program,
optimizer=fluid.optimizer.Adam(learning_rate=0.001), optimizer=fluid.optimizer.Adam(learning_rate=0.001),
place=place, place=place)
event_handler=event_handler)
trainer.train(train_reader, EPOCH_NUM, event_handler=event_handler)
trainer.train(
reader=train_reader,
num_epochs=EPOCH_NUM,
event_handler=event_handler,
feed_order=['pixel', 'label'])
def infer(use_cuda, save_path):
params = fluid.Params(save_path) def infer(use_cuda, inference_program, save_dirname=None):
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
inferencer = fluid.Inferencer(inference_network, params, place=place) inferencer = fluid.Inferencer(
infer_func=inference_program, param_path=save_dirname, place=place)
# The input's dimension of conv should be 4-D or 5-D. # The input's dimension of conv should be 4-D or 5-D.
# Use normilized image pixels as input data, which should be in the range # Use normilized image pixels as input data, which should be in the range
...@@ -135,8 +140,14 @@ def main(use_cuda): ...@@ -135,8 +140,14 @@ def main(use_cuda):
if use_cuda and not fluid.core.is_compiled_with_cuda(): if use_cuda and not fluid.core.is_compiled_with_cuda():
return return
save_path = "image_classification_resnet.inference.model" save_path = "image_classification_resnet.inference.model"
train(use_cuda, save_path)
infer(use_cuda, save_path) train(
use_cuda=use_cuda, train_program=train_network, save_dirname=save_path)
infer(
use_cuda=use_cuda,
inference_program=inference_network,
save_dirname=save_path)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -17,6 +17,7 @@ from __future__ import print_function ...@@ -17,6 +17,7 @@ from __future__ import print_function
import paddle import paddle
import paddle.fluid as fluid import paddle.fluid as fluid
import numpy import numpy
import cifar10_small_test_set
def vgg16_bn_drop(input): def vgg16_bn_drop(input):
...@@ -60,46 +61,48 @@ def train_network(): ...@@ -60,46 +61,48 @@ def train_network():
cost = fluid.layers.cross_entropy(input=predict, label=label) cost = fluid.layers.cross_entropy(input=predict, label=label)
avg_cost = fluid.layers.mean(cost) avg_cost = fluid.layers.mean(cost)
accuracy = fluid.layers.accuracy(input=predict, label=label) accuracy = fluid.layers.accuracy(input=predict, label=label)
return avg_cost, accuracy return [avg_cost, accuracy]
def train(use_cuda, save_path): def train(use_cuda, train_program, save_dirname):
BATCH_SIZE = 128 BATCH_SIZE = 128
EPOCH_NUM = 1
train_reader = paddle.batch( train_reader = paddle.batch(
paddle.reader.shuffle( paddle.reader.shuffle(
paddle.dataset.cifar.train10(), buf_size=128 * 10), cifar10_small_test_set.train10(batch_size=10), buf_size=128 * 10),
batch_size=BATCH_SIZE) batch_size=BATCH_SIZE)
test_reader = paddle.batch( test_reader = paddle.batch(
paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE) paddle.dataset.cifar.test10(), batch_size=BATCH_SIZE)
def event_handler(event): def event_handler(event):
if isinstance(event, fluid.EndIteration): if isinstance(event, fluid.EndStepEvent):
if (event.batch_id % 10) == 0: avg_cost, accuracy = trainer.test(
avg_cost, accuracy = trainer.test(reader=test_reader) reader=test_reader, feed_order=['pixel', 'label'])
print('BatchID {1:04}, Loss {2:2.2}, Acc {3:2.2}'.format( print('Loss {0:2.2}, Acc {1:2.2}'.format(avg_cost, accuracy))
event.batch_id + 1, avg_cost, accuracy))
if accuracy > 0.01: # Low threshold for speeding up CI if accuracy > 0.01: # Low threshold for speeding up CI
trainer.params.save(save_path) if save_dirname is not None:
return trainer.save_params(save_dirname)
return
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
trainer = fluid.Trainer( trainer = fluid.Trainer(
train_network, train_func=train_program,
optimizer=fluid.optimizer.Adam(learning_rate=0.001),
place=place, place=place,
event_handler=event_handler) optimizer=fluid.optimizer.Adam(learning_rate=0.001))
trainer.train(train_reader, EPOCH_NUM, event_handler=event_handler)
trainer.train(
reader=train_reader,
num_epochs=1,
event_handler=event_handler,
feed_order=['pixel', 'label'])
def infer(use_cuda, save_path): def infer(use_cuda, inference_program, save_dirname=None):
params = fluid.Params(save_path)
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
inferencer = fluid.Inferencer(inference_network, params, place=place) inferencer = fluid.Inferencer(
infer_func=inference_program, param_path=save_dirname, place=place)
# The input's dimension of conv should be 4-D or 5-D. # The input's dimension of conv should be 4-D or 5-D.
# Use normilized image pixels as input data, which should be in the range # Use normilized image pixels as input data, which should be in the range
...@@ -114,8 +117,14 @@ def main(use_cuda): ...@@ -114,8 +117,14 @@ def main(use_cuda):
if use_cuda and not fluid.core.is_compiled_with_cuda(): if use_cuda and not fluid.core.is_compiled_with_cuda():
return return
save_path = "image_classification_vgg.inference.model" save_path = "image_classification_vgg.inference.model"
train(use_cuda, save_path)
infer(use_cuda, save_path) train(
use_cuda=use_cuda, train_program=train_network, save_dirname=save_path)
infer(
use_cuda=use_cuda,
inference_program=inference_network,
save_dirname=save_path)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -62,31 +62,31 @@ def train(use_cuda, train_program, save_dirname): ...@@ -62,31 +62,31 @@ def train(use_cuda, train_program, save_dirname):
optimizer = fluid.optimizer.Adam(learning_rate=0.001) optimizer = fluid.optimizer.Adam(learning_rate=0.001)
trainer = fluid.Trainer( trainer = fluid.Trainer(
train_func=train_program, place=place, optimizer=optimizer) train_func=train_program,
place=place,
optimizer=optimizer,
parallel=True)
def event_handler(event): def event_handler(event):
if isinstance(event, fluid.EndEpochEvent): if isinstance(event, fluid.EndEpochEvent):
test_reader = paddle.batch( test_reader = paddle.batch(
paddle.dataset.mnist.test(), batch_size=BATCH_SIZE) paddle.dataset.mnist.test(), batch_size=BATCH_SIZE)
test_metrics = trainer.test( avg_cost, acc = trainer.test(
reader=test_reader, feed_order=['img', 'label']) reader=test_reader, feed_order=['img', 'label'])
avg_cost_set = test_metrics[0]
acc_set = test_metrics[1]
# get test acc and loss
acc = numpy.array(acc_set).mean()
avg_cost = numpy.array(avg_cost_set).mean()
print("avg_cost: %s" % avg_cost) print("avg_cost: %s" % avg_cost)
print("acc : %s" % acc) print("acc : %s" % acc)
if float(acc) > 0.2: # Smaller value to increase CI speed if acc > 0.2: # Smaller value to increase CI speed
trainer.save_params(save_dirname) trainer.save_params(save_dirname)
else: else:
print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format( print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format(
event.epoch + 1, float(avg_cost), float(acc))) event.epoch + 1, avg_cost, acc))
if math.isnan(float(avg_cost)): if math.isnan(avg_cost):
sys.exit("got NaN loss, training failed.") sys.exit("got NaN loss, training failed.")
elif isinstance(event, fluid.EndStepEvent):
print("Step {0}, Epoch {1} Metrics {2}".format(
event.step, event.epoch, map(numpy.array, event.metrics)))
train_reader = paddle.batch( train_reader = paddle.batch(
paddle.reader.shuffle( paddle.reader.shuffle(
...@@ -112,7 +112,7 @@ def infer(use_cuda, inference_program, save_dirname=None): ...@@ -112,7 +112,7 @@ def infer(use_cuda, inference_program, save_dirname=None):
results = inferencer.infer({'img': tensor_img}) results = inferencer.infer({'img': tensor_img})
print("infer results: ", results[0]) print("infer results: ", numpy.array(results[0]))
def main(use_cuda): def main(use_cuda):
...@@ -131,4 +131,4 @@ def main(use_cuda): ...@@ -131,4 +131,4 @@ def main(use_cuda):
if __name__ == '__main__': if __name__ == '__main__':
# for use_cuda in (False, True): # for use_cuda in (False, True):
main(use_cuda=False) main(use_cuda=True)
...@@ -55,24 +55,18 @@ def train(use_cuda, train_program, save_dirname): ...@@ -55,24 +55,18 @@ def train(use_cuda, train_program, save_dirname):
if isinstance(event, fluid.EndEpochEvent): if isinstance(event, fluid.EndEpochEvent):
test_reader = paddle.batch( test_reader = paddle.batch(
paddle.dataset.mnist.test(), batch_size=BATCH_SIZE) paddle.dataset.mnist.test(), batch_size=BATCH_SIZE)
test_metrics = trainer.test( avg_cost, acc = trainer.test(
reader=test_reader, feed_order=['img', 'label']) reader=test_reader, feed_order=['img', 'label'])
avg_cost_set = test_metrics[0]
acc_set = test_metrics[1]
# get test acc and loss
acc = numpy.array(acc_set).mean()
avg_cost = numpy.array(avg_cost_set).mean()
print("avg_cost: %s" % avg_cost) print("avg_cost: %s" % avg_cost)
print("acc : %s" % acc) print("acc : %s" % acc)
if float(acc) > 0.2: # Smaller value to increase CI speed if acc > 0.2: # Smaller value to increase CI speed
trainer.save_params(save_dirname) trainer.save_params(save_dirname)
else: else:
print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format( print('BatchID {0}, Test Loss {1:0.2}, Acc {2:0.2}'.format(
event.epoch + 1, float(avg_cost), float(acc))) event.epoch + 1, avg_cost, acc))
if math.isnan(float(avg_cost)): if math.isnan(avg_cost):
sys.exit("got NaN loss, training failed.") sys.exit("got NaN loss, training failed.")
train_reader = paddle.batch( train_reader = paddle.batch(
...@@ -99,7 +93,7 @@ def infer(use_cuda, inference_program, save_dirname=None): ...@@ -99,7 +93,7 @@ def infer(use_cuda, inference_program, save_dirname=None):
results = inferencer.infer({'img': tensor_img}) results = inferencer.infer({'img': tensor_img})
print("infer results: ", results[0]) print("infer results: ", numpy.array(results[0]))
def main(use_cuda): def main(use_cuda):
......
...@@ -90,7 +90,7 @@ def train_program(is_sparse): ...@@ -90,7 +90,7 @@ def train_program(is_sparse):
return avg_cost return avg_cost
def train(use_cuda, train_program, save_path): def train(use_cuda, train_program, save_dirname):
train_reader = paddle.batch( train_reader = paddle.batch(
paddle.dataset.imikolov.train(word_dict, N), BATCH_SIZE) paddle.dataset.imikolov.train(word_dict, N), BATCH_SIZE)
test_reader = paddle.batch( test_reader = paddle.batch(
...@@ -99,27 +99,36 @@ def train(use_cuda, train_program, save_path): ...@@ -99,27 +99,36 @@ def train(use_cuda, train_program, save_path):
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
def event_handler(event): def event_handler(event):
if isinstance(event, fluid.EndEpochEvent): if isinstance(event, fluid.EndStepEvent):
outs = trainer.test(reader=test_reader) outs = trainer.test(
reader=test_reader,
feed_order=['firstw', 'secondw', 'thirdw', 'forthw', 'nextw'])
avg_cost = outs[0] avg_cost = outs[0]
print("loss= ", avg_cost) print("loss= ", avg_cost)
if avg_cost < 5.0: if avg_cost < 10.0:
trainer.save_params(save_path) trainer.save_params(save_dirname)
return trainer.stop()
if math.isnan(avg_cost): if math.isnan(avg_cost):
sys.exit("got NaN loss, training failed.") sys.exit("got NaN loss, training failed.")
trainer = fluid.Trainer( trainer = fluid.Trainer(
train_program, fluid.optimizer.SGD(learning_rate=0.001), place=place) train_func=train_program,
optimizer=fluid.optimizer.SGD(learning_rate=0.001),
place=place)
trainer.train( trainer.train(
reader=train_reader, num_epochs=1, event_handler=event_handler) reader=train_reader,
num_epochs=1,
event_handler=event_handler,
feed_order=['firstw', 'secondw', 'thirdw', 'forthw', 'nextw'])
def infer(use_cuda, inference_program, save_path): def infer(use_cuda, inference_program, save_dirname=None):
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
inferencer = fluid.Inferencer( inferencer = fluid.Inferencer(
infer_func=inference_program, param_path=save_path, place=place) infer_func=inference_program, param_path=save_dirname, place=place)
lod = [0, 1] lod = [0, 1]
first_word = create_random_lodtensor(lod, place, low=0, high=dict_size - 1) first_word = create_random_lodtensor(lod, place, low=0, high=dict_size - 1)
...@@ -142,9 +151,17 @@ def main(use_cuda, is_sparse): ...@@ -142,9 +151,17 @@ def main(use_cuda, is_sparse):
if use_cuda and not fluid.core.is_compiled_with_cuda(): if use_cuda and not fluid.core.is_compiled_with_cuda():
return return
save_path = "word2vec.params" save_path = "word2vec.inference.model"
train(use_cuda, partial(train_program, is_sparse), save_path)
infer(use_cuda, partial(inference_program, is_sparse), save_path) train(
use_cuda=use_cuda,
train_program=partial(train_program, is_sparse),
save_dirname=save_path)
infer(
use_cuda=use_cuda,
inference_program=partial(inference_program, is_sparse),
save_dirname=save_path)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -182,12 +182,6 @@ def train(use_cuda, save_dirname=None, is_local=True): ...@@ -182,12 +182,6 @@ def train(use_cuda, save_dirname=None, is_local=True):
crf_decode = fluid.layers.crf_decoding( crf_decode = fluid.layers.crf_decoding(
input=feature_out, param_attr=fluid.ParamAttr(name='crfw')) input=feature_out, param_attr=fluid.ParamAttr(name='crfw'))
chunk_evaluator = fluid.evaluator.ChunkEvaluator(
input=crf_decode,
label=target,
chunk_scheme="IOB",
num_chunk_types=int(math.ceil((label_dict_len - 1) / 2.0)))
train_data = paddle.batch( train_data = paddle.batch(
paddle.reader.shuffle( paddle.reader.shuffle(
paddle.dataset.conll05.test(), buf_size=8192), paddle.dataset.conll05.test(), buf_size=8192),
...@@ -203,7 +197,6 @@ def train(use_cuda, save_dirname=None, is_local=True): ...@@ -203,7 +197,6 @@ def train(use_cuda, save_dirname=None, is_local=True):
def train_loop(main_program): def train_loop(main_program):
exe.run(fluid.default_startup_program()) exe.run(fluid.default_startup_program())
embedding_param = fluid.global_scope().find_var( embedding_param = fluid.global_scope().find_var(
embedding_name).get_tensor() embedding_name).get_tensor()
embedding_param.set( embedding_param.set(
...@@ -213,27 +206,19 @@ def train(use_cuda, save_dirname=None, is_local=True): ...@@ -213,27 +206,19 @@ def train(use_cuda, save_dirname=None, is_local=True):
start_time = time.time() start_time = time.time()
batch_id = 0 batch_id = 0
for pass_id in xrange(PASS_NUM): for pass_id in xrange(PASS_NUM):
chunk_evaluator.reset(exe)
for data in train_data(): for data in train_data():
cost, precision, recall, f1_score = exe.run( cost = exe.run(main_program,
main_program, feed=feeder.feed(data),
feed=feeder.feed(data), fetch_list=[avg_cost])
fetch_list=[avg_cost] + chunk_evaluator.metrics) cost = cost[0]
pass_precision, pass_recall, pass_f1_score = chunk_evaluator.eval(
exe)
if batch_id % 10 == 0: if batch_id % 10 == 0:
print("avg_cost:" + str(cost) + " precision:" + str( print("avg_cost:" + str(cost))
precision) + " recall:" + str(recall) + " f1_score:" +
str(f1_score) + " pass_precision:" + str(
pass_precision) + " pass_recall:" + str(
pass_recall) + " pass_f1_score:" + str(
pass_f1_score))
if batch_id != 0: if batch_id != 0:
print("second per batch: " + str((time.time( print("second per batch: " + str((time.time(
) - start_time) / batch_id)) ) - start_time) / batch_id))
# Set the threshold low to speed up the CI test # Set the threshold low to speed up the CI test
if float(pass_precision) > 0.01: if float(cost) < 60.0:
if save_dirname is not None: if save_dirname is not None:
# TODO(liuyiqun): Change the target to crf_decode # TODO(liuyiqun): Change the target to crf_decode
fluid.io.save_inference_model(save_dirname, [ fluid.io.save_inference_model(save_dirname, [
......
...@@ -13,15 +13,62 @@ ...@@ -13,15 +13,62 @@
# limitations under the License. # limitations under the License.
import paddle.fluid as fluid import paddle.fluid as fluid
import unittest
def test_converter(): class TestDataFeeder(unittest.TestCase):
img = fluid.layers.data(name='image', shape=[1, 28, 28]) def test_lod_level_0_converter(self):
label = fluid.layers.data(name='label', shape=[1], dtype='int64') img = fluid.layers.data(name='image', shape=[1, 28, 28])
feeder = fluid.DataFeeder([img, label], fluid.CPUPlace()) label = fluid.layers.data(name='label', shape=[1], dtype='int64')
result = feeder.feed([[[0] * 784, [9]], [[1] * 784, [1]]]) feeder = fluid.DataFeeder([img, label], fluid.CPUPlace())
print(result) result = feeder.feed([([0] * 784, [9]), ([1] * 784, [1])])
print(result)
self.assertEqual(result['image'].shape(), [2, 1, 28, 28])
self.assertEqual(result['label'].shape(), [2, 1])
self.assertEqual(result['image'].lod(), [])
self.assertEqual(result['label'].lod(), [])
def test_lod_level_1_converter(self):
# lod_level = 1
# each sentence has a different number of words
sentences = fluid.layers.data(
name='sentences', shape=[1], dtype='int64', lod_level=1)
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
feeder = fluid.DataFeeder([sentences, label], fluid.CPUPlace())
# lod = [[0, 3, 5, 9]]
# data = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
# label = [1] * len(data)
result = feeder.feed(
[([1, 2, 3], [1]), ([4, 5], [1]), ([6, 7, 8, 9], [1])])
print(result)
self.assertEqual(result['sentences'].shape(), [9, 1])
self.assertEqual(result['label'].shape(), [3, 1])
self.assertEqual(result['sentences'].lod(), [[0, 3, 5, 9]])
self.assertEqual(result['label'].lod(), [])
def test_lod_level_2_converter(self):
# lod_level = 2
# paragraphs -> sentences -> words
paragraphs = fluid.layers.data(
name='paragraphs', shape=[1], dtype='int64', lod_level=2)
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
feeder = fluid.DataFeeder([paragraphs, label], fluid.CPUPlace())
# lod = [[0, 2, 3], [0, 3, 5, 9]]
# data = [[[1, 2, 3], [4, 5]], [[6, 7, 8, 9]]]
# label = [1] * len(data)
result = feeder.feed(
[([[1, 2, 3], [4, 5]], [1]), ([[6, 7, 8, 9]], [1])])
print(result)
self.assertEqual(result['paragraphs'].shape(), [9, 1])
self.assertEqual(result['label'].shape(), [2, 1])
self.assertEqual(result['paragraphs'].lod(), [[0, 2, 3], [0, 3, 5, 9]])
self.assertEqual(result['label'].lod(), [])
if __name__ == '__main__': if __name__ == '__main__':
test_converter() unittest.main()
...@@ -109,6 +109,24 @@ class TestDetection(unittest.TestCase): ...@@ -109,6 +109,24 @@ class TestDetection(unittest.TestCase):
print(str(program)) print(str(program))
class TestPriorBox(unittest.TestCase):
def test_prior_box(self):
data_shape = [3, 224, 224]
images = fluid.layers.data(
name='pixel', shape=data_shape, dtype='float32')
conv1 = fluid.layers.conv2d(images, 3, 3, 2)
box, var = layers.prior_box(
input=conv1,
image=images,
min_sizes=[100.0],
aspect_ratios=[1.],
flip=True,
clip=True)
assert len(box.shape) == 4
assert box.shape == var.shape
assert box.shape[3] == 4
class TestMultiBoxHead(unittest.TestCase): class TestMultiBoxHead(unittest.TestCase):
def test_multi_box_head(self): def test_multi_box_head(self):
data_shape = [3, 224, 224] data_shape = [3, 224, 224]
......
...@@ -28,11 +28,11 @@ function(py_test_modules TARGET_NAME) ...@@ -28,11 +28,11 @@ function(py_test_modules TARGET_NAME)
if(WITH_TESTING) if(WITH_TESTING)
set(options "") set(options "")
set(oneValueArgs "") set(oneValueArgs "")
set(multiValueArgs MODULES DEPS ARGS ENVS) set(multiValueArgs MODULES DEPS ENVS)
cmake_parse_arguments(py_test_modules "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(py_test_modules "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
add_test(NAME ${TARGET_NAME} add_test(NAME ${TARGET_NAME}
COMMAND env PYTHONPATH=${PADDLE_BINARY_DIR}/python ${py_test_modules_ENVS} COMMAND env PYTHONPATH=${PADDLE_BINARY_DIR}/python ${py_test_modules_ENVS}
${PYTHON_EXECUTABLE} -u -m unittest --verbose ${py_test_modules_MODULES} ${py_test_modules_ARGS} ${PYTHON_EXECUTABLE} ${PADDLE_SOURCE_DIR}/tools/test_runner.py ${py_test_modules_MODULES}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif() endif()
endfunction() endfunction()
......
...@@ -52,15 +52,18 @@ class TestSendOp(unittest.TestCase): ...@@ -52,15 +52,18 @@ class TestSendOp(unittest.TestCase):
serv = layers.ListenAndServ( serv = layers.ListenAndServ(
"127.0.0.1:0", ["X"], optimizer_mode=False) "127.0.0.1:0", ["X"], optimizer_mode=False)
with serv.do(): with serv.do():
out_var = main.global_block().create_var(
name="scale_0.tmp_0",
psersistable=True,
dtype="float32",
shape=[32, 32])
x = layers.data( x = layers.data(
shape=[32, 32], shape=[32, 32],
dtype='float32', dtype='float32',
name="X", name="X",
append_batch_size=False) append_batch_size=False)
fluid.initializer.Constant(value=1.0)(x, main.global_block()) fluid.initializer.Constant(value=1.0)(x, main.global_block())
o = layers.scale(x=x, scale=10.0) layers.scale(x=x, scale=10.0, out=out_var)
main.global_block().create_var(
name=o.name, psersistable=False, dtype=o.dtype, shape=o.shape)
self.server_exe = fluid.Executor(place) self.server_exe = fluid.Executor(place)
self.server_exe.run(main) self.server_exe.run(main)
......
...@@ -24,33 +24,30 @@ BATCH_SIZE = 20 ...@@ -24,33 +24,30 @@ BATCH_SIZE = 20
class TestNetWithDtype(unittest.TestCase): class TestNetWithDtype(unittest.TestCase):
def set_network(self): def setUp(self):
self.dtype = "float64" self.dtype = "float64"
self.init_dtype() self.init_dtype()
main = fluid.Program()
with fluid.program_guard(main):
self.x = fluid.layers.data(name='x', shape=[13], dtype=self.dtype)
self.y = fluid.layers.data(name='y', shape=[1], dtype=self.dtype)
y_predict = fluid.layers.fc(input=self.x, size=1, act=None)
cost = fluid.layers.square_error_cost(input=y_predict, label=self.y) def run_net_on_place(self, place):
main = fluid.Program()
startup = fluid.Program()
with fluid.program_guard(main, startup):
x = fluid.layers.data(name='x', shape=[13], dtype=self.dtype)
y = fluid.layers.data(name='y', shape=[1], dtype=self.dtype)
y_predict = fluid.layers.fc(input=x, size=1, act=None)
cost = fluid.layers.square_error_cost(input=y_predict, label=y)
avg_cost = fluid.layers.mean(cost) avg_cost = fluid.layers.mean(cost)
self.program = main sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001)
self.fetch_list = [avg_cost] sgd_optimizer.minimize(avg_cost)
sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001) fetch_list = [avg_cost]
sgd_optimizer.minimize(avg_cost)
def run_net_on_place(self, place):
train_reader = paddle.batch( train_reader = paddle.batch(
paddle.dataset.uci_housing.train(), batch_size=BATCH_SIZE) paddle.dataset.uci_housing.train(), batch_size=BATCH_SIZE)
feeder = fluid.DataFeeder(place=place, feed_list=[self.x, self.y]) feeder = fluid.DataFeeder(place=place, feed_list=[x, y])
exe = fluid.Executor(place) exe = fluid.Executor(place)
exe.run(fluid.default_startup_program()) exe.run(startup)
for data in train_reader(): for data in train_reader():
exe.run(self.program, exe.run(main, feed=feeder.feed(data), fetch_list=fetch_list)
feed=feeder.feed(data),
fetch_list=self.fetch_list)
# the main program is runable, the datatype is fully supported # the main program is runable, the datatype is fully supported
break break
...@@ -58,14 +55,12 @@ class TestNetWithDtype(unittest.TestCase): ...@@ -58,14 +55,12 @@ class TestNetWithDtype(unittest.TestCase):
pass pass
def test_cpu(self): def test_cpu(self):
self.set_network()
place = fluid.CPUPlace() place = fluid.CPUPlace()
self.run_net_on_place(place) self.run_net_on_place(place)
def test_gpu(self): def test_gpu(self):
if not core.is_compiled_with_cuda(): if not core.is_compiled_with_cuda():
return return
self.set_network()
place = fluid.CUDAPlace(0) place = fluid.CUDAPlace(0)
self.run_net_on_place(place) self.run_net_on_place(place)
......
...@@ -775,7 +775,7 @@ class TestCRFModel(unittest.TestCase): ...@@ -775,7 +775,7 @@ class TestCRFModel(unittest.TestCase):
build_strategy = fluid.BuildStrategy() build_strategy = fluid.BuildStrategy()
build_strategy.reduce_strategy = fluid.BuildStrategy.ReduceStrategy.Reduce build_strategy.reduce_strategy = fluid.BuildStrategy.ReduceStrategy.Reduce
self.check_network_convergence( self.check_network_convergence(
is_sparse=False, build_strategy=build_strategy) is_sparse=True, build_strategy=build_strategy)
def test_update_dense_parameter_reduce(self): def test_update_dense_parameter_reduce(self):
build_strategy = fluid.BuildStrategy() build_strategy = fluid.BuildStrategy()
...@@ -849,8 +849,7 @@ class TestFetchOp(unittest.TestCase): ...@@ -849,8 +849,7 @@ class TestFetchOp(unittest.TestCase):
assert not math.isnan(np.sum(ret[i])) and \ assert not math.isnan(np.sum(ret[i])) and \
not math.isinf(np.sum(ret[i])) not math.isinf(np.sum(ret[i]))
@unittest.skip("this test is buggy") def test_fetch_op(self):
def test_feed(self):
tst_reader = paddle.batch(flowers.test(use_xmap=False), batch_size=16) tst_reader = paddle.batch(flowers.test(use_xmap=False), batch_size=16)
tst_reader_iter = tst_reader() tst_reader_iter = tst_reader()
......
...@@ -12,17 +12,18 @@ ...@@ -12,17 +12,18 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import contextlib
import os import os
import core import core
import framework
import executor
import data_feeder import data_feeder
import contextlib import executor
import framework
import io import io
import unique_name
# optimizer is same as the parameter of Trainer.__init__. Rename it to opt_module # optimizer is same as the parameter of Trainer.__init__. Rename it to opt_module
import optimizer as opt_module import optimizer as opt_module
import parallel_executor
from transpiler import distribute_transpiler from transpiler import distribute_transpiler
__all__ = [ __all__ = [
...@@ -48,12 +49,14 @@ class BeginStepEvent(object): ...@@ -48,12 +49,14 @@ class BeginStepEvent(object):
def __init__(self, epoch_id, step_id): def __init__(self, epoch_id, step_id):
self.epoch = epoch_id self.epoch = epoch_id
self.step = step_id self.step = step_id
self.fetch_metrics = True
class EndStepEvent(object): class EndStepEvent(object):
def __init__(self, epoch_id, step_id): def __init__(self, epoch_id, step_id, metrics):
self.epoch = epoch_id self.epoch = epoch_id
self.step = step_id self.step = step_id
self.metrics = metrics
def check_and_get_place(place): def check_and_get_place(place):
...@@ -87,12 +90,18 @@ class Trainer(object): ...@@ -87,12 +90,18 @@ class Trainer(object):
Args: Args:
train_func(callable): A function which will return loss. The loss must be a scalar. train_func(callable): A function which will return loss. The loss must be a scalar.
infer_func(callable): A function which will return predict, used to save inference model
optimizer(optimizer.Optimizer): The optimizer should be an instance of Optimizer optimizer(optimizer.Optimizer): The optimizer should be an instance of Optimizer
place: The device place of this trainer. place: The device place of this trainer.
""" """
def __init__(self, train_func, optimizer, param_path=None, place=None): def __init__(self,
train_func,
optimizer,
param_path=None,
place=None,
parallel=False):
self.__stop = False
self.parallel = parallel
# 1. we need to generate a framework.Program by calling # 1. we need to generate a framework.Program by calling
# program_func. Reference: fluid.program_guard in # program_func. Reference: fluid.program_guard in
# test_word2vec.py # test_word2vec.py
...@@ -106,14 +115,14 @@ class Trainer(object): ...@@ -106,14 +115,14 @@ class Trainer(object):
with framework.program_guard(self.train_program, self.startup_program): with framework.program_guard(self.train_program, self.startup_program):
program_func_outs = train_func() program_func_outs = train_func()
self.test_outputs = program_func_outs if isinstance( self.train_func_outputs = program_func_outs if isinstance(
program_func_outs, list) else [program_func_outs] program_func_outs, list) else [program_func_outs]
self.test_program = self.train_program.clone() self.test_program = self.train_program.clone()
if not isinstance(optimizer, opt_module.Optimizer): if not isinstance(optimizer, opt_module.Optimizer):
raise TypeError( raise TypeError(
"The optimizer should be an instance of Optimizer") "The optimizer should be an instance of Optimizer")
# The fisrt element of program_func_outs is loss. # The fisrt element of program_func_outs is loss.
loss = self.test_outputs[0] loss = self.train_func_outputs[0]
optimize_ops, params_grads = optimizer.minimize(loss) optimize_ops, params_grads = optimizer.minimize(loss)
self.place = check_and_get_place(place) self.place = check_and_get_place(place)
...@@ -131,7 +140,40 @@ class Trainer(object): ...@@ -131,7 +140,40 @@ class Trainer(object):
# load params from param_path into scope # load params from param_path into scope
io.load_persistables(exe, dirname=param_path) io.load_persistables(exe, dirname=param_path)
def _transpile_nccl2_dist(self):
# PADDLE_TRAINER_IPS
if "PADDLE_TRAINER_IPS" not in os.environ:
self.nccl_id_var = None
else:
self.trainer_id = int(os.getenv("PADDLE_TRAINER_ID"))
port = os.getenv("PADDLE_PSERVER_PORT")
worker_ips = os.getenv("PADDLE_TRAINER_IPS")
worker_endpoints = []
for ip in worker_ips.split(","):
worker_endpoints.append(':'.join([ip, port]))
self.num_trainers = len(worker_endpoints)
current_endpoint = os.getenv("POD_IP") + ":" + port
worker_endpoints.remove(current_endpoint)
# TODO(wuyi): use self.nccl_id_var, self.num_trainers and self.trainer_id
# in ParallelExecutor to start
# distributed training using NCCL2
self.nccl_id_var = self.startup_program.global_block().create_var(
name="NCCLID", persistable=True, type=core.VarDesc.VarType.RAW)
self.startup_program.global_block().append_op(
type="gen_nccl_id",
inputs={},
outputs={"NCCLID": self.nccl_id_var},
attrs={
"endpoint": current_endpoint,
"endpoint_list": worker_endpoints,
"trainer_id": self.trainer_id
})
def _dist_transpile_if_necessary(self, optimize_ops, params_grads): def _dist_transpile_if_necessary(self, optimize_ops, params_grads):
self._transpile_nccl2_dist()
if self.nccl_id_var != None:
return
if "PADDLE_TRAINING_ROLE" not in os.environ: if "PADDLE_TRAINING_ROLE" not in os.environ:
return return
...@@ -169,12 +211,13 @@ class Trainer(object): ...@@ -169,12 +211,13 @@ class Trainer(object):
'TRAINING_ROLE environment variable must be either TRAINER or PSERVER' 'TRAINING_ROLE environment variable must be either TRAINER or PSERVER'
) )
def train(self, def stop(self):
num_epochs, """
event_handler, stop training
reader, """
feed_order, self.__stop = True
parallel=False):
def train(self, num_epochs, event_handler, reader=None, feed_order=None):
""" """
Train the model. Train the model.
...@@ -182,25 +225,24 @@ class Trainer(object): ...@@ -182,25 +225,24 @@ class Trainer(object):
num_epochs: The number of epoch. An epoch will process all data in reader num_epochs: The number of epoch. An epoch will process all data in reader
event_handler: The event handler. A function with type (ev:Event)->void event_handler: The event handler. A function with type (ev:Event)->void
reader: reader:
parallel: True if use multi-CPUs or multi-GPUs
feed_order: Feeding order of reader. None will following the defining feed_order: Feeding order of reader. None will following the defining
order in program order in program
Returns: Returns:
""" """
if parallel:
raise NotImplementedError(
"Parallel Executor version of trainer is not implemented")
training_role = os.getenv("PADDLE_TRAINING_ROLE", "") training_role = os.getenv("PADDLE_TRAINING_ROLE", "")
if training_role == "PSERVER": if training_role == "PSERVER":
with self._prog_and_scope_guard(): with self._prog_and_scope_guard():
exe = executor.Executor(self.place) exe = executor.Executor(self.place)
exe.run() exe.run()
return return
if self.parallel:
self._train_by_executor(num_epochs, event_handler, reader, feed_order) self._train_by_parallel_executor(num_epochs, event_handler, reader,
feed_order)
else:
self._train_by_executor(num_epochs, event_handler, reader,
feed_order)
def test(self, reader, feed_order): def test(self, reader, feed_order):
""" """
...@@ -212,7 +254,8 @@ class Trainer(object): ...@@ -212,7 +254,8 @@ class Trainer(object):
order in program order in program
""" """
return self._test_by_executor(reader, feed_order, self.test_outputs) return self._test_by_executor(reader, feed_order,
self.train_func_outputs)
def save_params(self, param_path): def save_params(self, param_path):
# reference: save_persistables in io.py # reference: save_persistables in io.py
...@@ -246,13 +289,27 @@ class Trainer(object): ...@@ -246,13 +289,27 @@ class Trainer(object):
feeder = data_feeder.DataFeeder( feeder = data_feeder.DataFeeder(
feed_list=feed_var_list, place=self.place) feed_list=feed_var_list, place=self.place)
exe = executor.Executor(self.place) exe = executor.Executor(self.place)
for epoch_id in range(num_epochs): reader = feeder.decorate_reader(reader, multi_devices=False)
event_handler(BeginEpochEvent(epoch_id)) self._train_by_any_executor(event_handler, exe, num_epochs, reader)
for step_id, data in enumerate(reader()):
event_handler(BeginStepEvent(epoch_id, step_id)) def _train_by_any_executor(self, event_handler, exe, num_epochs, reader):
exe.run(feed=feeder.feed(data), fetch_list=[]) for epoch_id in range(num_epochs):
event_handler(EndStepEvent(epoch_id, step_id)) event_handler(BeginEpochEvent(epoch_id))
event_handler(EndEpochEvent(epoch_id)) for step_id, data in enumerate(reader()):
if self.__stop:
return
begin_event = BeginStepEvent(epoch_id, step_id)
event_handler(begin_event)
if begin_event.fetch_metrics:
metrics = exe.run(feed=data,
fetch_list=[
var.name
for var in self.train_func_outputs
])
else:
metrics = exe.run(feed=data, fetch_list=[])
event_handler(EndStepEvent(epoch_id, step_id, metrics))
event_handler(EndEpochEvent(epoch_id))
def _test_by_executor(self, reader, feed_order, fetch_list): def _test_by_executor(self, reader, feed_order, fetch_list):
with executor.scope_guard(self.scope): with executor.scope_guard(self.scope):
...@@ -271,6 +328,26 @@ class Trainer(object): ...@@ -271,6 +328,26 @@ class Trainer(object):
return [x / count for x in accumulated] return [x / count for x in accumulated]
def _train_by_parallel_executor(self, num_epochs, event_handler, reader,
feed_order):
with self._prog_and_scope_guard():
pe = self._get_or_create_parallel_executor()
feed_var_list = build_feed_var_list(self.train_program, feed_order)
feeder = data_feeder.DataFeeder(
feed_list=feed_var_list, place=self.place)
reader = feeder.decorate_reader(reader, multi_devices=True)
self._train_by_any_executor(event_handler, pe, num_epochs, reader)
def _get_parallel_executor(self):
return getattr(self, 'parallel_executor', None)
def _get_or_create_parallel_executor(self):
if self._get_parallel_executor() is None:
self.parallel_executor = parallel_executor.ParallelExecutor(
use_cuda=isinstance(self.place, core.CUDAPlace),
loss_name=self.train_func_outputs[0].name)
return self._get_parallel_executor()
def build_feed_var_list(program, feed_order): def build_feed_var_list(program, feed_order):
if not isinstance(program, framework.Program): if not isinstance(program, framework.Program):
......
# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest
import os
import sys
import paddle.fluid as fluid
import importlib
import cStringIO
def main():
sys.path.append(os.getcwd())
some_test_failed = False
for module_name in sys.argv[1:]:
buffer = cStringIO.StringIO()
main = fluid.Program()
startup = fluid.Program()
scope = fluid.core.Scope()
with fluid.program_guard(main, startup):
with fluid.scope_guard(scope):
with fluid.unique_name.guard():
test_loader = unittest.TestLoader()
module = importlib.import_module(module_name)
tests = test_loader.loadTestsFromModule(module)
res = unittest.TextTestRunner(stream=buffer).run(tests)
if not res.wasSuccessful():
some_test_failed = True
print >> sys.stderr, module_name, 'failed\n', buffer.getvalue(
)
if some_test_failed:
exit(1)
if __name__ == '__main__':
main()
...@@ -171,7 +171,7 @@ if args.timeline_path: ...@@ -171,7 +171,7 @@ if args.timeline_path:
profile_paths = profile_path.split(',') profile_paths = profile_path.split(',')
profile_dict = dict() profile_dict = dict()
if len(profile_path) == 1: if len(profile_paths) == 1:
with open(profile_path, 'r') as f: with open(profile_path, 'r') as f:
profile_s = f.read() profile_s = f.read()
profile_pb = profiler_pb2.Profile() profile_pb = profiler_pb2.Profile()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册