Refactor dygraph (#19107)
* refactor dygraph,test=develop * fix failed unittest,test=develop * polish code,test=develop * check windows ci error,test=develop try to fix windows ci error by np.allclose,test=develop * polish vlog and profiler, test=develop * try to fix preceding ops order,test=develop * test transformer in windows ci, test=develop * use python c-api to speed up tracer.trace,test=develop * test=develop, fix docker with paddle nccl problem * test=develop, add ut for debug string and gradient_accumulator * test=develop, add tests for layer/gradient_accumulator/prepared_op * test=develop, fix complie error for test_prepared_op * test=develop, add more ut for dygraph * test=develop, create API.spec for dygraph api change * test=develop, refoctor name to make it easier to understand * test=develop, refoctor name to make it easier to understand * test=develop, fix multi-gpu failed problem , add Tracer tests, change PADDLEENFORCE to PADDLEENFORCE_EQ * test=develop, fix ut failed on parallel se-resnext * test=develop, change one more PADDLE_ENFORCEsigmoid_bug
parent
dca9b6c5b0
commit
e9233d1c1e
@ -1,10 +1,11 @@
|
||||
cc_library(imperative_flag SRCS flags.cc DEPS gflags)
|
||||
|
||||
if(WITH_PYTHON)
|
||||
cc_library(layer SRCS layer.cc DEPS proto_desc operator device_context blas pybind profiler imperative_flag)
|
||||
cc_library(tracer SRCS tracer.cc DEPS proto_desc device_context pybind profiler)
|
||||
cc_library(engine SRCS engine.cc)
|
||||
cc_library(prepared_operator SRCS prepared_operator.cc DEPS proto_desc operator device_context lod_tensor selected_rows var_type_traits)
|
||||
cc_library(layer SRCS layer.cc DEPS prepared_operator math_function imperative_flag variable_helper op_registry)
|
||||
cc_library(gradient_accumulator SRCS gradient_accumulator.cc DEPS blas operator lod_tensor selected_rows var_type_traits layer)
|
||||
cc_library(tracer SRCS tracer.cc DEPS layer engine)
|
||||
cc_library(engine SRCS engine.cc DEPS layer gradient_accumulator)
|
||||
cc_library(imperative_profiler SRCS profiler.cc)
|
||||
cc_library(nccl_context SRCS nccl_context.cc DEPS device_context)
|
||||
cc_test(nccl_context_test SRCS nccl_context_test.cc DEPS nccl_context)
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
#include "paddle/fluid/imperative/gradient_accumulator.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "paddle/fluid/framework/lod_tensor.h"
|
||||
#include "paddle/fluid/framework/selected_rows.h"
|
||||
#include "paddle/fluid/imperative/layer.h"
|
||||
#include "paddle/fluid/operators/math/blas.h"
|
||||
#include "paddle/fluid/operators/math/math_function.h"
|
||||
#include "paddle/fluid/platform/device_context.h"
|
||||
#include "paddle/fluid/platform/profiler.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
template <typename T>
|
||||
class TensorAddFunctor : public boost::static_visitor<> {
|
||||
public:
|
||||
TensorAddFunctor(int64_t numel, const T* x, T* y)
|
||||
: numel_(numel), x_(x), y_(y) {}
|
||||
|
||||
void operator()(const platform::CPUPlace& place) {
|
||||
platform::CPUDeviceContext* ctx = dynamic_cast<platform::CPUDeviceContext*>(
|
||||
platform::DeviceContextPool::Instance().Get(place));
|
||||
auto blas = operators::math::GetBlas<platform::CPUDeviceContext, T>(*ctx);
|
||||
blas.AXPY(numel_, 1., x_, y_);
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
void operator()(const platform::CUDAPlace& place) {
|
||||
platform::CUDADeviceContext* ctx =
|
||||
dynamic_cast<platform::CUDADeviceContext*>(
|
||||
platform::DeviceContextPool::Instance().Get(place));
|
||||
auto blas = operators::math::GetBlas<platform::CUDADeviceContext, T>(*ctx);
|
||||
blas.AXPY(numel_, 1., x_, y_);
|
||||
}
|
||||
#else
|
||||
void operator()(const platform::CUDAPlace& place) {
|
||||
PADDLE_THROW("Do NOT support gradient merge in place %s", place);
|
||||
}
|
||||
#endif
|
||||
|
||||
// there is NO blas in CUDAPinnedPlace
|
||||
void operator()(const platform::CUDAPinnedPlace& place) {
|
||||
PADDLE_THROW("Do NOT support gradient merge in place %s", place);
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t numel_;
|
||||
const T* x_;
|
||||
T* y_;
|
||||
};
|
||||
|
||||
void TensorAdd(const framework::Variable& src, framework::Variable* dst) {
|
||||
auto* dst_tensor = dst->GetMutable<framework::LoDTensor>();
|
||||
auto& src_tensor = src.Get<framework::LoDTensor>();
|
||||
|
||||
auto numel = src_tensor.numel();
|
||||
|
||||
// FIXME(minqiyang): loss_grad op will pass a zero grad of label
|
||||
// ugly fix for it
|
||||
if (numel == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PADDLE_ENFORCE_EQ(dst_tensor->numel() == numel, true,
|
||||
"dst_numel %d vs. src_numel %d", dst_tensor->numel(),
|
||||
numel);
|
||||
|
||||
auto data_type = src_tensor.type();
|
||||
auto place = src_tensor.place();
|
||||
|
||||
#define PADDLE_TENSOR_ADD_MACRO(cpp_type) \
|
||||
if (data_type == framework::DataTypeTrait<cpp_type>::DataType()) { \
|
||||
TensorAddFunctor<cpp_type> func( \
|
||||
numel, src_tensor.data<cpp_type>(), \
|
||||
dst_tensor->mutable_data<cpp_type>(place)); \
|
||||
boost::apply_visitor(func, place); \
|
||||
return; \
|
||||
}
|
||||
|
||||
PADDLE_TENSOR_ADD_MACRO(float);
|
||||
PADDLE_TENSOR_ADD_MACRO(double);
|
||||
|
||||
#undef PADDLE_TENSOR_ADD_MACRO
|
||||
|
||||
PADDLE_THROW("Not supported data type %s for AddTo",
|
||||
framework::DataTypeToString(data_type));
|
||||
}
|
||||
|
||||
void EagerGradientAccumulator::Add(std::shared_ptr<VarBase> var,
|
||||
size_t trace_id) {
|
||||
auto* dst_var = var_->MutableVar();
|
||||
if (cur_cnt_ == 0) {
|
||||
*dst_var = std::move(*(var->MutableVar()));
|
||||
} else {
|
||||
TensorAdd(var->Var(), dst_var);
|
||||
}
|
||||
++cur_cnt_;
|
||||
}
|
||||
|
||||
void SortedGradientAccumulator::Add(std::shared_ptr<VarBase> var,
|
||||
size_t trace_id) {
|
||||
auto* dst_var = var_->MutableVar();
|
||||
if (ref_cnt_ == 1) {
|
||||
*dst_var = std::move(*(var->MutableVar()));
|
||||
} else {
|
||||
if (tmp_grad_vars_.empty()) {
|
||||
tmp_grad_vars_.reserve(ref_cnt_);
|
||||
}
|
||||
|
||||
tmp_grad_vars_.emplace_back(std::move(var), trace_id);
|
||||
|
||||
if (tmp_grad_vars_.size() != ref_cnt_) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(tmp_grad_vars_.begin(), tmp_grad_vars_.end(),
|
||||
[](const std::pair<std::shared_ptr<VarBase>, size_t>& p1,
|
||||
const std::pair<std::shared_ptr<VarBase>, size_t>& p2) {
|
||||
return p1.second > p2.second;
|
||||
});
|
||||
|
||||
*dst_var = std::move(*(tmp_grad_vars_[0].first->MutableVar()));
|
||||
for (size_t i = 1; i < tmp_grad_vars_.size(); ++i) {
|
||||
TensorAdd(tmp_grad_vars_[i].first->Var(), dst_var);
|
||||
}
|
||||
|
||||
tmp_grad_vars_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "paddle/fluid/imperative/layer.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
class GradientAccumulator {
|
||||
public:
|
||||
explicit GradientAccumulator(VarBase* var) : var_(var) {}
|
||||
|
||||
virtual void Add(std::shared_ptr<VarBase> var, size_t trace_id) = 0;
|
||||
|
||||
virtual ~GradientAccumulator() = default;
|
||||
|
||||
inline void IncreaseRefCnt() { ++ref_cnt_; }
|
||||
|
||||
inline size_t RefCnt() const { return ref_cnt_; }
|
||||
|
||||
protected:
|
||||
VarBase* var_;
|
||||
size_t ref_cnt_{0};
|
||||
};
|
||||
|
||||
class EagerGradientAccumulator : public GradientAccumulator {
|
||||
public:
|
||||
using GradientAccumulator::GradientAccumulator;
|
||||
|
||||
void Add(std::shared_ptr<VarBase> var, size_t trace_id) override;
|
||||
|
||||
private:
|
||||
size_t cur_cnt_{0};
|
||||
};
|
||||
|
||||
class SortedGradientAccumulator : public GradientAccumulator {
|
||||
public:
|
||||
using GradientAccumulator::GradientAccumulator;
|
||||
|
||||
void Add(std::shared_ptr<VarBase> var, size_t trace_id) override;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::shared_ptr<VarBase>, size_t>> tmp_grad_vars_;
|
||||
};
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
#include "paddle/fluid/imperative/prepared_operator.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
const framework::Tensor* GetTensorFromVar(const framework::Variable& var) {
|
||||
if (var.IsType<framework::LoDTensor>()) {
|
||||
return &(var.Get<framework::LoDTensor>());
|
||||
} else if (var.IsType<framework::SelectedRows>()) {
|
||||
return &(var.Get<framework::SelectedRows>().value());
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
platform::Place PreparedOp::GetExpectedPlace(const platform::Place& place,
|
||||
const NameVarBaseMap& ins) {
|
||||
bool found = false;
|
||||
for (auto& name_pair : ins) {
|
||||
for (auto& var_base : name_pair.second) {
|
||||
const auto* tensor = GetTensorFromVar(var_base->Var());
|
||||
if (tensor && tensor->IsInitialized()) {
|
||||
auto tmp_place = tensor->place();
|
||||
PADDLE_ENFORCE_EQ(!found || tmp_place == place, true,
|
||||
"Input variable should keep in the same place: %s, "
|
||||
"but get place: %s of input %s instead",
|
||||
place, tmp_place, name_pair.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return place;
|
||||
}
|
||||
|
||||
PreparedOp::PreparedOp(const framework::OperatorBase& op,
|
||||
const framework::RuntimeContext& ctx,
|
||||
framework::OperatorWithKernel::OpKernelFunc func,
|
||||
platform::DeviceContext* dev_ctx,
|
||||
std::vector<framework::KernelConfig>* kernel_configs)
|
||||
: op_(op),
|
||||
ctx_(ctx),
|
||||
func_(std::move(func)),
|
||||
dev_ctx_(dev_ctx),
|
||||
kernel_configs_(kernel_configs) {}
|
||||
|
||||
PreparedOp PreparedOp::Prepare(const framework::RuntimeContext& ctx,
|
||||
const framework::OperatorWithKernel& op,
|
||||
const platform::Place& place) {
|
||||
auto* dev_ctx = platform::DeviceContextPool::Instance().Get(place);
|
||||
|
||||
// check if op[type] has kernel registered.
|
||||
auto& all_op_kernels = op.AllOpKernels();
|
||||
auto kernels_iter = all_op_kernels.find(op.Type());
|
||||
if (kernels_iter == all_op_kernels.end()) {
|
||||
PADDLE_THROW(
|
||||
"There are no kernels which are registered in the %s operator.",
|
||||
op.Type());
|
||||
}
|
||||
|
||||
auto& kernels = kernels_iter->second;
|
||||
|
||||
auto expected_kernel_key =
|
||||
op.GetExpectedKernelType(framework::ExecutionContext(
|
||||
op, framework::Scope(), *dev_ctx, ctx, nullptr));
|
||||
VLOG(3) << "expected_kernel_key:" << expected_kernel_key;
|
||||
|
||||
auto kernel_iter = kernels.find(expected_kernel_key);
|
||||
// TODO(jiabin): Add operator.cc's line 1000 part back when we need that case
|
||||
if (kernel_iter == kernels.end()) {
|
||||
PADDLE_THROW("op %s does not have kernel for %s", op.Type(),
|
||||
KernelTypeToString(expected_kernel_key));
|
||||
}
|
||||
std::vector<framework::KernelConfig>* kernel_configs =
|
||||
op.GetKernelConfig(expected_kernel_key);
|
||||
return PreparedOp(op, ctx, kernel_iter->second, dev_ctx, kernel_configs);
|
||||
}
|
||||
|
||||
void PreparedOp::Run() {
|
||||
// TODO(zjl): remove scope in dygraph
|
||||
framework::Scope scope;
|
||||
op_.RuntimeInferShape(scope, dev_ctx_->GetPlace(), ctx_);
|
||||
func_(framework::ExecutionContext(op_, scope, *dev_ctx_, ctx_,
|
||||
kernel_configs_));
|
||||
}
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "paddle/fluid/framework/operator.h"
|
||||
#include "paddle/fluid/imperative/layer.h"
|
||||
#include "paddle/fluid/imperative/type_defs.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
const framework::Tensor* GetTensorFromVar(const framework::Variable& var);
|
||||
|
||||
class PreparedOp {
|
||||
public:
|
||||
static PreparedOp Prepare(const framework::RuntimeContext& ctx,
|
||||
const framework::OperatorWithKernel& op,
|
||||
const platform::Place& place);
|
||||
|
||||
inline platform::DeviceContext* GetDeviceContext() const { return dev_ctx_; }
|
||||
|
||||
void Run();
|
||||
|
||||
static platform::Place GetExpectedPlace(const platform::Place& place,
|
||||
const NameVarBaseMap& ins);
|
||||
|
||||
private:
|
||||
PreparedOp(const framework::OperatorBase& op,
|
||||
const framework::RuntimeContext& ctx,
|
||||
framework::OperatorWithKernel::OpKernelFunc func,
|
||||
platform::DeviceContext* dev_ctx,
|
||||
std::vector<framework::KernelConfig>* kernel_configs);
|
||||
|
||||
private:
|
||||
const framework::OperatorBase& op_;
|
||||
const framework::RuntimeContext& ctx_;
|
||||
framework::OperatorWithKernel::OpKernelFunc func_;
|
||||
platform::DeviceContext* dev_ctx_;
|
||||
std::vector<framework::KernelConfig>* kernel_configs_;
|
||||
};
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
@ -0,0 +1,5 @@
|
||||
cc_test(nccl_context_test SRCS nccl_context_test.cc DEPS nccl_context)
|
||||
cc_test(test_gradient_accmulator SRCS test_gradient_accmulator.cc DEPS gradient_accumulator memcpy)
|
||||
cc_test(test_layer SRCS test_layer.cc DEPS layer proto_desc operator op_registry variable_helper mul_op)
|
||||
cc_test(test_prepare_op SRCS test_prepare_op.cc DEPS prepared_operator op_info split_op layer concat_and_split)
|
||||
cc_test(test_tracer SRCS test_tracer.cc DEPS tracer layer proto_desc operator op_registry variable_helper mul_op)
|
@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/fluid/framework/variable.h"
|
||||
#include "paddle/fluid/imperative/gradient_accumulator.h"
|
||||
#include "paddle/fluid/memory/memcpy.h"
|
||||
|
||||
namespace imperative = paddle::imperative;
|
||||
namespace platform = paddle::platform;
|
||||
namespace framework = paddle::framework;
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
void TensorAdd(const framework::Variable& src, framework::Variable* dst);
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
template <typename T>
|
||||
int TensorGPUAddTest(platform::CUDAPlace place, T t1, T t2) {
|
||||
framework::Variable var1;
|
||||
framework::Variable var2;
|
||||
std::vector<T> src_data(10, t1);
|
||||
std::vector<T> dst_data(10, t2);
|
||||
std::vector<T> result;
|
||||
platform::CPUPlace src_place;
|
||||
for (unsigned int i = 0; i < 10; i++) {
|
||||
result.emplace_back(src_data[i] + dst_data[i]);
|
||||
}
|
||||
std::vector<int64_t> dims = {2, 5};
|
||||
auto* src = var1.GetMutable<framework::LoDTensor>();
|
||||
auto* dst = var2.GetMutable<framework::LoDTensor>();
|
||||
src->Resize(framework::make_ddim(dims));
|
||||
dst->Resize(framework::make_ddim(dims));
|
||||
auto* src_mutable = src->mutable_data<T>(place);
|
||||
auto* dst_mutable = dst->mutable_data<T>(place);
|
||||
paddle::memory::Copy(place, src_mutable, src_place, src_data.data(),
|
||||
sizeof(T) * src_data.size(), 0);
|
||||
paddle::memory::Copy(place, dst_mutable, src_place, dst_data.data(),
|
||||
sizeof(T) * dst_data.size(), 0);
|
||||
imperative::TensorAdd(var1, &var2);
|
||||
framework::LoDTensor rlt;
|
||||
platform::CPUPlace rlt_place;
|
||||
framework::TensorCopySync(*dst, rlt_place, &rlt);
|
||||
|
||||
for (unsigned int i = 0; i < rlt.numel(); i++) {
|
||||
if (rlt.data<T>()[i] != result[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
int TensorCPUAddTest(platform::CPUPlace place, T t1, T t2) {
|
||||
framework::Variable var1;
|
||||
framework::Variable var2;
|
||||
std::vector<T> src_data(10, t1);
|
||||
std::vector<T> dst_data(10, t2);
|
||||
std::vector<T> result;
|
||||
platform::CPUPlace src_place;
|
||||
for (unsigned int i = 0; i < 10; i++) {
|
||||
result.emplace_back(src_data[i] + dst_data[i]);
|
||||
}
|
||||
std::vector<int64_t> dims = {2, 5};
|
||||
auto* src = var1.GetMutable<framework::LoDTensor>();
|
||||
auto* dst = var2.GetMutable<framework::LoDTensor>();
|
||||
src->Resize(framework::make_ddim(dims));
|
||||
dst->Resize(framework::make_ddim(dims));
|
||||
auto* src_mutable = src->mutable_data<T>(place);
|
||||
auto* dst_mutable = dst->mutable_data<T>(place);
|
||||
paddle::memory::Copy(place, src_mutable, src_place, src_data.data(),
|
||||
sizeof(T) * src_data.size());
|
||||
paddle::memory::Copy(place, dst_mutable, src_place, dst_data.data(),
|
||||
sizeof(T) * dst_data.size());
|
||||
imperative::TensorAdd(var1, &var2);
|
||||
framework::LoDTensor rlt;
|
||||
platform::CPUPlace rlt_place;
|
||||
framework::TensorCopySync(*dst, rlt_place, &rlt);
|
||||
|
||||
for (unsigned int i = 0; i < rlt.numel(); i++) {
|
||||
if (rlt.data<T>()[i] != result[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(test_add_functor, add_functor) {
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
platform::CUDAPlace gpu_place(0);
|
||||
#endif
|
||||
platform::CPUPlace cpu_place;
|
||||
|
||||
int cpu_res = 1;
|
||||
cpu_res = TensorCPUAddTest(cpu_place, 1.0, 0.0);
|
||||
EXPECT_EQ(cpu_res, 0);
|
||||
cpu_res = TensorCPUAddTest(cpu_place, static_cast<double>(1.0),
|
||||
static_cast<double>(2.0));
|
||||
EXPECT_EQ(cpu_res, 0);
|
||||
#if defined(PADDLE_WITH_CUDA)
|
||||
int gpu_res = 1;
|
||||
gpu_res = TensorGPUAddTest(gpu_place, 1.0, 0.0);
|
||||
EXPECT_EQ(gpu_res, 0);
|
||||
gpu_res = TensorGPUAddTest(gpu_place, static_cast<double>(1.0),
|
||||
static_cast<double>(2.0));
|
||||
EXPECT_EQ(gpu_res, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
//
|
||||
// Created by Jiabin on 2019-08-16.
|
||||
//
|
||||
|
||||
#include <paddle/fluid/framework/op_registry.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/fluid/imperative/layer.h"
|
||||
|
||||
namespace imperative = paddle::imperative;
|
||||
namespace platform = paddle::platform;
|
||||
namespace framework = paddle::framework;
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
using vb_vector = std::vector<std::shared_ptr<imperative::VarBase>>;
|
||||
|
||||
using var_pair = std::pair<std::string, vb_vector>;
|
||||
|
||||
TEST(test_layer, test_runtime_context) {
|
||||
std::shared_ptr<imperative::VarBase> vin(
|
||||
new imperative::VarBase(false, "vin"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(false, "vout"));
|
||||
var_pair in_pair = var_pair("X", vb_vector(1, vin));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {in_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap attrs;
|
||||
auto* ctx = new imperative::RuntimeInferVarTypeContext(ins, &outs, attrs);
|
||||
ASSERT_TRUE(ctx->HasVar("vin"));
|
||||
ASSERT_TRUE(ctx->HasInput("X"));
|
||||
ASSERT_TRUE(ctx->HasOutput("Out"));
|
||||
|
||||
ASSERT_ANY_THROW(ctx->GetDataTypes("vin"));
|
||||
std::vector<framework::proto::VarType::Type> NullType;
|
||||
ASSERT_ANY_THROW(ctx->SetDataTypes("vin", NullType));
|
||||
ASSERT_ANY_THROW(ctx->GetShape("vin"));
|
||||
ASSERT_ANY_THROW(ctx->GetLoDLevel("vin"));
|
||||
ASSERT_ANY_THROW(ctx->SetLoDLevel("vin", 2));
|
||||
}
|
||||
|
||||
std::string LayerDebugString(const std::string& op_type,
|
||||
const NameVarBaseMap& ins,
|
||||
const NameVarBaseMap& outs);
|
||||
|
||||
TEST(test_layer, test_debug_string_test_debug_Test) {
|
||||
std::shared_ptr<imperative::VarBase> vin(
|
||||
new imperative::VarBase(false, "vin"));
|
||||
std::shared_ptr<imperative::VarBase> vin_error(
|
||||
new imperative::VarBase(false, "vin_error"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(false, "vout"));
|
||||
std::shared_ptr<imperative::VarBase> vout_error(
|
||||
new imperative::VarBase(false, "vout_error"));
|
||||
vin_error->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
vout->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
vout_error->MutableVar()->GetMutable<framework::SelectedRows>();
|
||||
var_pair in_pair = var_pair("X", vb_vector(1, vin));
|
||||
vb_vector vb_in_error = {vin_error, nullptr};
|
||||
var_pair vin_error_pair = var_pair("X", vb_in_error);
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
var_pair vout_error_pair = var_pair("Out2", vb_vector(1, vout_error));
|
||||
imperative::NameVarBaseMap ins = {in_pair};
|
||||
imperative::NameVarBaseMap ins_error = {vin_error_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
imperative::NameVarBaseMap outs_error = {vout_error_pair};
|
||||
ASSERT_NO_FATAL_FAILURE(LayerDebugString("test_op", ins, outs));
|
||||
std::string res = LayerDebugString("test_op", ins, outs_error);
|
||||
ASSERT_TRUE(res.find("UNRESOLVED_TYPE") != std::string::npos);
|
||||
std::string res2 = LayerDebugString("test_op", ins_error, outs_error);
|
||||
VLOG(3) << res2;
|
||||
ASSERT_TRUE(res2.find("NOT_INITED") != std::string::npos);
|
||||
ASSERT_TRUE(res2.find("NULL") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST(test_layer, test_clear_backward_info) {
|
||||
std::shared_ptr<imperative::VarBase> vin(
|
||||
new imperative::VarBase(false, "vin"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(false, "vout"));
|
||||
framework::OpDesc desc;
|
||||
platform::CPUPlace place;
|
||||
var_pair x_pair = var_pair("X", vb_vector(1, vin));
|
||||
var_pair y_pair = var_pair("Y", vb_vector(1, vin));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {x_pair, y_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap concat_att_map;
|
||||
concat_att_map["axis"] = 1;
|
||||
std::shared_ptr<imperative::OpBase> op(
|
||||
OpBase::Create(0, "mul", ins, outs, concat_att_map, place));
|
||||
std::shared_ptr<imperative::OpBase> preceding_op(
|
||||
OpBase::Create(0, "mul", ins, outs, concat_att_map, place));
|
||||
op->InsertGradPendingOps(preceding_op.get());
|
||||
*(op->GetMutableInsMap()) = ins;
|
||||
*(op->GetMutableOutsMap()) = outs;
|
||||
ASSERT_GT(op->GetInsMap().size(), 0);
|
||||
ASSERT_GT(op->GetOutsMap().size(), 0);
|
||||
ASSERT_GT(op->GradPendingOps().size(), 0);
|
||||
|
||||
op->ClearBackwardTrace();
|
||||
|
||||
ASSERT_EQ(op->GetInsMap().size(), 0);
|
||||
ASSERT_EQ(op->GetOutsMap().size(), 0);
|
||||
ASSERT_EQ(op->GradPendingOps().size(), 0);
|
||||
}
|
||||
|
||||
TEST(test_layer, test_varbase_basic) {
|
||||
platform::CPUPlace place;
|
||||
std::shared_ptr<imperative::VarBase> vin(
|
||||
new imperative::VarBase(false, "vin"));
|
||||
vin->MutableVar()->GetMutable<framework::LoDTensor>()->mutable_data<float>(
|
||||
place);
|
||||
std::shared_ptr<imperative::VarBase> vout(vin->NewVarBase(place, false));
|
||||
ASSERT_EQ(vout->Name(), "Itmp0");
|
||||
|
||||
std::shared_ptr<imperative::VarBase> vin_with_grad(
|
||||
new imperative::VarBase(true, "vin"));
|
||||
ASSERT_ANY_THROW(vin->MutableGradVar());
|
||||
ASSERT_NO_THROW(ASSERT_TRUE(dynamic_cast<framework::Variable*>(
|
||||
vin_with_grad->MutableGradVar()) != 0));
|
||||
ASSERT_TRUE(
|
||||
dynamic_cast<framework::Variable*>(vin_with_grad->MutableGradVar()) != 0);
|
||||
vin_with_grad->SetStopGradient(true);
|
||||
ASSERT_TRUE(vin_with_grad->StopGradient());
|
||||
ASSERT_NO_FATAL_FAILURE(vin_with_grad->SetPersistable(true));
|
||||
ASSERT_TRUE(vin_with_grad->StopGradient());
|
||||
ASSERT_NO_FATAL_FAILURE(vin_with_grad->SetName("new_name"));
|
||||
ASSERT_EQ(vin_with_grad->Name(), "new_name");
|
||||
}
|
||||
// TODO(jiabin): Add more ut here for layer
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
||||
|
||||
USE_OP(mul);
|
@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
//
|
||||
// Created by Jiabin on 2019-08-19.
|
||||
//
|
||||
|
||||
#include <paddle/fluid/framework/op_registry.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/fluid/framework/op_info.h"
|
||||
#include "paddle/fluid/imperative/prepared_operator.h"
|
||||
#include "paddle/fluid/imperative/type_defs.h"
|
||||
|
||||
namespace imperative = paddle::imperative;
|
||||
namespace platform = paddle::platform;
|
||||
namespace framework = paddle::framework;
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
static framework::RuntimeContext PrepareRuntimeContext(
|
||||
const NameVarBaseMap& ins, const NameVarBaseMap& outs) {
|
||||
framework::VariableValueMap inputs, outputs;
|
||||
for (auto& in_pair : ins) {
|
||||
auto& in_ctx = inputs[in_pair.first];
|
||||
in_ctx.reserve(in_pair.second.size());
|
||||
for (auto& in_var : in_pair.second) {
|
||||
in_ctx.emplace_back(in_var->MutableVar());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& out_pair : outs) {
|
||||
auto& out_ctx = outputs[out_pair.first];
|
||||
out_ctx.reserve(out_pair.second.size());
|
||||
for (auto& out_var : out_pair.second) {
|
||||
out_ctx.emplace_back(out_var->MutableVar());
|
||||
}
|
||||
}
|
||||
return framework::RuntimeContext(std::move(inputs), std::move(outputs));
|
||||
}
|
||||
|
||||
static framework::VariableNameMap CreateVarNameMap(
|
||||
const framework::OpInfo& op_info, const std::string& op_type,
|
||||
const NameVarBaseMap& varbase_map, bool is_input) {
|
||||
if (op_info.proto_ == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
framework::VariableNameMap result;
|
||||
|
||||
for (auto& var :
|
||||
is_input ? op_info.Proto().inputs() : op_info.Proto().outputs()) {
|
||||
auto it = varbase_map.find(var.name());
|
||||
if (it == varbase_map.end()) {
|
||||
PADDLE_ENFORCE_EQ(
|
||||
var.dispensable(), true,
|
||||
"Var: %s not dispensable and there are no such var in inputs",
|
||||
var.name());
|
||||
result[var.name()] = {};
|
||||
} else {
|
||||
auto& var_vector = it->second;
|
||||
std::vector<std::string> args;
|
||||
args.reserve(var_vector.size());
|
||||
for (auto& var_base : var_vector) {
|
||||
args.emplace_back(var_base->Name());
|
||||
}
|
||||
result[var.name()] = std::move(args);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
using vb_vector = std::vector<std::shared_ptr<imperative::VarBase>>;
|
||||
|
||||
using var_pair = std::pair<std::string, vb_vector>;
|
||||
|
||||
TEST(test_prepare_op, test_prepare_op) {
|
||||
std::shared_ptr<imperative::VarBase> vin(
|
||||
new imperative::VarBase(false, "vin"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(false, "vout"));
|
||||
framework::OpDesc desc;
|
||||
platform::CPUPlace place;
|
||||
vin->MutableVar()->GetMutable<framework::LoDTensor>()->mutable_data<float>(
|
||||
place);
|
||||
var_pair x_pair = var_pair("X", vb_vector(1, vin));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {x_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap split_attr_map;
|
||||
const auto& info = framework::OpInfoMap::Instance().Get("split");
|
||||
framework::VariableNameMap var_in_map =
|
||||
CreateVarNameMap(info, "split", ins, true);
|
||||
framework::VariableNameMap var_out_map =
|
||||
CreateVarNameMap(info, "split", outs, false);
|
||||
framework::OperatorWithKernel op("split", var_in_map, var_out_map,
|
||||
split_attr_map);
|
||||
framework::RuntimeContext ctx = PrepareRuntimeContext(ins, outs);
|
||||
ASSERT_NO_FATAL_FAILURE(PreparedOp preparedOp =
|
||||
PreparedOp::Prepare(ctx, op, place));
|
||||
}
|
||||
|
||||
const framework::Tensor* GetTensorFromVar(const framework::Variable& var);
|
||||
|
||||
TEST(test_prepare_op, test_get_tensor_from_var) {
|
||||
std::shared_ptr<imperative::VarBase> vout_error(
|
||||
new imperative::VarBase(false, "vout_error"));
|
||||
vout_error->MutableVar()->GetMutable<framework::SelectedRows>();
|
||||
auto* ts = GetTensorFromVar(*vout_error->MutableVar());
|
||||
ASSERT_TRUE(ts != nullptr);
|
||||
}
|
||||
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
||||
|
||||
USE_OP(split);
|
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2019 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.
|
||||
|
||||
//
|
||||
// Created by Jiabin on 2019-08-16.
|
||||
//
|
||||
|
||||
#include <paddle/fluid/framework/op_registry.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/fluid/imperative/tracer.h"
|
||||
|
||||
namespace imperative = paddle::imperative;
|
||||
namespace platform = paddle::platform;
|
||||
namespace framework = paddle::framework;
|
||||
|
||||
namespace paddle {
|
||||
namespace imperative {
|
||||
|
||||
using vb_vector = std::vector<std::shared_ptr<imperative::VarBase>>;
|
||||
|
||||
using var_pair = std::pair<std::string, vb_vector>;
|
||||
|
||||
TEST(test_tracer, test_trace_op) {
|
||||
// Doing an mul
|
||||
imperative::Tracer tracer;
|
||||
std::shared_ptr<imperative::VarBase> x_in(
|
||||
new imperative::VarBase(true, "x_in"));
|
||||
std::shared_ptr<imperative::VarBase> y_in(
|
||||
new imperative::VarBase(true, "y_in"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(true, "vout"));
|
||||
platform::CPUPlace place;
|
||||
std::vector<float> src_data(10, 2.0);
|
||||
std::vector<int64_t> dims1 = {2, 5};
|
||||
std::vector<int64_t> dims2 = {5, 2};
|
||||
|
||||
auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
x_in_tensor->Resize(framework::make_ddim(dims1));
|
||||
auto* mutable_x = x_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_x, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
y_in_tensor->Resize(framework::make_ddim(dims2));
|
||||
auto* mutable_y = y_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_y, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
|
||||
var_pair x_pair = var_pair("X", vb_vector(1, x_in));
|
||||
var_pair y_pair = var_pair("Y", vb_vector(1, y_in));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {x_pair, y_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap mul_attr_map;
|
||||
mul_attr_map["use_mkldnn"] = false;
|
||||
tracer.TraceOp("mul", ins, outs, mul_attr_map, place, true);
|
||||
const auto& out_tensor = vout->Var().Get<framework::LoDTensor>();
|
||||
for (size_t i = 0; i < vout->Var().Get<framework::LoDTensor>().numel(); i++) {
|
||||
ASSERT_EQ(out_tensor.data<float>()[i], 20.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(test_tracer, test_track_backward_output) {
|
||||
// Doing an mul
|
||||
imperative::Tracer tracer;
|
||||
std::shared_ptr<imperative::VarBase> x_in(
|
||||
new imperative::VarBase(true, "x_in"));
|
||||
std::shared_ptr<imperative::VarBase> y_in(
|
||||
new imperative::VarBase(false, "y_in"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(true, "vout"));
|
||||
platform::CPUPlace place;
|
||||
std::vector<float> src_data(10, 2.0);
|
||||
std::vector<int64_t> dims1 = {2, 5};
|
||||
std::vector<int64_t> dims2 = {5, 2};
|
||||
|
||||
auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
x_in_tensor->Resize(framework::make_ddim(dims1));
|
||||
auto* mutable_x = x_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_x, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
y_in_tensor->Resize(framework::make_ddim(dims2));
|
||||
auto* mutable_y = y_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_y, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
|
||||
var_pair x_pair = var_pair("X", vb_vector(1, x_in));
|
||||
var_pair y_pair = var_pair("Y", vb_vector(1, y_in));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {x_pair, y_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap mul_attr_map;
|
||||
mul_attr_map["use_mkldnn"] = false;
|
||||
ASSERT_ANY_THROW(tracer.TraceOp("mul", ins, outs, mul_attr_map, place, true));
|
||||
}
|
||||
|
||||
TEST(test_tracer, test_track_backward_input) {
|
||||
// Doing an mul
|
||||
imperative::Tracer tracer;
|
||||
std::shared_ptr<imperative::VarBase> x_in(
|
||||
new imperative::VarBase(true, "x_in"));
|
||||
std::shared_ptr<imperative::VarBase> y_in(
|
||||
new imperative::VarBase(true, "y_in"));
|
||||
std::shared_ptr<imperative::VarBase> vout(
|
||||
new imperative::VarBase(false, "vout"));
|
||||
platform::CPUPlace place;
|
||||
std::vector<float> src_data(10, 2.0);
|
||||
std::vector<int64_t> dims1 = {2, 5};
|
||||
std::vector<int64_t> dims2 = {5, 2};
|
||||
|
||||
auto* x_in_tensor = x_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
auto* y_in_tensor = y_in->MutableVar()->GetMutable<framework::LoDTensor>();
|
||||
x_in_tensor->Resize(framework::make_ddim(dims1));
|
||||
auto* mutable_x = x_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_x, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
y_in_tensor->Resize(framework::make_ddim(dims2));
|
||||
auto* mutable_y = y_in_tensor->mutable_data<float>(place);
|
||||
paddle::memory::Copy(place, mutable_y, place, src_data.data(),
|
||||
sizeof(float) * src_data.size());
|
||||
|
||||
var_pair x_pair = var_pair("X", vb_vector(1, x_in));
|
||||
var_pair y_pair = var_pair("Y", vb_vector(1, y_in));
|
||||
var_pair out_pair = var_pair("Out", vb_vector(1, vout));
|
||||
imperative::NameVarBaseMap ins = {x_pair, y_pair};
|
||||
imperative::NameVarBaseMap outs = {out_pair};
|
||||
framework::AttributeMap mul_attr_map;
|
||||
mul_attr_map["use_mkldnn"] = false;
|
||||
ASSERT_ANY_THROW(tracer.TraceOp("mul", ins, outs, mul_attr_map, place, true));
|
||||
}
|
||||
} // namespace imperative
|
||||
} // namespace paddle
|
||||
|
||||
USE_OP(mul);
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue