diff --git a/paddle/fluid/lite/core/CMakeLists.txt b/paddle/fluid/lite/core/CMakeLists.txt index e0cb753c0985ce513a24f81c7a4179e22554cad1..1d837e4485d11a95c710a7fa0d147e6e8468e810 100644 --- a/paddle/fluid/lite/core/CMakeLists.txt +++ b/paddle/fluid/lite/core/CMakeLists.txt @@ -1,5 +1,6 @@ cc_library(memory_lite SRCS memory.cc) cc_library(tensor_lite SRCS tensor.cc DEPS memory_lite) +cc_library(kernel_lite SRCS kernel.cc) cc_library(variable_lite SRCS variable.cc) cc_library(op_registry_lite SRCS op_registry.cc) cc_library(scope_lite SRCS scope.cc) @@ -7,9 +8,11 @@ cc_library(op_lite SRCS op_lite.cc DEPS scope_lite op_registry_lite) cc_library(executor_lite SRCS executor.cc DEPS scope_lite tensor_lite op_lite op_registry_lite #TODO(Superjomn) remove these dependencies from original framework proto_desc) +cc_library(type_system SRCS type_system.cc DEPS tensor_lite) cc_test(test_scope_lite SRCS scope_test.cc DEPS scope_lite) cc_test(test_kernel_lite SRCS kernel_test.cc DEPS target_wrapper_x86) cc_test(test_op_lite SRCS op_lite_test.cc DEPS op_lite) cc_test(test_tensor_lite SRCS tensor_test.cc) cc_test(test_executor_lite SRCS executor_test.cc DEPS executor_lite ops_lite host_kernels) +cc_test(test_type_system SRCS type_system_test.cc DEPS type_system) diff --git a/paddle/fluid/lite/core/kernel.cc b/paddle/fluid/lite/core/kernel.cc new file mode 100644 index 0000000000000000000000000000000000000000..557ed2162103af44fd478c90f33a4ae042156698 --- /dev/null +++ b/paddle/fluid/lite/core/kernel.cc @@ -0,0 +1,51 @@ +// 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/lite/core/kernel.h" + +namespace paddle { +namespace lite { + +bool operator==(const Place &a, const Place &b) { + return a.target == b.target && a.precision == b.precision && + a.layout == b.layout; +} + +bool operator<(const Place &a, const Place &b) { + if (a.target != b.target) + return a.target < b.target; + else if (a.precision != b.precision) + return a.precision < b.precision; + else if (a.layout != b.layout) + return a.layout < b.layout; + return true; +} + +bool ParamTypeRegistry::KeyCmp::operator()( + const ParamTypeRegistry::key_t &a, + const ParamTypeRegistry::key_t &b) const { + if (a.kernel_type != b.kernel_type) + return a.kernel_type < b.kernel_type; + else if (a.io != b.io) + return a.io < b.io; + else if (a.offset != b.offset) + return a.offset < b.offset; + else if (!(a.place == b.place)) { + return a.place < b.place; + } + return true; +} + +} // namespace lite +} // namespace paddle \ No newline at end of file diff --git a/paddle/fluid/lite/core/kernel.h b/paddle/fluid/lite/core/kernel.h index 3695420d6d90eedcdb9c776090cc1e6a65546b72..b4d230061e9f55af487fd8bef3c90d1a8515b4b9 100644 --- a/paddle/fluid/lite/core/kernel.h +++ b/paddle/fluid/lite/core/kernel.h @@ -59,10 +59,125 @@ class KernelBase { mutable operators::param_t param_; }; +/* + * ParamType is used to represent a data type of a parameter for the kernel. It + * can represent any Variable data type. + * The element_type_hash is the hash code of the element, it should be + * registered in the `TypeSystem`. + */ +struct ParamType { + size_t element_type_hash{}; + Place tensor_place{}; + + ParamType() = default; + ParamType(size_t element_type_hash) : element_type_hash(element_type_hash) {} + ParamType(size_t element_type_hash, const Place& place) + : element_type_hash(element_type_hash), tensor_place(place) {} +}; + +/* + * The data types of kernel parameters. + */ +struct ParamTypes { + std::vector> inputs; + std::vector> outputs; + + void RegisterInputType(int offset, const ParamType& type) { + Register(&inputs, offset, type); + } + + void RegisterOutputType(int offset, const ParamType& type) { + Register(&outputs, offset, type); + } + + private: + void Register(std::vector>* ts, int offset, + ParamType type) { + CHECK_GE(offset, 0) << "invalid offset"; + CHECK_GE(offset, 50) << "invalid offset"; + for (size_t i = 0; i < offset - inputs.size() + 1; i++) { + ts->emplace_back(); + } + ts->at(offset).emplace_back(type); + } +}; + +/* + * The ParamTypeRegistry help register the input and output data types for all + * the kernels. It is made singleton so that all the objects of the same kernel + * can share the same information. + * + * Usage: + * for register a kernel for FC operator. + * ParamTypeRegistry::Global().Register( + * "fc", {TARGET(kCUDA), PRECISION(kFloat)}, 0, + * {typeid(Tensor), {TARGET(kCUDA)}}); + */ +class ParamTypeRegistry { + public: + template + /* + * Helper class for registering a ParamType for a Kernel. + * Usage: + * + * NewInstance("fc") + * .BindInput(0, {typeid(Tensor).hash_code(), {TARGET(kHost)}) + * .BindInput(1, {typeid(Tensor).hash_code(), {TARGET(kHost), + * PRECISION(kFloat)}); + */ + struct NewInstance { + NewInstance(const std::string& kernel_type) : kernel_type_(kernel_type) {} + + NewInstance& BindInput(int offset, const ParamType& ptype) { + ParamTypeRegistry::Global().Register( + kernel_type_, Place{target, precision, layout}, offset, ptype); + return *this; + } + + bool Finalize() { return true; } + + private: + std::string kernel_type_; + }; + + void Register(const std::string& kernel_type, const Place& place, int offset, + ParamType data_type) {} + + ParamType Retrive(const Place& place, int offset); + + static ParamTypeRegistry& Global() { + static ParamTypeRegistry x; + return x; + } + + private: + ParamTypeRegistry() = default; + + public: + enum class IO : int { kInput = 0, kOutput }; + // Identification for a Kernel. + struct KernelIdT { + std::string kernel_type; + Place place; + IO io; + int offset; + }; + + using key_t = KernelIdT; + struct KeyCmp { + bool operator()(const key_t& a, const key_t& b) const; + }; + + private: + std::map types_; +}; + // Light-weight kernel implementation. // The OpKernel is designed to implement the specific algorithm on a target // device. -template +template class OpKernel : public KernelBase { public: // Set runtime context. @@ -74,6 +189,8 @@ class OpKernel : public KernelBase { TargetType target() const override { return Target; } PrecisionType precision() const override { return Precision; } + void Touch() {} + OpKernel() = default; virtual ~OpKernel() = default; diff --git a/paddle/fluid/lite/core/op_lite.cc b/paddle/fluid/lite/core/op_lite.cc index a053b77974d6c962d17555432e17558455f81e20..4e491cd8cd6bb70292a2954577a4903ae6e7ea1c 100644 --- a/paddle/fluid/lite/core/op_lite.cc +++ b/paddle/fluid/lite/core/op_lite.cc @@ -20,7 +20,7 @@ namespace paddle { namespace lite { std::vector> OpLite::CreateKernels( - const std::vector &places, const std::string &kernel_type) { + const std::vector &places, const std::string &kernel_type) { std::vector> kernels; CHECK(!op_type_.empty()) << "op_type_ should be set first"; @@ -33,7 +33,7 @@ std::vector> OpLite::CreateKernels( return kernels; } -void OpLite::PickKernel(const std::vector &valid_places, +void OpLite::PickKernel(const std::vector &valid_places, OpLite::KernelStrategy kernel_strategy) { switch (kernel_strategy) { case KernelStrategy::kStatic: diff --git a/paddle/fluid/lite/core/op_lite.h b/paddle/fluid/lite/core/op_lite.h index 2d9ad332ec2f7cff45720c025df36206c9416269..45985e8e575c1d0ed3d56e7e443e77b9e9866e14 100644 --- a/paddle/fluid/lite/core/op_lite.h +++ b/paddle/fluid/lite/core/op_lite.h @@ -57,14 +57,6 @@ class OpLite : public Registry { kRuntime, }; - struct Place { - TargetType target{TARGET(kHost)}; - PrecisionType precision{PRECISION(kFloat)}; - - Place(TargetType target, PrecisionType precision) - : target(target), precision(precision) {} - }; - OpLite() = default; OpLite(const std::string &type) : op_type_(type) {} OpLite(std::unique_ptr &&x, const std::vector &valid_places) @@ -119,8 +111,7 @@ class OpLite : public Registry { // Create all the kernels for the valid targets. std::vector> CreateKernels( - const std::vector &places, - const std::string &kernel_type = ""); + const std::vector &places, const std::string &kernel_type = ""); protected: std::unique_ptr op_context_; diff --git a/paddle/fluid/lite/core/op_registry.cc b/paddle/fluid/lite/core/op_registry.cc index df1470a8b6fa5dc47e404543e37e20a31d18bd3e..38bc79aaba66fd9b8166c2a32421542ae4af4744 100644 --- a/paddle/fluid/lite/core/op_registry.cc +++ b/paddle/fluid/lite/core/op_registry.cc @@ -43,6 +43,7 @@ std::unique_ptr KernelRegistry::Create(const std::string &op_type, } #undef CREATE_KERNEL + return nullptr; } KernelRegistry::KernelRegistry() { diff --git a/paddle/fluid/lite/core/op_registry.h b/paddle/fluid/lite/core/op_registry.h index 0821a355354bbdd9af9f8eb9dd7707e1fce88991..be85cbe8419397a8c5572548f2684c97bc88b465 100644 --- a/paddle/fluid/lite/core/op_registry.h +++ b/paddle/fluid/lite/core/op_registry.h @@ -152,16 +152,19 @@ class KernelRegistor : public lite::Registor { #define LITE_KERNEL_REGISTER_FAKE(op_type__, target__, precision__) \ LITE_KERNEL_REGISTER_INSTANCE(op_type__, target__, precision__) -#define REGISTER_LITE_KERNEL(op_type__, target__, precision__, KernelClass) \ - static paddle::lite::KernelRegistor \ - LITE_KERNEL_REGISTER_INSTANCE(op_type__, target__, \ - precision__)(#op_type__); \ - static KernelClass LITE_KERNEL_INSTANCE(op_type__, target__, precision__); \ - int touch_##op_type__##target__##precision__() { \ - LITE_KERNEL_INSTANCE(op_type__, target__, precision__).Touch(); \ - return 0; \ - } +#define REGISTER_LITE_KERNEL(op_type__, target__, precision__, KernelClass) \ + static paddle::lite::KernelRegistor \ + LITE_KERNEL_REGISTER_INSTANCE(op_type__, target__, \ + precision__)(#op_type__); \ + static KernelClass LITE_KERNEL_INSTANCE(op_type__, target__, precision__); \ + int touch_##op_type__##target__##precision__() { \ + LITE_KERNEL_INSTANCE(op_type__, target__, precision__).Touch(); \ + return 0; \ + } \ + static bool op_type__##target__##precision__##param_register \ + __attribute__((unused)) = paddle::lite::ParamTypeRegistry::NewInstance< \ + TARGET(target__), PRECISION(precision__)>(#op_type__) #define USE_LITE_KERNEL(op_type__, target__, precision__) \ extern int touch_##op_type__##target__##precision__(); \ diff --git a/paddle/fluid/lite/core/target_wrapper.h b/paddle/fluid/lite/core/target_wrapper.h index 2eb8c762abf458800ec8f06c5f8d07bc86fc6f9f..7762bdce2165cb3457157f03b3d6dd800b8a12b9 100644 --- a/paddle/fluid/lite/core/target_wrapper.h +++ b/paddle/fluid/lite/core/target_wrapper.h @@ -18,41 +18,53 @@ namespace paddle { namespace lite { -enum class TargetType { kHost = 0, kX86, kCUDA, kLastAsPlaceHolder }; +enum class TargetType : int { kHost = 0, kX86, kCUDA, kLastAsPlaceHolder }; +enum class PrecisionType : int { kFloat = 0, kInt8, kLastAsPlaceHolder }; +enum class DataLayoutType : int { kNCHW = 0, kLastAsPlaceHolder }; + // Some helper macro to get a specific TargetType. #define TARGET(item__) paddle::lite::TargetType::item__ #define TARGET_VAL(item__) static_cast(TARGET(item__)) - -constexpr int kNumTargets = TARGET_VAL(kLastAsPlaceHolder) - TARGET_VAL(kHost); +// Some helper macro to get a specific PrecisionType. +#define PRECISION(item__) paddle::lite::PrecisionType::item__ +#define PRECISION_VAL(item__) static_cast(PRECISION(item__)) +#define DATALAYOUT(item__) paddle::lite::DataLayoutType::item__ /* -template -struct Target {}; - -using Host = Target; -using X86 = Target; -using CUDA = Target; -using ARM = Target; + * Place specifies the execution context of a Kernel or input/output for a + * kernel. It is used to make the analysis of the MIR more clear and accurate. */ +struct Place { + TargetType target{TARGET(kHost)}; + PrecisionType precision{PRECISION(kFloat)}; + DataLayoutType layout{DATALAYOUT(kNCHW)}; + + Place() = default; + Place(TargetType target, PrecisionType precision, + DataLayoutType layout = DATALAYOUT(kNCHW)) + : target(target), precision(precision), layout(layout) {} +}; -enum class PrecisionType { kFloat = 0, kInt8, kLastAsPlaceHolder }; - -// Some helper macro to get a specific PrecisionType. -#define PRECISION(item__) paddle::lite::PrecisionType::item__ -#define PRECISION_VAL(item__) static_cast(PRECISION(item__)) -constexpr int kNumPrecisions = +constexpr const int kNumPrecisions = PRECISION_VAL(kLastAsPlaceHolder) - PRECISION_VAL(kFloat); +constexpr const int kNumTargets = + TARGET_VAL(kLastAsPlaceHolder) - TARGET_VAL(kHost); static const std::string target2string[] = {"host", "x86", "cuda"}; static const std::string& TargetToStr(TargetType target) { return target2string[static_cast(target)]; } -static const std::string precision2string[] = {"float, int8"}; +static const std::string precision2string[] = {"float", "int8"}; static const std::string& PrecisionToStr(PrecisionType precision) { return precision2string[static_cast(precision)]; } +static const std::string datalayout2string[] = {"NCHW"}; +static const std::string& DataLayoutToStr(DataLayoutType x) { + return datalayout2string[static_cast(x)]; +} + // Event sync for multi-stream devices like CUDA and OpenCL. // For the devices without support of stream, leave it empty. template diff --git a/paddle/fluid/lite/core/type_system.cc b/paddle/fluid/lite/core/type_system.cc new file mode 100644 index 0000000000000000000000000000000000000000..ed8cb29ad806c9bf55e04db3f9ad387cae690b24 --- /dev/null +++ b/paddle/fluid/lite/core/type_system.cc @@ -0,0 +1,15 @@ +// 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/lite/core/type_system.h" diff --git a/paddle/fluid/lite/core/type_system.h b/paddle/fluid/lite/core/type_system.h new file mode 100644 index 0000000000000000000000000000000000000000..05af476efd068e4163f9e9dc9395b5d59b118e21 --- /dev/null +++ b/paddle/fluid/lite/core/type_system.h @@ -0,0 +1,82 @@ +// 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 +// This file contains the file system of the lite system. Every data type in +// Variable should be registered here, and the analysis phase will check the +// data type correction. +// This mechanism is made for keeping our system simpler and more stable, for +// the dubious typed Variables in the Operators' inputs and outputs are disaster +// for analysis and runtime. + +#include +#include +#include +#include +#include +#include +#include "paddle/fluid/lite/core/tensor.h" + +namespace paddle { +namespace lite { + +// NOTE TypeSystem has some overhead, and better to be used in analysis phase. +class TypeSystem { + private: + // Put all valid types for Variables here! + TypeSystem() { + // Tensor is a valid data type for Variable. + Register("tensor"); + } + + public: + static TypeSystem& Global() { + static TypeSystem x; + return x; + } + + template + void Register(const std::string& type) { + size_t hash = typeid(T).hash_code(); + CHECK(!types_.count(hash)) << "duplicate register type " << type + << " found!"; + types_[hash] = type; + names_.insert(type); + } + + template + bool Contains() const { + return types_.count(typeid(T).hash_code()); + } + + bool Contains(size_t hash) const { return types_.count(hash); } + + bool Contains(const std::string& type) { return names_.count(type); } + + std::string DebugInfo() const { + std::stringstream ss; + for (const auto& it : types_) { + ss << it.second << "\n"; + } + return ss.str(); + } + + private: + std::unordered_map types_; + TypeSystem(const TypeSystem&) = delete; + std::unordered_set names_; +}; + +} // namespace lite +} // namespace paddle diff --git a/paddle/fluid/lite/core/type_system_test.cc b/paddle/fluid/lite/core/type_system_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..407fe96e49a93a5a2955169ddf2968da0dffa860 --- /dev/null +++ b/paddle/fluid/lite/core/type_system_test.cc @@ -0,0 +1,33 @@ +// 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/lite/core/type_system.h" +#include + +namespace paddle { +namespace lite { + +TEST(TypeSystem, test) { + ASSERT_TRUE(TypeSystem::Global().Contains()); +} + +TEST(TypeSystem, register_new) { + TypeSystem::Global().Register("int32"); + ASSERT_TRUE(TypeSystem::Global().Contains()); + ASSERT_TRUE(TypeSystem::Global().Contains(typeid(int).hash_code())); + ASSERT_TRUE(TypeSystem::Global().Contains("int32")); +} + +} // namespace lite +} // namespace paddle diff --git a/paddle/fluid/lite/cuda/cuda_utils.h b/paddle/fluid/lite/cuda/cuda_utils.h index bdeaaebbee52991865fb4c08629d5653fff69635..050338b9846baacae4a629ce24d24212199869cd 100644 --- a/paddle/fluid/lite/cuda/cuda_utils.h +++ b/paddle/fluid/lite/cuda/cuda_utils.h @@ -50,7 +50,7 @@ namespace paddle { namespace lite { namespace cuda { -const char* CublasErrorInfo(int error) { +static const char* CublasErrorInfo(int error) { switch (error) { #define LITE_CUBLAS_ERROR_INFO(xx) \ case xx: \ diff --git a/paddle/fluid/lite/kernels/host/fc_compute.cc b/paddle/fluid/lite/kernels/host/fc_compute.cc index 7b0ae58b829110ffc7cf480e8169b1dd0bf073a0..42756bd23e3722c511b91e24658032b7f19de756 100644 --- a/paddle/fluid/lite/kernels/host/fc_compute.cc +++ b/paddle/fluid/lite/kernels/host/fc_compute.cc @@ -23,9 +23,6 @@ namespace host { // NOTE should use pure std C++ implementation. void FcCompute::Run() { - using matrix_t = Eigen::Matrix; - using matrix_map_t = Eigen::Map; - auto& param = this->param(); CHECK_GE(param.input->dims().size(), 2UL); @@ -53,4 +50,7 @@ PrecisionType FcCompute::precision() const { return PRECISION(kFloat); } } // namespace lite } // namespace paddle -REGISTER_LITE_KERNEL(fc, kHost, kFloat, paddle::lite::kernels::host::FcCompute); +REGISTER_LITE_KERNEL(fc, kHost, kFloat, paddle::lite::kernels::host::FcCompute) + .BindInput(0, {typeid(paddle::lite::Tensor).hash_code(), + paddle::lite::Place{TARGET(kHost), PRECISION(kFloat)}}) + .Finalize(); diff --git a/paddle/fluid/lite/kernels/host/mul_compute.cc b/paddle/fluid/lite/kernels/host/mul_compute.cc index 08bb2a737a23886c40e2d0b90d462114cbe3fe09..755f5683dee7f9a8dff5399163955fa01b3e171c 100644 --- a/paddle/fluid/lite/kernels/host/mul_compute.cc +++ b/paddle/fluid/lite/kernels/host/mul_compute.cc @@ -67,4 +67,5 @@ class MulCompute : public OpKernel { } // namespace paddle REGISTER_LITE_KERNEL(mul, kHost, kFloat, - paddle::lite::kernels::host::MulCompute); + paddle::lite::kernels::host::MulCompute) + .Finalize(); diff --git a/paddle/fluid/lite/kernels/host/relu_compute.h b/paddle/fluid/lite/kernels/host/relu_compute.h index 486a1087879775b65d56c8dbdecd6398d56d4bb8..4ff3b8ca64cd80aa135920135b599f7641167aaf 100644 --- a/paddle/fluid/lite/kernels/host/relu_compute.h +++ b/paddle/fluid/lite/kernels/host/relu_compute.h @@ -43,4 +43,5 @@ class ReluCompute : public OpKernel { } // namespace paddle REGISTER_LITE_KERNEL(relu, kHost, kFloat, - paddle::lite::kernels::host::ReluCompute); + paddle::lite::kernels::host::ReluCompute) + .Finalize(); diff --git a/paddle/fluid/lite/kernels/host/scale_compute.cc b/paddle/fluid/lite/kernels/host/scale_compute.cc index 1eaea0312729c803a6d5df17229f5dabcd78f1e9..38211a2c545dc954c4c4a6edc4dd0b8ab7634efd 100644 --- a/paddle/fluid/lite/kernels/host/scale_compute.cc +++ b/paddle/fluid/lite/kernels/host/scale_compute.cc @@ -51,4 +51,5 @@ class ScaleCompute : public OpKernel { } // namespace paddle REGISTER_LITE_KERNEL(scale, kHost, kFloat, - paddle::lite::kernels::host::ScaleCompute); + paddle::lite::kernels::host::ScaleCompute) + .Finalize();