From 0e91e081b8b706e9b9c1ec9fd9696a3bc84a1ae7 Mon Sep 17 00:00:00 2001 From: Superjom Date: Sat, 29 Jul 2017 15:44:23 +0800 Subject: [PATCH 01/16] init lottensor --- paddle/framework/tensor.h | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h index 039ab08374e99..6c4f6d98d0a36 100644 --- a/paddle/framework/tensor.h +++ b/paddle/framework/tensor.h @@ -18,6 +18,8 @@ limitations under the License. */ #include #include #include +#include + #include "paddle/framework/ddim.h" #include "paddle/memory/memory.h" #include "paddle/platform/device_context.h" @@ -171,6 +173,44 @@ class Tensor { size_t offset_; }; +/* + * LODTensor + */ +class LODTensor { + public: + typedef std::vector level_t; + typedef std::vector lod_t; + + size_t Levels() const { return lod_start_pos_->size(); } + size_t Elements(int level = 0) const { + return lod_start_pos_->at(level).size(); + } + // Slice of level[elem_begin: elem_end] + // NOTE low performance in slice seq_start_positions_. + // TODO should call Tensor's Slice. + LODTensor LODSlice(int level, int elem_begin, int elem_end) const; + + // Slice with tensor's data shared with this. + // LODTensor LODSliceShared(int level, int elem_begin, int elem_end) const; + + // Copy other's lod_start_pos_, to share LOD info. + // NOTE the LOD info sould not be changed. + void ShareConstLODFrom(const LODTensor& other) { + lod_start_pos_ = other.lod_start_pos_; + } + // Copy other's lod_start_pos_'s content, free to mutate. + void ShareMutableLODFrom(const LODTensor& other) { + lod_start_pos_ = std::make_shared(other); + } + + // Determine whether LODTensor has a valid LOD info. + bool HasLOD() const { return lod_start_pos_.get(); } + + private: + std::shared_ptr lod_start_pos_; + Tensor* tensor_{nullptr}; +}; + } // namespace framework } // namespace paddle From 32c948ac96919e8b5b2f3282b641e27e80542eb3 Mon Sep 17 00:00:00 2001 From: Superjom Date: Sun, 30 Jul 2017 10:35:06 +0800 Subject: [PATCH 02/16] init lottensor --- paddle/framework/detail/tensor-inl.h | 28 +++++++++++++ paddle/framework/tensor.cc | 13 +++++- paddle/framework/tensor.h | 60 +++++++++++++++++++++++----- paddle/framework/tensor_test.cc | 39 ++++++++++++++++++ 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/paddle/framework/detail/tensor-inl.h b/paddle/framework/detail/tensor-inl.h index e7ff09dd5c954..0029b7cd933dc 100644 --- a/paddle/framework/detail/tensor-inl.h +++ b/paddle/framework/detail/tensor-inl.h @@ -138,5 +138,33 @@ inline void Tensor::Resize(const DDim& dims) { dims_ = dims; } inline const DDim& Tensor::dims() const { return dims_; } +template +LODTensor LODTensor::Slice(uint32_t level, uint32_t elem_begin, + uint32_t elem_end) const { + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + PADDLE_ENFORCE(elem_begin < Elements(level), + "element begin [%d] out of range [%d]", elem_begin, + Elements(level)); + PADDLE_ENFORCE(elem_end < Elements(level), + "element end [%d] out of range [%d]", elem_begin, + Elements(level)); + // slice the lod. + auto new_lod = std::make_shared(); + auto start = lod_start_pos_->at(level)[elem_begin]; + auto end = lod_start_pos_->at(level)[elem_end]; + for (const auto& l : *lod_start_pos_) { + auto it_begin = std::find(l.begin(), l.end(), start); + auto it_end = std::find(it_begin, l.end(), end); + new_lod->emplace_back(it_begin, it_end); + } + auto new_tensor = tensor_->Slice(start, end); + + LODTensor res; + res.set_tensor(new_tensor); + res.set_lod(new_lod); + return res; +} + } // namespace framework } // namespace paddle diff --git a/paddle/framework/tensor.cc b/paddle/framework/tensor.cc index ea7b2a1f7b17d..bd061870ec43f 100644 --- a/paddle/framework/tensor.cc +++ b/paddle/framework/tensor.cc @@ -15,5 +15,16 @@ #include "paddle/framework/tensor.h" namespace paddle { -namespace framework {} +namespace framework { + +LODTensor LODTensor::Slice(uint32_t level) const { + LODTensor res; + auto new_lod = std::make_shared(lod_start_pos_->begin() + level, + lod_start_pos_->end()); + res.set_tensor(tensor_); + res.set_lod(new_lod); + return res; +} + +} // namespace framework } // namespace paddle diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h index 02aa025724cce..d4d8d6bfb5ffc 100644 --- a/paddle/framework/tensor.h +++ b/paddle/framework/tensor.h @@ -19,6 +19,10 @@ limitations under the License. */ #include #include #include +#if (!PADDLE_ONLY_CPU) +#include +#include +#endif #include "paddle/framework/ddim.h" #include "paddle/memory/memory.h" @@ -171,17 +175,50 @@ class Tensor { */ class LODTensor { public: - typedef std::vector level_t; +// level_t save offsets of each unit. +#ifdef PADDLE_ONLY_CPU + using level_t = std::vector; +#else + using level_t = thrust::device_vector; +#endif + // LOD stores offsets of each level of units, the largest units level first, + // then the smaller units level. Each level_t stores the offsets of units in + // Tesor. typedef std::vector lod_t; - size_t Levels() const { return lod_start_pos_->size(); } - size_t Elements(int level = 0) const { + explicit LODTensor() {} + + LODTensor(LODTensor&& other) + : lod_start_pos_(std::move(other.lod_start_pos_)), + tensor_(other.tensor_) {} + + /* + * Number of LODTensor's levels, each level has units of data, for example, + * in the sentence's view, article, paragraph, sentence are 3 levels. + */ + size_t Levels() const { + return lod_start_pos_.get() ? lod_start_pos_->size() : 0UL; + } + /* + * Number of elements in a level. + */ + size_t Elements(uint32_t level = 0) const { + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); return lod_start_pos_->at(level).size(); } - // Slice of level[elem_begin: elem_end] - // NOTE low performance in slice seq_start_positions_. - // TODO should call Tensor's Slice. - LODTensor LODSlice(int level, int elem_begin, int elem_end) const; + + /* + * Slice of a level. + */ + LODTensor Slice(uint32_t level) const; + + /* + * Slice of elements of a level, [elem_begin: elem_end] + * NOTE low performance in slice seq_start_positions_. + */ + template + LODTensor Slice(uint32_t level, uint32_t elem_begin, uint32_t elem_end) const; // Slice with tensor's data shared with this. // LODTensor LODSliceShared(int level, int elem_begin, int elem_end) const; @@ -193,15 +230,18 @@ class LODTensor { } // Copy other's lod_start_pos_'s content, free to mutate. void ShareMutableLODFrom(const LODTensor& other) { - lod_start_pos_ = std::make_shared(other); + lod_start_pos_ = std::make_shared(*other.lod_start_pos_); } - // Determine whether LODTensor has a valid LOD info. bool HasLOD() const { return lod_start_pos_.get(); } + void set_tensor(std::shared_ptr tensor) { tensor_ = tensor; } + void set_lod(std::shared_ptr lod) { this->lod_start_pos_ = lod; } + Tensor* tensor() { return tensor_.get(); } + private: std::shared_ptr lod_start_pos_; - Tensor* tensor_{nullptr}; + std::shared_ptr tensor_; }; } // namespace framework diff --git a/paddle/framework/tensor_test.cc b/paddle/framework/tensor_test.cc index ef1cc10b84089..94ca67266ae7e 100644 --- a/paddle/framework/tensor_test.cc +++ b/paddle/framework/tensor_test.cc @@ -260,3 +260,42 @@ TEST(Tensor, CopyFrom) { } #endif } + +namespace paddle { +namespace framework { + +class LODTensorTester : public ::testing::Test { + public: + virtual void SetUp() override { + lod_tensor = decltype(lod_tensor)(new LODTensor); + // tensor's batch_size: 30 + // 3 levels + // 0 10 20 + // 0 5 10 15 20 + // 0 2 5 7 10 12 15 20 + auto lod = std::make_shared(); + lod->emplace_back(LODTensor::level_t{0, 10, 20}); + lod->emplace_back(LODTensor::level_t{0, 5, 10, 15, 20}); + lod->emplace_back(LODTensor::level_t{0, 2, 5, 7, 10, 12, 15, 17, 20}); + + auto tensor = std::make_shared(); + DDim dims = make_ddim({20 /*batch size*/, 128 /*dim*/}); + tensor->Resize(dims); + + lod_tensor->set_tensor(tensor); + lod_tensor->set_lod(lod); + } + + protected: + std::unique_ptr lod_tensor; +}; + +TEST_F(LODTensorTester, Levels) { ASSERT_EQ(lod_tensor->Levels(), 3UL); } + +TEST_F(LODTensorTester, Elements) { + ASSERT_EQ(lod_tensor->Elements(0), 3UL); + ASSERT_EQ(lod_tensor->Elements(1), 5UL); + ASSERT_EQ(lod_tensor->Elements(2), 9UL); +} +} // namespace framework +} // namespace paddle From 660fc06934df9b1c50dc97ae82ce721dafb776c1 Mon Sep 17 00:00:00 2001 From: Superjom Date: Tue, 1 Aug 2017 19:28:41 +0800 Subject: [PATCH 03/16] finish lodtensor --- paddle/framework/.clang-format | 3 ++ paddle/framework/CMakeLists.txt | 3 ++ paddle/framework/detail/tensor-inl.h | 28 ---------- paddle/framework/tensor.cc | 13 +---- paddle/framework/tensor.h | 78 ---------------------------- paddle/framework/tensor_test.cc | 41 +-------------- 6 files changed, 8 insertions(+), 158 deletions(-) diff --git a/paddle/framework/.clang-format b/paddle/framework/.clang-format index 29282dc87e2c4..1f096f94d9292 100644 --- a/paddle/framework/.clang-format +++ b/paddle/framework/.clang-format @@ -2,4 +2,7 @@ Language: Cpp BasedOnStyle: Google Standard: Cpp11 +AlignTrailingComments: true +#FixNamespaceComments: true +SpacesBeforeTrailingComments: 2 ... diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index 21cb7c7265e00..4da06b441c5e8 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -7,6 +7,9 @@ cc_library(tensor SRCS tensor.cc DEPS ddim place paddle_memory device_context) cc_test(tensor_test SRCS tensor_test.cc DEPS tensor) cc_test(eigen_test SRCS eigen_test.cc DEPS tensor) +cc_library(lod_tensor SRCS lod_tensor.cc DEPS ddim place tensor) +cc_test(lod_tensor_test SRCS lod_tensor_test.cc DEPS lod_tensor) + cc_test(variable_test SRCS variable_test.cc) cc_test(scope_test SRCS scope_test.cc) diff --git a/paddle/framework/detail/tensor-inl.h b/paddle/framework/detail/tensor-inl.h index 0029b7cd933dc..e7ff09dd5c954 100644 --- a/paddle/framework/detail/tensor-inl.h +++ b/paddle/framework/detail/tensor-inl.h @@ -138,33 +138,5 @@ inline void Tensor::Resize(const DDim& dims) { dims_ = dims; } inline const DDim& Tensor::dims() const { return dims_; } -template -LODTensor LODTensor::Slice(uint32_t level, uint32_t elem_begin, - uint32_t elem_end) const { - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - PADDLE_ENFORCE(elem_begin < Elements(level), - "element begin [%d] out of range [%d]", elem_begin, - Elements(level)); - PADDLE_ENFORCE(elem_end < Elements(level), - "element end [%d] out of range [%d]", elem_begin, - Elements(level)); - // slice the lod. - auto new_lod = std::make_shared(); - auto start = lod_start_pos_->at(level)[elem_begin]; - auto end = lod_start_pos_->at(level)[elem_end]; - for (const auto& l : *lod_start_pos_) { - auto it_begin = std::find(l.begin(), l.end(), start); - auto it_end = std::find(it_begin, l.end(), end); - new_lod->emplace_back(it_begin, it_end); - } - auto new_tensor = tensor_->Slice(start, end); - - LODTensor res; - res.set_tensor(new_tensor); - res.set_lod(new_lod); - return res; -} - } // namespace framework } // namespace paddle diff --git a/paddle/framework/tensor.cc b/paddle/framework/tensor.cc index bd061870ec43f..9da4cfdef8223 100644 --- a/paddle/framework/tensor.cc +++ b/paddle/framework/tensor.cc @@ -15,16 +15,5 @@ #include "paddle/framework/tensor.h" namespace paddle { -namespace framework { - -LODTensor LODTensor::Slice(uint32_t level) const { - LODTensor res; - auto new_lod = std::make_shared(lod_start_pos_->begin() + level, - lod_start_pos_->end()); - res.set_tensor(tensor_); - res.set_lod(new_lod); - return res; -} - -} // namespace framework +namespace framework {} // namespace framework } // namespace paddle diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h index d4d8d6bfb5ffc..b1fa0454979f7 100644 --- a/paddle/framework/tensor.h +++ b/paddle/framework/tensor.h @@ -19,10 +19,6 @@ limitations under the License. */ #include #include #include -#if (!PADDLE_ONLY_CPU) -#include -#include -#endif #include "paddle/framework/ddim.h" #include "paddle/memory/memory.h" @@ -170,80 +166,6 @@ class Tensor { size_t offset_; }; -/* - * LODTensor - */ -class LODTensor { - public: -// level_t save offsets of each unit. -#ifdef PADDLE_ONLY_CPU - using level_t = std::vector; -#else - using level_t = thrust::device_vector; -#endif - // LOD stores offsets of each level of units, the largest units level first, - // then the smaller units level. Each level_t stores the offsets of units in - // Tesor. - typedef std::vector lod_t; - - explicit LODTensor() {} - - LODTensor(LODTensor&& other) - : lod_start_pos_(std::move(other.lod_start_pos_)), - tensor_(other.tensor_) {} - - /* - * Number of LODTensor's levels, each level has units of data, for example, - * in the sentence's view, article, paragraph, sentence are 3 levels. - */ - size_t Levels() const { - return lod_start_pos_.get() ? lod_start_pos_->size() : 0UL; - } - /* - * Number of elements in a level. - */ - size_t Elements(uint32_t level = 0) const { - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - return lod_start_pos_->at(level).size(); - } - - /* - * Slice of a level. - */ - LODTensor Slice(uint32_t level) const; - - /* - * Slice of elements of a level, [elem_begin: elem_end] - * NOTE low performance in slice seq_start_positions_. - */ - template - LODTensor Slice(uint32_t level, uint32_t elem_begin, uint32_t elem_end) const; - - // Slice with tensor's data shared with this. - // LODTensor LODSliceShared(int level, int elem_begin, int elem_end) const; - - // Copy other's lod_start_pos_, to share LOD info. - // NOTE the LOD info sould not be changed. - void ShareConstLODFrom(const LODTensor& other) { - lod_start_pos_ = other.lod_start_pos_; - } - // Copy other's lod_start_pos_'s content, free to mutate. - void ShareMutableLODFrom(const LODTensor& other) { - lod_start_pos_ = std::make_shared(*other.lod_start_pos_); - } - // Determine whether LODTensor has a valid LOD info. - bool HasLOD() const { return lod_start_pos_.get(); } - - void set_tensor(std::shared_ptr tensor) { tensor_ = tensor; } - void set_lod(std::shared_ptr lod) { this->lod_start_pos_ = lod; } - Tensor* tensor() { return tensor_.get(); } - - private: - std::shared_ptr lod_start_pos_; - std::shared_ptr tensor_; -}; - } // namespace framework } // namespace paddle diff --git a/paddle/framework/tensor_test.cc b/paddle/framework/tensor_test.cc index 94ca67266ae7e..d42a443c11f21 100644 --- a/paddle/framework/tensor_test.cc +++ b/paddle/framework/tensor_test.cc @@ -19,7 +19,7 @@ TEST(Tensor, Dims) { using namespace paddle::framework; using namespace paddle::platform; Tensor tt; - tt.Resize(make_ddim({2, 3, 4})); + tt.Resize({2, 3, 4}); DDim dims = tt.dims(); ASSERT_EQ(arity(dims), 3); for (int i = 0; i < 3; ++i) { @@ -260,42 +260,3 @@ TEST(Tensor, CopyFrom) { } #endif } - -namespace paddle { -namespace framework { - -class LODTensorTester : public ::testing::Test { - public: - virtual void SetUp() override { - lod_tensor = decltype(lod_tensor)(new LODTensor); - // tensor's batch_size: 30 - // 3 levels - // 0 10 20 - // 0 5 10 15 20 - // 0 2 5 7 10 12 15 20 - auto lod = std::make_shared(); - lod->emplace_back(LODTensor::level_t{0, 10, 20}); - lod->emplace_back(LODTensor::level_t{0, 5, 10, 15, 20}); - lod->emplace_back(LODTensor::level_t{0, 2, 5, 7, 10, 12, 15, 17, 20}); - - auto tensor = std::make_shared(); - DDim dims = make_ddim({20 /*batch size*/, 128 /*dim*/}); - tensor->Resize(dims); - - lod_tensor->set_tensor(tensor); - lod_tensor->set_lod(lod); - } - - protected: - std::unique_ptr lod_tensor; -}; - -TEST_F(LODTensorTester, Levels) { ASSERT_EQ(lod_tensor->Levels(), 3UL); } - -TEST_F(LODTensorTester, Elements) { - ASSERT_EQ(lod_tensor->Elements(0), 3UL); - ASSERT_EQ(lod_tensor->Elements(1), 5UL); - ASSERT_EQ(lod_tensor->Elements(2), 9UL); -} -} // namespace framework -} // namespace paddle From a1342c818b46258628d8fefa2934ed4031676de4 Mon Sep 17 00:00:00 2001 From: Superjom Date: Tue, 1 Aug 2017 19:29:57 +0800 Subject: [PATCH 04/16] add lodtensor --- paddle/framework/lod_tensor.cc | 63 +++++++++ paddle/framework/lod_tensor.h | 197 ++++++++++++++++++++++++++++ paddle/framework/lod_tensor_test.cc | 145 ++++++++++++++++++++ 3 files changed, 405 insertions(+) create mode 100644 paddle/framework/lod_tensor.cc create mode 100644 paddle/framework/lod_tensor.h create mode 100644 paddle/framework/lod_tensor_test.cc diff --git a/paddle/framework/lod_tensor.cc b/paddle/framework/lod_tensor.cc new file mode 100644 index 0000000000000..af51d59ced01f --- /dev/null +++ b/paddle/framework/lod_tensor.cc @@ -0,0 +1,63 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + + 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/framework/lod_tensor.h" + +#include + +namespace paddle { +namespace framework { + +LODTensor LODTensor::SliceShared(size_t level_begin, size_t level_end) const { + PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); + return LODTensor(tensor_, new_lod); +} + +namespace details { + +std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, + size_t level_begin, + size_t level_end) { + auto new_lod = std::make_shared(); + for (size_t i = level_begin; i < level_end; i++) { + new_lod->emplace_back(lod[i]); + } + return new_lod; +} + +std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, + size_t level, size_t elem_begin, + size_t elem_end) { + // slice the lod. + auto new_lod = std::make_shared(); + auto start = lod.at(level)[elem_begin]; + auto end = lod.at(level)[elem_end]; + + LOG(INFO) << "start: " << start << " end: " << end; + + for (auto it = lod.begin() + level; it != lod.end(); it++) { + auto it_begin = std::find(it->begin(), it->end(), start); + auto it_end = std::find(it_begin, it->end(), end); + PADDLE_ENFORCE(it_begin != it->end(), "error in parsing lod info"); + PADDLE_ENFORCE(it_end != it->end(), "error in parsing lod info"); + new_lod->emplace_back(it_begin, it_end + 1); + } + return new_lod; +} + +} // namespace details + +} // namespace framework +} // namespace paddle diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h new file mode 100644 index 0000000000000..6360de2a1c554 --- /dev/null +++ b/paddle/framework/lod_tensor.h @@ -0,0 +1,197 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + + 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 +#if (!PADDLE_ONLY_CPU) +#include +#include +#endif + +#include "paddle/framework/ddim.h" +#include "paddle/framework/tensor.h" +#include "paddle/platform/enforce.h" + +namespace paddle { +namespace framework { + +/* + * LODTensor (Level of details Tensor) + * see https://en.wikipedia.org/wiki/Level_of_details for reference. + */ +class LODTensor { + public: +// level_t save offsets of each unit. +#ifdef PADDLE_ONLY_CPU + using level_t = std::vector; +#else + using level_t = thrust::device_vector; +#endif + // LOD stores offsets of each level of units, the largest units level first, + // then the smaller units level. Each level_t stores the offsets of units in + // Tesor. + typedef std::vector lod_t; + + LODTensor() {} + LODTensor(std::shared_ptr tensor, std::shared_ptr lod) { + Reset(tensor, lod); + } + + void Reset(std::shared_ptr tensor, std::shared_ptr lod) { + tensor_ = tensor; + lod_start_pos_ = lod; + } + + /* + * Number of LODTensor's levels, each level has units of data, for example, + * in the sentence's view, article, paragraph, sentence are 3 levels. + */ + size_t Levels() const { + return lod_start_pos_.get() ? lod_start_pos_->size() : 0UL; + } + /* + * Number of elements in a level. + */ + size_t Elements(size_t level = 0) const { + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + // the last offset is the end of last element + return lod_start_pos_->at(level).size() - 1; + } + + /* + * Slice of levels[level_begin:level_end], with tensor copied. + */ + template + LODTensor SliceCopied(size_t level_begin, size_t level_end, + const platform::Place &dst_place) const; + + /* + * Slice of levels[level_begin:level_end], with tensor shared. + */ + LODTensor SliceShared(size_t level_begin, size_t level_end) const; + + /* + * Slice of elements of a level, [elem_begin: elem_end], with tensor copied. + * @note: low performance in slice lod_start_pos_. + */ + template + LODTensor SliceCopied(size_t level, size_t elem_begin, size_t elem_end, + const platform::Place &dst_place) const; + + /* + * Slice of elements of a level, [elem_begin: elem_end], with tensor shared. + * @note: low performance in slice lod_start_pos_. + */ + template + LODTensor SliceShared(size_t level, size_t elem_begin, size_t elem_end) const; + + /* + * Copy other's lod_start_pos_, to share LOD info. + * @note: the LOD info should not be changed. + */ + void ShareLOD(const LODTensor &other) { + lod_start_pos_ = other.lod_start_pos_; + } + + /* + * Copy other's lod_start_pos_'s content, free to mutate. + */ + void CopyLOD(const LODTensor &other) { + lod_start_pos_ = std::make_shared(*other.lod_start_pos_); + } + /* + * Determine whether LODTensor has a valid LOD info. + */ + bool has_lod() const { return lod_start_pos_.get(); } + std::shared_ptr const lod() const { return lod_start_pos_; } + + std::shared_ptr &tensor() const { return tensor_; } + Tensor *raw_tensor() { return tensor_.get(); } + + private: + mutable std::shared_ptr lod_start_pos_; + mutable std::shared_ptr tensor_; +}; + +namespace details { + +std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, + size_t level_begin, + size_t level_end); + +std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, + size_t level, size_t elem_begin, + size_t elem_end); +} // namespace details + +template +LODTensor LODTensor::SliceCopied(size_t level_begin, size_t level_end, + const platform::Place &dst_place) const { + PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); + auto new_tensor = std::make_shared(); + new_tensor->CopyFrom(*tensor_, dst_place); + + return LODTensor(new_tensor, new_lod); +} + +template +LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, + size_t elem_end) const { + PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + PADDLE_ENFORCE(elem_begin < Elements(level), + "element begin [%d] out of range [%d]", elem_begin, + Elements(level)); + PADDLE_ENFORCE(elem_end < Elements(level) + 1, + "element end [%d] out of range [%d]", elem_end, + Elements(level)); + + auto new_lod = + details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end); + + return LODTensor(tensor_, new_lod); +} + +template +LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, + size_t elem_end, + const platform::Place &dst_place) const { + PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + PADDLE_ENFORCE(elem_begin < Elements(level), + "element begin [%d] out of range [%d]", elem_begin, + Elements(level)); + PADDLE_ENFORCE(elem_end < Elements(level) + 1, + "element end [%d] out of range [%d]", elem_end, + Elements(level)); + + auto new_lod = + details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end); + + auto start_idx = new_lod->front().front(); + auto end_idx = new_lod->front().back() - 1 /*the next element's start*/; + auto sliced_tensor = tensor_->Slice(start_idx, end_idx); + auto new_tensor = std::make_shared(); + new_tensor->template CopyFrom(sliced_tensor, dst_place); + + return LODTensor(new_tensor, new_lod); +} + +} // namespace framework +} // namespace paddle diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc new file mode 100644 index 0000000000000..486f2e42f6c0a --- /dev/null +++ b/paddle/framework/lod_tensor_test.cc @@ -0,0 +1,145 @@ +/* + Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + 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/framework/lod_tensor.h" + +#include +#include +#include + +namespace paddle { +namespace framework { + +class LODTensorTester : public ::testing::Test { + public: + virtual void SetUp() override { + lod_tensor.reset(new LODTensor); + // tensor's batch_size: 30 + // 3 levels + // 0 10 20 + // 0 5 10 15 20 + // 0 2 5 7 10 12 15 20 + auto lod = + std::make_shared(std::vector>{ + {0, 10, 20}, {0, 5, 10, 15, 20}, {0, 2, 5, 7, 10, 12, 15, 17, 20}}); + + auto tensor = std::make_shared(); + tensor->Resize({20 /*batch size*/, 128 /*dim*/}); + // malloc memory + tensor->mutable_data(place); + + lod_tensor->Reset(tensor, lod); + } + + protected: + std::unique_ptr lod_tensor; + platform::CPUPlace place; +}; + +TEST_F(LODTensorTester, Levels) { ASSERT_EQ(lod_tensor->Levels(), 3UL); } + +TEST_F(LODTensorTester, Elements) { + ASSERT_EQ(lod_tensor->Elements(0), 2UL); + ASSERT_EQ(lod_tensor->Elements(1), 4UL); + ASSERT_EQ(lod_tensor->Elements(2), 8UL); +} + +TEST_F(LODTensorTester, SliceShared_Level) { + // slice 1 level + for (int level = 0; level < 3; level++) { + auto new_lod_tensor = lod_tensor->SliceShared(level, level + 1); + ASSERT_EQ(new_lod_tensor.Levels(), 1UL); + ASSERT_EQ(new_lod_tensor.Elements(0UL), lod_tensor->Elements(level)); + ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); + } + // slice 2 level + for (int level = 0; level < 2; level++) { + auto new_lod_tensor = lod_tensor->SliceShared(level, level + 2); + ASSERT_EQ(new_lod_tensor.Levels(), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(0), lod_tensor->Elements(level)); + ASSERT_EQ(new_lod_tensor.Elements(1), lod_tensor->Elements(level + 1)); + ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); + } +} + +TEST_F(LODTensorTester, SliceCopied_Level) { + // slice 1 level + for (int level = 0; level < 3; level++) { + auto new_lod_tensor = + lod_tensor->SliceCopied(level, level + 1, place); + ASSERT_EQ(new_lod_tensor.Levels(), 1UL); + ASSERT_EQ(new_lod_tensor.Elements(0UL), lod_tensor->Elements(level)); + // ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); + // TODO(superjom) add tensor comparation here. + } + // slice 2 level + for (int level = 0; level < 2; level++) { + auto new_lod_tensor = + lod_tensor->SliceCopied(level, level + 2, place); + ASSERT_EQ(new_lod_tensor.Levels(), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(0), lod_tensor->Elements(level)); + ASSERT_EQ(new_lod_tensor.Elements(1), lod_tensor->Elements(level + 1)); + // ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); + // TODO(superjom) add tensor comparation here. + } +} + +TEST_F(LODTensorTester, SliceShared_Element) { + size_t level = 0; + auto new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); + ASSERT_EQ(new_lod_tensor.Levels(), 3UL); + ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.Elements(2), 8UL); + ASSERT_EQ(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); + + level = 1; + new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); + ASSERT_EQ(new_lod_tensor.Levels(), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); +} + +TEST_F(LODTensorTester, SliceCopied_Element) { + size_t level = 0; + auto new_lod_tensor = lod_tensor->SliceCopied(level, 0, 2, place); + ASSERT_EQ(new_lod_tensor.Levels(), 3UL); + ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.Elements(2), 8UL); + ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); + + level = 1; + new_lod_tensor = lod_tensor->SliceCopied(level, 0, 2, place); + ASSERT_EQ(new_lod_tensor.Levels(), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); + // TODO(superjom) compare the content of these tensors +} + +TEST_F(LODTensorTester, ShareLOD) { + LODTensor new_lod_tensor; + new_lod_tensor.ShareLOD(*lod_tensor); + ASSERT_EQ(new_lod_tensor.lod(), lod_tensor->lod()); +} + +TEST_F(LODTensorTester, CopyLOD) { + LODTensor new_lod_tensor; + new_lod_tensor.CopyLOD(*lod_tensor); + ASSERT_NE(new_lod_tensor.lod(), lod_tensor->lod()); +} + +} // namespace framework +} // namespace paddle From c4e751a5879e35eee292a31a16482f8f88c5538d Mon Sep 17 00:00:00 2001 From: Superjom Date: Wed, 2 Aug 2017 17:23:44 +0800 Subject: [PATCH 05/16] add reshape of lod --- paddle/framework/lod_tensor.cc | 14 +++++++--- paddle/framework/lod_tensor.h | 41 ++++++++++++++++++++++++----- paddle/framework/lod_tensor_test.cc | 7 +++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/paddle/framework/lod_tensor.cc b/paddle/framework/lod_tensor.cc index af51d59ced01f..312c9610cf4b8 100644 --- a/paddle/framework/lod_tensor.cc +++ b/paddle/framework/lod_tensor.cc @@ -22,6 +22,8 @@ namespace framework { LODTensor LODTensor::SliceShared(size_t level_begin, size_t level_end) const { PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); + // slice levels just need to update LOD info, each level will contains the + // whole tensor_, so no need to modify tensor_. return LODTensor(tensor_, new_lod); } @@ -39,20 +41,26 @@ std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, size_t level, size_t elem_begin, - size_t elem_end) { + size_t elem_end, + bool tensor_shared) { // slice the lod. auto new_lod = std::make_shared(); auto start = lod.at(level)[elem_begin]; auto end = lod.at(level)[elem_end]; - LOG(INFO) << "start: " << start << " end: " << end; - for (auto it = lod.begin() + level; it != lod.end(); it++) { auto it_begin = std::find(it->begin(), it->end(), start); auto it_end = std::find(it_begin, it->end(), end); PADDLE_ENFORCE(it_begin != it->end(), "error in parsing lod info"); PADDLE_ENFORCE(it_end != it->end(), "error in parsing lod info"); new_lod->emplace_back(it_begin, it_end + 1); + if (!tensor_shared) { + // reset offset if tensor is copyed and sliced. + std::transform(new_lod->back().begin(), new_lod->back().end(), + new_lod->back().begin(), + [start](int v) { return v - start; }); + PADDLE_ENFORCE(new_lod->back().front() == 0, "error in slice LOD"); + } } return new_lod; } diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index 6360de2a1c554..abadc7324fc79 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -54,12 +54,24 @@ class LODTensor { lod_start_pos_ = lod; } + /* + * Get a element from LOD. + */ + size_t lod_element(size_t level, size_t elem) const { + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + PADDLE_ENFORCE(elem < Elements(level), + "element begin [%d] out of range [%d]", elem, + Elements(level)); + return lod_start_pos_->at(level)[elem]; + } + /* * Number of LODTensor's levels, each level has units of data, for example, * in the sentence's view, article, paragraph, sentence are 3 levels. */ size_t Levels() const { - return lod_start_pos_.get() ? lod_start_pos_->size() : 0UL; + return lod_start_pos_ ? lod_start_pos_->size() : 0UL; } /* * Number of elements in a level. @@ -128,13 +140,28 @@ class LODTensor { namespace details { +/* + * Slice levels from LOD. + * + * @lod: LOD to slice. + * @level_begin: level to begin slice. + * @level_end: level to end slice. + */ std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, size_t level_begin, size_t level_end); +/* + * Slice elements from a level of LOD. + * + * @lod: LOD to slice. + * @level: which level to slice. + * @elem_begin: element's index to begin slice. + * @elem_end: element's index to end slice. + */ std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, size_t level, size_t elem_begin, - size_t elem_end); + size_t elem_end, bool tensor_shared); } // namespace details template @@ -161,9 +188,11 @@ LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, "element end [%d] out of range [%d]", elem_end, Elements(level)); - auto new_lod = - details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end); + auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, + true /*tensor_shared*/); + // slice elements just need to update LOD info, because offsets are not + // changed, so the original tensor_ can be reused. return LODTensor(tensor_, new_lod); } @@ -181,8 +210,8 @@ LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, "element end [%d] out of range [%d]", elem_end, Elements(level)); - auto new_lod = - details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end); + auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, + false /*tensor_shared*/); auto start_idx = new_lod->front().front(); auto end_idx = new_lod->front().back() - 1 /*the next element's start*/; diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 486f2e42f6c0a..6b82b365d1fcb 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -126,6 +126,13 @@ TEST_F(LODTensorTester, SliceCopied_Element) { ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); + + new_lod_tensor = lod_tensor->SliceCopied(level, 1, 3, place); + ASSERT_EQ(new_lod_tensor.lod_element(0, 0), 0UL); + ASSERT_EQ(new_lod_tensor.lod_element(0, 1), 5UL); + ASSERT_EQ(new_lod_tensor.lod_element(1, 0), 0UL); + ASSERT_EQ(new_lod_tensor.lod_element(1, 1), 5UL); + // TODO(superjom) compare the content of these tensors } From 6a0953c17f32ecfb107470d7eda0d7d84d0968aa Mon Sep 17 00:00:00 2001 From: Superjom Date: Wed, 2 Aug 2017 17:26:07 +0800 Subject: [PATCH 06/16] recover .clang-format --- paddle/framework/.clang-format | 3 --- 1 file changed, 3 deletions(-) diff --git a/paddle/framework/.clang-format b/paddle/framework/.clang-format index 1f096f94d9292..29282dc87e2c4 100644 --- a/paddle/framework/.clang-format +++ b/paddle/framework/.clang-format @@ -2,7 +2,4 @@ Language: Cpp BasedOnStyle: Google Standard: Cpp11 -AlignTrailingComments: true -#FixNamespaceComments: true -SpacesBeforeTrailingComments: 2 ... From 76a9c8bf13355d9b73a0848e20038137a21758d2 Mon Sep 17 00:00:00 2001 From: Superjom Date: Thu, 3 Aug 2017 13:09:07 +0800 Subject: [PATCH 07/16] fix test lod --- paddle/framework/lod_tensor_test.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 6b82b365d1fcb..0a0d474c1309b 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -29,9 +29,10 @@ class LODTensorTester : public ::testing::Test { // 0 10 20 // 0 5 10 15 20 // 0 2 5 7 10 12 15 20 - auto lod = - std::make_shared(std::vector>{ - {0, 10, 20}, {0, 5, 10, 15, 20}, {0, 2, 5, 7, 10, 12, 15, 17, 20}}); + auto lod = std::make_shared(); + lod->emplace_back(LODTensor::level_t{0, 10, 20}); + lod->emplace_back(LODTensor::level_t{0, 5, 10, 15, 20}); + lod->emplace_back(LODTensor::level_t{0, 2, 5, 7, 10, 12, 15, 17, 20}); auto tensor = std::make_shared(); tensor->Resize({20 /*batch size*/, 128 /*dim*/}); From 9cd80338727f18c047b06621f7985173b1122506 Mon Sep 17 00:00:00 2001 From: Superjom Date: Thu, 3 Aug 2017 16:59:29 +0800 Subject: [PATCH 08/16] add details --- paddle/framework/CMakeLists.txt | 2 +- paddle/framework/lod_tensor.cc | 56 ++++++++++------------------- paddle/framework/lod_tensor.h | 54 ++++------------------------ paddle/framework/lod_tensor_test.cc | 16 +++++++-- 4 files changed, 38 insertions(+), 90 deletions(-) diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index 0aba1509ea6d2..3dd3e9143e222 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -7,7 +7,7 @@ cc_library(tensor SRCS tensor.cc DEPS ddim place paddle_memory device_context) cc_test(tensor_test SRCS tensor_test.cc DEPS tensor) cc_test(eigen_test SRCS eigen_test.cc DEPS tensor) -cc_library(lod_tensor SRCS lod_tensor.cc DEPS ddim place tensor) +cc_library(lod_tensor SRCS lod_tensor.cc details/lod_tensor.cc DEPS ddim place tensor) cc_test(lod_tensor_test SRCS lod_tensor_test.cc DEPS lod_tensor) cc_test(variable_test SRCS variable_test.cc) diff --git a/paddle/framework/lod_tensor.cc b/paddle/framework/lod_tensor.cc index 312c9610cf4b8..a9d931f296b63 100644 --- a/paddle/framework/lod_tensor.cc +++ b/paddle/framework/lod_tensor.cc @@ -27,45 +27,25 @@ LODTensor LODTensor::SliceShared(size_t level_begin, size_t level_end) const { return LODTensor(tensor_, new_lod); } -namespace details { - -std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, - size_t level_begin, - size_t level_end) { - auto new_lod = std::make_shared(); - for (size_t i = level_begin; i < level_end; i++) { - new_lod->emplace_back(lod[i]); - } - return new_lod; -} - -std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, - size_t level, size_t elem_begin, - size_t elem_end, - bool tensor_shared) { - // slice the lod. - auto new_lod = std::make_shared(); - auto start = lod.at(level)[elem_begin]; - auto end = lod.at(level)[elem_end]; - - for (auto it = lod.begin() + level; it != lod.end(); it++) { - auto it_begin = std::find(it->begin(), it->end(), start); - auto it_end = std::find(it_begin, it->end(), end); - PADDLE_ENFORCE(it_begin != it->end(), "error in parsing lod info"); - PADDLE_ENFORCE(it_end != it->end(), "error in parsing lod info"); - new_lod->emplace_back(it_begin, it_end + 1); - if (!tensor_shared) { - // reset offset if tensor is copyed and sliced. - std::transform(new_lod->back().begin(), new_lod->back().end(), - new_lod->back().begin(), - [start](int v) { return v - start; }); - PADDLE_ENFORCE(new_lod->back().front() == 0, "error in slice LOD"); - } - } - return new_lod; +LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, + size_t elem_end) const { + PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, + Levels()); + PADDLE_ENFORCE(elem_begin < Elements(level), + "element begin [%d] out of range [%d]", elem_begin, + Elements(level)); + PADDLE_ENFORCE(elem_end < Elements(level) + 1, + "element end [%d] out of range [%d]", elem_end, + Elements(level)); + + auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, + true /*tensor_shared*/); + + // slice elements just need to update LOD info, because offsets are not + // changed, so the original tensor_ can be reused. + return LODTensor(tensor_, new_lod); } -} // namespace details - } // namespace framework } // namespace paddle diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index abadc7324fc79..4b92a01e2721a 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -107,7 +107,6 @@ class LODTensor { * Slice of elements of a level, [elem_begin: elem_end], with tensor shared. * @note: low performance in slice lod_start_pos_. */ - template LODTensor SliceShared(size_t level, size_t elem_begin, size_t elem_end) const; /* @@ -138,32 +137,13 @@ class LODTensor { mutable std::shared_ptr tensor_; }; -namespace details { +} // namespace framework +} // namespace paddle -/* - * Slice levels from LOD. - * - * @lod: LOD to slice. - * @level_begin: level to begin slice. - * @level_end: level to end slice. - */ -std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, - size_t level_begin, - size_t level_end); - -/* - * Slice elements from a level of LOD. - * - * @lod: LOD to slice. - * @level: which level to slice. - * @elem_begin: element's index to begin slice. - * @elem_end: element's index to end slice. - */ -std::shared_ptr SliceLOD(const LODTensor::lod_t &lod, - size_t level, size_t elem_begin, - size_t elem_end, bool tensor_shared); -} // namespace details +#include "paddle/framework/details/lod_tensor.h" +namespace paddle { +namespace framework { template LODTensor LODTensor::SliceCopied(size_t level_begin, size_t level_end, const platform::Place &dst_place) const { @@ -175,27 +155,6 @@ LODTensor LODTensor::SliceCopied(size_t level_begin, size_t level_end, return LODTensor(new_tensor, new_lod); } -template -LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, - size_t elem_end) const { - PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - PADDLE_ENFORCE(elem_begin < Elements(level), - "element begin [%d] out of range [%d]", elem_begin, - Elements(level)); - PADDLE_ENFORCE(elem_end < Elements(level) + 1, - "element end [%d] out of range [%d]", elem_end, - Elements(level)); - - auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, - true /*tensor_shared*/); - - // slice elements just need to update LOD info, because offsets are not - // changed, so the original tensor_ can be reused. - return LODTensor(tensor_, new_lod); -} - template LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, size_t elem_end, @@ -217,10 +176,9 @@ LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, auto end_idx = new_lod->front().back() - 1 /*the next element's start*/; auto sliced_tensor = tensor_->Slice(start_idx, end_idx); auto new_tensor = std::make_shared(); - new_tensor->template CopyFrom(sliced_tensor, dst_place); + new_tensor->CopyFrom(sliced_tensor, dst_place); return LODTensor(new_tensor, new_lod); } - } // namespace framework } // namespace paddle diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 0a0d474c1309b..8603ed6532daa 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -97,7 +97,7 @@ TEST_F(LODTensorTester, SliceCopied_Level) { TEST_F(LODTensorTester, SliceShared_Element) { size_t level = 0; - auto new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); + auto new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); ASSERT_EQ(new_lod_tensor.Levels(), 3UL); ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); @@ -105,7 +105,7 @@ TEST_F(LODTensorTester, SliceShared_Element) { ASSERT_EQ(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); level = 1; - new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); + new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); ASSERT_EQ(new_lod_tensor.Levels(), 2UL); ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); @@ -128,11 +128,21 @@ TEST_F(LODTensorTester, SliceCopied_Element) { ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); + level = 1; + // LOD is + // 0 5 10 + // 0 2 5 7 10 new_lod_tensor = lod_tensor->SliceCopied(level, 1, 3, place); + ASSERT_EQ(new_lod_tensor.Levels(), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); + ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.lod_element(0, 0), 0UL); ASSERT_EQ(new_lod_tensor.lod_element(0, 1), 5UL); ASSERT_EQ(new_lod_tensor.lod_element(1, 0), 0UL); - ASSERT_EQ(new_lod_tensor.lod_element(1, 1), 5UL); + ASSERT_EQ(new_lod_tensor.lod_element(1, 1), 2UL); + ASSERT_EQ(new_lod_tensor.lod_element(1, 2), 5UL); + ASSERT_EQ(new_lod_tensor.lod_element(1, 3), 7UL); // TODO(superjom) compare the content of these tensors } From 71108f85f6a7fec91a9f11da9c558041ee2833a1 Mon Sep 17 00:00:00 2001 From: Superjom Date: Thu, 3 Aug 2017 20:43:41 +0800 Subject: [PATCH 09/16] rename Elements/Levels --- paddle/framework/lod_tensor.cc | 16 +++--- paddle/framework/lod_tensor.h | 85 ++++++++--------------------- paddle/framework/lod_tensor_test.cc | 74 +++++++++++++------------ 3 files changed, 69 insertions(+), 106 deletions(-) diff --git a/paddle/framework/lod_tensor.cc b/paddle/framework/lod_tensor.cc index a9d931f296b63..70045dbf7afd0 100644 --- a/paddle/framework/lod_tensor.cc +++ b/paddle/framework/lod_tensor.cc @@ -20,7 +20,7 @@ namespace paddle { namespace framework { LODTensor LODTensor::SliceShared(size_t level_begin, size_t level_end) const { - PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(HasLOD(), "has no LOD info, can't be sliced."); auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); // slice levels just need to update LOD info, each level will contains the // whole tensor_, so no need to modify tensor_. @@ -29,15 +29,15 @@ LODTensor LODTensor::SliceShared(size_t level_begin, size_t level_end) const { LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, size_t elem_end) const { - PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - PADDLE_ENFORCE(elem_begin < Elements(level), + PADDLE_ENFORCE(HasLOD(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(level < NumLevels(), "level [%d] out of range [%d]", level, + NumLevels()); + PADDLE_ENFORCE(elem_begin < NumElements(level), "element begin [%d] out of range [%d]", elem_begin, - Elements(level)); - PADDLE_ENFORCE(elem_end < Elements(level) + 1, + NumElements(level)); + PADDLE_ENFORCE(elem_end < NumElements(level) + 1, "element end [%d] out of range [%d]", elem_end, - Elements(level)); + NumElements(level)); auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, true /*tensor_shared*/); diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index 4b92a01e2721a..bd8b03b259958 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -33,23 +33,23 @@ namespace framework { */ class LODTensor { public: -// level_t save offsets of each unit. +// Level save offsets of each unit. #ifdef PADDLE_ONLY_CPU - using level_t = std::vector; + using Level = std::vector; #else - using level_t = thrust::device_vector; + using Level = thrust::device_vector; #endif // LOD stores offsets of each level of units, the largest units level first, - // then the smaller units level. Each level_t stores the offsets of units in + // then the smaller units level. Each Level stores the offsets of units in // Tesor. - typedef std::vector lod_t; + typedef std::vector LOD; LODTensor() {} - LODTensor(std::shared_ptr tensor, std::shared_ptr lod) { + LODTensor(std::shared_ptr tensor, std::shared_ptr lod) { Reset(tensor, lod); } - void Reset(std::shared_ptr tensor, std::shared_ptr lod) { + void Reset(std::shared_ptr tensor, std::shared_ptr lod) { tensor_ = tensor; lod_start_pos_ = lod; } @@ -58,27 +58,27 @@ class LODTensor { * Get a element from LOD. */ size_t lod_element(size_t level, size_t elem) const { - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - PADDLE_ENFORCE(elem < Elements(level), + PADDLE_ENFORCE(level < NumLevels(), "level [%d] out of range [%d]", level, + NumLevels()); + PADDLE_ENFORCE(elem < NumElements(level), "element begin [%d] out of range [%d]", elem, - Elements(level)); - return lod_start_pos_->at(level)[elem]; + NumElements(level)); + return (*lod_start_pos_)[level][elem]; } /* * Number of LODTensor's levels, each level has units of data, for example, * in the sentence's view, article, paragraph, sentence are 3 levels. */ - size_t Levels() const { + size_t NumLevels() const { return lod_start_pos_ ? lod_start_pos_->size() : 0UL; } /* * Number of elements in a level. */ - size_t Elements(size_t level = 0) const { - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); + size_t NumElements(size_t level = 0) const { + PADDLE_ENFORCE(level < NumLevels(), "level [%d] out of range [%d]", level, + NumLevels()); // the last offset is the end of last element return lod_start_pos_->at(level).size() - 1; } @@ -121,64 +121,25 @@ class LODTensor { * Copy other's lod_start_pos_'s content, free to mutate. */ void CopyLOD(const LODTensor &other) { - lod_start_pos_ = std::make_shared(*other.lod_start_pos_); + lod_start_pos_ = std::make_shared(*other.lod_start_pos_); } /* * Determine whether LODTensor has a valid LOD info. */ - bool has_lod() const { return lod_start_pos_.get(); } - std::shared_ptr const lod() const { return lod_start_pos_; } + bool HasLOD() const { return bool(lod_start_pos_); } + std::shared_ptr lod() const { + return std::const_pointer_cast(lod_start_pos_); + } std::shared_ptr &tensor() const { return tensor_; } Tensor *raw_tensor() { return tensor_.get(); } private: - mutable std::shared_ptr lod_start_pos_; + mutable std::shared_ptr lod_start_pos_; mutable std::shared_ptr tensor_; }; } // namespace framework } // namespace paddle -#include "paddle/framework/details/lod_tensor.h" - -namespace paddle { -namespace framework { -template -LODTensor LODTensor::SliceCopied(size_t level_begin, size_t level_end, - const platform::Place &dst_place) const { - PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); - auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); - auto new_tensor = std::make_shared(); - new_tensor->CopyFrom(*tensor_, dst_place); - - return LODTensor(new_tensor, new_lod); -} - -template -LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, - size_t elem_end, - const platform::Place &dst_place) const { - PADDLE_ENFORCE(has_lod(), "has no LOD info, can't be sliced."); - PADDLE_ENFORCE(level < Levels(), "level [%d] out of range [%d]", level, - Levels()); - PADDLE_ENFORCE(elem_begin < Elements(level), - "element begin [%d] out of range [%d]", elem_begin, - Elements(level)); - PADDLE_ENFORCE(elem_end < Elements(level) + 1, - "element end [%d] out of range [%d]", elem_end, - Elements(level)); - - auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, - false /*tensor_shared*/); - - auto start_idx = new_lod->front().front(); - auto end_idx = new_lod->front().back() - 1 /*the next element's start*/; - auto sliced_tensor = tensor_->Slice(start_idx, end_idx); - auto new_tensor = std::make_shared(); - new_tensor->CopyFrom(sliced_tensor, dst_place); - - return LODTensor(new_tensor, new_lod); -} -} // namespace framework -} // namespace paddle +#include "paddle/framework/lod_tensor_impl.h" diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 8603ed6532daa..809b31a273f06 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -29,10 +29,10 @@ class LODTensorTester : public ::testing::Test { // 0 10 20 // 0 5 10 15 20 // 0 2 5 7 10 12 15 20 - auto lod = std::make_shared(); - lod->emplace_back(LODTensor::level_t{0, 10, 20}); - lod->emplace_back(LODTensor::level_t{0, 5, 10, 15, 20}); - lod->emplace_back(LODTensor::level_t{0, 2, 5, 7, 10, 12, 15, 17, 20}); + auto lod = std::make_shared(); + lod->emplace_back(LODTensor::Level{0, 10, 20}); + lod->emplace_back(LODTensor::Level{0, 5, 10, 15, 20}); + lod->emplace_back(LODTensor::Level{0, 2, 5, 7, 10, 12, 15, 17, 20}); auto tensor = std::make_shared(); tensor->Resize({20 /*batch size*/, 128 /*dim*/}); @@ -47,28 +47,29 @@ class LODTensorTester : public ::testing::Test { platform::CPUPlace place; }; -TEST_F(LODTensorTester, Levels) { ASSERT_EQ(lod_tensor->Levels(), 3UL); } +TEST_F(LODTensorTester, NumLevels) { ASSERT_EQ(lod_tensor->NumLevels(), 3UL); } -TEST_F(LODTensorTester, Elements) { - ASSERT_EQ(lod_tensor->Elements(0), 2UL); - ASSERT_EQ(lod_tensor->Elements(1), 4UL); - ASSERT_EQ(lod_tensor->Elements(2), 8UL); +TEST_F(LODTensorTester, NumElements) { + ASSERT_EQ(lod_tensor->NumElements(0), 2UL); + ASSERT_EQ(lod_tensor->NumElements(1), 4UL); + ASSERT_EQ(lod_tensor->NumElements(2), 8UL); } TEST_F(LODTensorTester, SliceShared_Level) { // slice 1 level for (int level = 0; level < 3; level++) { auto new_lod_tensor = lod_tensor->SliceShared(level, level + 1); - ASSERT_EQ(new_lod_tensor.Levels(), 1UL); - ASSERT_EQ(new_lod_tensor.Elements(0UL), lod_tensor->Elements(level)); + ASSERT_EQ(new_lod_tensor.NumLevels(), 1UL); + ASSERT_EQ(new_lod_tensor.NumElements(0UL), lod_tensor->NumElements(level)); ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); } // slice 2 level for (int level = 0; level < 2; level++) { auto new_lod_tensor = lod_tensor->SliceShared(level, level + 2); - ASSERT_EQ(new_lod_tensor.Levels(), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(0), lod_tensor->Elements(level)); - ASSERT_EQ(new_lod_tensor.Elements(1), lod_tensor->Elements(level + 1)); + ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), lod_tensor->NumElements(level)); + ASSERT_EQ(new_lod_tensor.NumElements(1), + lod_tensor->NumElements(level + 1)); ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); } } @@ -78,8 +79,8 @@ TEST_F(LODTensorTester, SliceCopied_Level) { for (int level = 0; level < 3; level++) { auto new_lod_tensor = lod_tensor->SliceCopied(level, level + 1, place); - ASSERT_EQ(new_lod_tensor.Levels(), 1UL); - ASSERT_EQ(new_lod_tensor.Elements(0UL), lod_tensor->Elements(level)); + ASSERT_EQ(new_lod_tensor.NumLevels(), 1UL); + ASSERT_EQ(new_lod_tensor.NumElements(0UL), lod_tensor->NumElements(level)); // ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); // TODO(superjom) add tensor comparation here. } @@ -87,9 +88,10 @@ TEST_F(LODTensorTester, SliceCopied_Level) { for (int level = 0; level < 2; level++) { auto new_lod_tensor = lod_tensor->SliceCopied(level, level + 2, place); - ASSERT_EQ(new_lod_tensor.Levels(), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(0), lod_tensor->Elements(level)); - ASSERT_EQ(new_lod_tensor.Elements(1), lod_tensor->Elements(level + 1)); + ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), lod_tensor->NumElements(level)); + ASSERT_EQ(new_lod_tensor.NumElements(1), + lod_tensor->NumElements(level + 1)); // ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); // TODO(superjom) add tensor comparation here. } @@ -98,34 +100,34 @@ TEST_F(LODTensorTester, SliceCopied_Level) { TEST_F(LODTensorTester, SliceShared_Element) { size_t level = 0; auto new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); - ASSERT_EQ(new_lod_tensor.Levels(), 3UL); - ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); - ASSERT_EQ(new_lod_tensor.Elements(2), 8UL); + ASSERT_EQ(new_lod_tensor.NumLevels(), 3UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(1), 4UL); + ASSERT_EQ(new_lod_tensor.NumElements(2), 8UL); ASSERT_EQ(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); level = 1; new_lod_tensor = lod_tensor->SliceShared(level, 0, 2); - ASSERT_EQ(new_lod_tensor.Levels(), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(1), 4UL); ASSERT_EQ(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); } TEST_F(LODTensorTester, SliceCopied_Element) { size_t level = 0; auto new_lod_tensor = lod_tensor->SliceCopied(level, 0, 2, place); - ASSERT_EQ(new_lod_tensor.Levels(), 3UL); - ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); - ASSERT_EQ(new_lod_tensor.Elements(2), 8UL); + ASSERT_EQ(new_lod_tensor.NumLevels(), 3UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(1), 4UL); + ASSERT_EQ(new_lod_tensor.NumElements(2), 8UL); ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); level = 1; new_lod_tensor = lod_tensor->SliceCopied(level, 0, 2, place); - ASSERT_EQ(new_lod_tensor.Levels(), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(1), 4UL); ASSERT_NE(new_lod_tensor.raw_tensor(), lod_tensor->raw_tensor()); level = 1; @@ -133,9 +135,9 @@ TEST_F(LODTensorTester, SliceCopied_Element) { // 0 5 10 // 0 2 5 7 10 new_lod_tensor = lod_tensor->SliceCopied(level, 1, 3, place); - ASSERT_EQ(new_lod_tensor.Levels(), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(0), 2UL); - ASSERT_EQ(new_lod_tensor.Elements(1), 4UL); + ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(0), 2UL); + ASSERT_EQ(new_lod_tensor.NumElements(1), 4UL); ASSERT_EQ(new_lod_tensor.lod_element(0, 0), 0UL); ASSERT_EQ(new_lod_tensor.lod_element(0, 1), 5UL); From 8e970b3575bfe33bcd834a8b96cd4a69b0f44b88 Mon Sep 17 00:00:00 2001 From: Superjom Date: Fri, 4 Aug 2017 11:03:07 +0800 Subject: [PATCH 10/16] size_t and vector reserve --- paddle/framework/lod_tensor_test.cc | 8 ++++---- paddle/framework/tensor.cc | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 809b31a273f06..43135020f94f1 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -57,14 +57,14 @@ TEST_F(LODTensorTester, NumElements) { TEST_F(LODTensorTester, SliceShared_Level) { // slice 1 level - for (int level = 0; level < 3; level++) { + for (size_t level = 0; level < 3UL; ++level) { auto new_lod_tensor = lod_tensor->SliceShared(level, level + 1); ASSERT_EQ(new_lod_tensor.NumLevels(), 1UL); ASSERT_EQ(new_lod_tensor.NumElements(0UL), lod_tensor->NumElements(level)); ASSERT_EQ(new_lod_tensor.tensor(), lod_tensor->tensor()); } // slice 2 level - for (int level = 0; level < 2; level++) { + for (size_t level = 0; level < 2UL; ++level) { auto new_lod_tensor = lod_tensor->SliceShared(level, level + 2); ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); ASSERT_EQ(new_lod_tensor.NumElements(0), lod_tensor->NumElements(level)); @@ -76,7 +76,7 @@ TEST_F(LODTensorTester, SliceShared_Level) { TEST_F(LODTensorTester, SliceCopied_Level) { // slice 1 level - for (int level = 0; level < 3; level++) { + for (size_t level = 0; level < 3UL; ++level) { auto new_lod_tensor = lod_tensor->SliceCopied(level, level + 1, place); ASSERT_EQ(new_lod_tensor.NumLevels(), 1UL); @@ -85,7 +85,7 @@ TEST_F(LODTensorTester, SliceCopied_Level) { // TODO(superjom) add tensor comparation here. } // slice 2 level - for (int level = 0; level < 2; level++) { + for (size_t level = 0; level < 2UL; ++level) { auto new_lod_tensor = lod_tensor->SliceCopied(level, level + 2, place); ASSERT_EQ(new_lod_tensor.NumLevels(), 2UL); diff --git a/paddle/framework/tensor.cc b/paddle/framework/tensor.cc index 9da4cfdef8223..ea7b2a1f7b17d 100644 --- a/paddle/framework/tensor.cc +++ b/paddle/framework/tensor.cc @@ -15,5 +15,5 @@ #include "paddle/framework/tensor.h" namespace paddle { -namespace framework {} // namespace framework +namespace framework {} } // namespace paddle From df75fe2ee5bc3dbf1a3c5d27bf633eea48d68440 Mon Sep 17 00:00:00 2001 From: Superjom Date: Fri, 4 Aug 2017 11:57:37 +0800 Subject: [PATCH 11/16] add details --- paddle/framework/details/lod_tensor.cc | 62 ++++++++++++++++++++++++++ paddle/framework/details/lod_tensor.h | 46 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 paddle/framework/details/lod_tensor.cc create mode 100644 paddle/framework/details/lod_tensor.h diff --git a/paddle/framework/details/lod_tensor.cc b/paddle/framework/details/lod_tensor.cc new file mode 100644 index 0000000000000..9ad3979e5b511 --- /dev/null +++ b/paddle/framework/details/lod_tensor.cc @@ -0,0 +1,62 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + + 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/framework/lod_tensor.h" + +#include + +namespace paddle { +namespace framework { +namespace details { + +using LOD = LODTensor::LOD; + +std::shared_ptr SliceLOD(const LOD &lod, size_t level_begin, + size_t level_end) { + auto new_lod = std::make_shared(); + new_lod->reserve(level_end - level_begin); + for (size_t i = level_begin; i < level_end; i++) { + new_lod->emplace_back(lod[i]); + } + return new_lod; +} + +std::shared_ptr SliceLOD(const LOD &lod, size_t level, size_t elem_begin, + size_t elem_end, bool tensor_shared) { + // slice the lod. + auto new_lod = std::make_shared(); + new_lod->reserve(lod.size() - level); + auto start = lod.at(level)[elem_begin]; + auto end = lod.at(level)[elem_end]; + + for (auto it = lod.begin() + level; it != lod.end(); it++) { + auto it_begin = std::find(it->begin(), it->end(), start); + auto it_end = std::find(it_begin, it->end(), end); + PADDLE_ENFORCE(it_begin != it->end(), "error in parsing lod info"); + PADDLE_ENFORCE(it_end != it->end(), "error in parsing lod info"); + new_lod->emplace_back(it_begin, it_end + 1); + if (!tensor_shared) { + // reset offset if tensor is copyed and sliced. + std::transform(new_lod->back().begin(), new_lod->back().end(), + new_lod->back().begin(), + [start](int v) { return v - start; }); + PADDLE_ENFORCE(new_lod->back().front() == 0, "error in slice LOD"); + } + } + return new_lod; +} + +} // namespace details +} // namespace framework +} // namespace paddle diff --git a/paddle/framework/details/lod_tensor.h b/paddle/framework/details/lod_tensor.h new file mode 100644 index 0000000000000..9a6a6cd2ea41f --- /dev/null +++ b/paddle/framework/details/lod_tensor.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + + 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 + +namespace paddle { +namespace framework { +namespace details { + +/* + * Slice levels from LOD. + * + * @lod: LOD to slice. + * @level_begin: level to begin slice. + * @level_end: level to end slice. + */ +std::shared_ptr SliceLOD(const LODTensor::LOD &lod, + size_t level_begin, size_t level_end); + +/* + * Slice elements from a level of LOD. + * + * @lod: LOD to slice. + * @level: which level to slice. + * @elem_begin: element's index to begin slice. + * @elem_end: element's index to end slice. + */ +std::shared_ptr SliceLOD(const LODTensor::LOD &lod, + size_t level, size_t elem_begin, + size_t elem_end, bool tensor_shared); +} // namespace details +} // namespace framework +} // namespace paddle From 14858cdc22d8ae3bfb9deaea1d5ebdb58b0e4ef7 Mon Sep 17 00:00:00 2001 From: Superjom Date: Fri, 4 Aug 2017 17:48:11 +0800 Subject: [PATCH 12/16] add const& std::shared_ptr --- paddle/framework/lod_tensor.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index bd8b03b259958..03379207ee6cb 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -45,11 +45,13 @@ class LODTensor { typedef std::vector LOD; LODTensor() {} - LODTensor(std::shared_ptr tensor, std::shared_ptr lod) { + LODTensor(const std::shared_ptr &tensor, + const std::shared_ptr &lod) { Reset(tensor, lod); } - void Reset(std::shared_ptr tensor, std::shared_ptr lod) { + void Reset(const std::shared_ptr &tensor, + const std::shared_ptr &lod) { tensor_ = tensor; lod_start_pos_ = lod; } @@ -131,12 +133,12 @@ class LODTensor { return std::const_pointer_cast(lod_start_pos_); } - std::shared_ptr &tensor() const { return tensor_; } + std::shared_ptr &tensor() { return tensor_; } Tensor *raw_tensor() { return tensor_.get(); } private: - mutable std::shared_ptr lod_start_pos_; - mutable std::shared_ptr tensor_; + std::shared_ptr lod_start_pos_; + std::shared_ptr tensor_; }; } // namespace framework From 9319c1e62e8eacef7b1f019088e098a528f75b57 Mon Sep 17 00:00:00 2001 From: Superjom Date: Sat, 5 Aug 2017 17:31:29 +0800 Subject: [PATCH 13/16] add lod_tensor_impl.h --- paddle/framework/lod_tensor_impl.h | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 paddle/framework/lod_tensor_impl.h diff --git a/paddle/framework/lod_tensor_impl.h b/paddle/framework/lod_tensor_impl.h new file mode 100644 index 0000000000000..0eb6469aea3ae --- /dev/null +++ b/paddle/framework/lod_tensor_impl.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + + 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 "paddle/framework/details/lod_tensor.h" + +namespace paddle { +namespace framework { + +template +LODTensor LODTensor::SliceCopied(size_t level_begin, size_t level_end, + const platform::Place &dst_place) const { + PADDLE_ENFORCE(HasLOD(), "has no LOD info, can't be sliced."); + auto new_lod = details::SliceLOD(*lod_start_pos_, level_begin, level_end); + auto new_tensor = std::make_shared(); + new_tensor->CopyFrom(*tensor_, dst_place); + + return LODTensor(new_tensor, new_lod); +} + +template +LODTensor LODTensor::SliceCopied(size_t level, size_t elem_begin, + size_t elem_end, + const platform::Place &dst_place) const { + PADDLE_ENFORCE(HasLOD(), "has no LOD info, can't be sliced."); + PADDLE_ENFORCE(level < NumLevels(), "level [%d] out of range [%d]", level, + NumLevels()); + PADDLE_ENFORCE(elem_begin < NumElements(level), + "element begin [%d] out of range [%d]", elem_begin, + NumElements(level)); + PADDLE_ENFORCE(elem_end < NumElements(level) + 1, + "element end [%d] out of range [%d]", elem_end, + NumElements(level)); + + auto new_lod = details::SliceLOD(*lod_start_pos_, level, elem_begin, elem_end, + false /*tensor_shared*/); + + auto start_idx = new_lod->front().front(); + auto end_idx = new_lod->front().back() - 1 /*the next element's start*/; + auto sliced_tensor = tensor_->Slice(start_idx, end_idx); + auto new_tensor = std::make_shared(); + new_tensor->CopyFrom(sliced_tensor, dst_place); + + return LODTensor(new_tensor, new_lod); +} + +} // namespace framework +} // namespace paddle From adfe84d86e6d49700ea6116e7685f7cb031d4d1c Mon Sep 17 00:00:00 2001 From: Superjom Date: Tue, 8 Aug 2017 20:58:52 +0800 Subject: [PATCH 14/16] fix compile error --- paddle/framework/lod_tensor_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index 43135020f94f1..be1c7bfc48feb 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -30,9 +30,9 @@ class LODTensorTester : public ::testing::Test { // 0 5 10 15 20 // 0 2 5 7 10 12 15 20 auto lod = std::make_shared(); - lod->emplace_back(LODTensor::Level{0, 10, 20}); - lod->emplace_back(LODTensor::Level{0, 5, 10, 15, 20}); - lod->emplace_back(LODTensor::Level{0, 2, 5, 7, 10, 12, 15, 17, 20}); + lod->push_back(LODTensor::Level{0, 10, 20}); + lod->push_back(LODTensor::Level{0, 5, 10, 15, 20}); + lod->push_back(LODTensor::Level{0, 2, 5, 7, 10, 12, 15, 17, 20}); auto tensor = std::make_shared(); tensor->Resize({20 /*batch size*/, 128 /*dim*/}); From 180499c6b0c6bddda058012cadb8e9fdcb7881a9 Mon Sep 17 00:00:00 2001 From: Superjom Date: Tue, 8 Aug 2017 21:22:08 +0800 Subject: [PATCH 15/16] fix thrust vector --- paddle/framework/lod_tensor_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paddle/framework/lod_tensor_test.cc b/paddle/framework/lod_tensor_test.cc index be1c7bfc48feb..511716375e81e 100644 --- a/paddle/framework/lod_tensor_test.cc +++ b/paddle/framework/lod_tensor_test.cc @@ -30,9 +30,9 @@ class LODTensorTester : public ::testing::Test { // 0 5 10 15 20 // 0 2 5 7 10 12 15 20 auto lod = std::make_shared(); - lod->push_back(LODTensor::Level{0, 10, 20}); - lod->push_back(LODTensor::Level{0, 5, 10, 15, 20}); - lod->push_back(LODTensor::Level{0, 2, 5, 7, 10, 12, 15, 17, 20}); + lod->push_back(std::vector{0, 10, 20}); + lod->push_back(std::vector{0, 5, 10, 15, 20}); + lod->push_back(std::vector{0, 2, 5, 7, 10, 12, 15, 17, 20}); auto tensor = std::make_shared(); tensor->Resize({20 /*batch size*/, 128 /*dim*/}); From 98a3de59a84bd27999fc33d8e61a343e03277f22 Mon Sep 17 00:00:00 2001 From: Superjom Date: Wed, 9 Aug 2017 07:18:43 +0800 Subject: [PATCH 16/16] remove a shared_ptr --- paddle/framework/lod_tensor.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index 03379207ee6cb..4933479b10969 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -129,9 +129,7 @@ class LODTensor { * Determine whether LODTensor has a valid LOD info. */ bool HasLOD() const { return bool(lod_start_pos_); } - std::shared_ptr lod() const { - return std::const_pointer_cast(lod_start_pos_); - } + LOD *lod() const { return lod_start_pos_.get(); } std::shared_ptr &tensor() { return tensor_; } Tensor *raw_tensor() { return tensor_.get(); }