-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LODTensor (Level of details, or Level of sequences Tensor). #3109
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late review.
paddle/framework/tensor_test.cc
Outdated
class LODTensorTester : public ::testing::Test { | ||
public: | ||
virtual void SetUp() override { | ||
lod_tensor = decltype(lod_tensor)(new LODTensor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe lod_tensor.reset(new LODTensor); could be simpler?
paddle/framework/tensor.h
Outdated
// Tesor. | ||
typedef std::vector<level_t> lod_t; | ||
|
||
explicit LODTensor() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explicit
is not necessary.
paddle/framework/tensor.h
Outdated
|
||
explicit LODTensor() {} | ||
|
||
LODTensor(LODTensor&& other) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we move an LODTensor
?
Maybe LODTensor(LODTensor&& ) = delete
is enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to move shared_ptr<lod_t>
and shared_ptr<Tensor>
paddle/framework/tensor.h
Outdated
/* | ||
* Number of elements in a level. | ||
*/ | ||
size_t Elements(uint32_t level = 0) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use size_t
not uint32_t
for index.
Please always use size_t
for index type because it is used widely in C++ standard library.
paddle/framework/tensor.h
Outdated
|
||
/* | ||
* Slice of elements of a level, [elem_begin: elem_end] | ||
* NOTE low performance in slice seq_start_positions_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seq_start_positions_
--> lod_start_pos_
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we use Doxygen comment style. maybe
@note: Low performance in slice lod_start_pos_
is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See here
paddle/framework/tensor_test.cc
Outdated
|
||
auto tensor = std::make_shared<Tensor>(); | ||
DDim dims = make_ddim({20 /*batch size*/, 128 /*dim*/}); | ||
tensor->Resize(dims); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tensor->Resize({20, 128})
is good.
paddle/framework/tensor_test.cc
Outdated
// 0 5 10 15 20 | ||
// 0 2 5 7 10 12 15 20 | ||
auto lod = std::make_shared<LODTensor::lod_t>(); | ||
lod->emplace_back(LODTensor::level_t{0, 10, 20}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto lod = std::make_shared<LODTensor::lod_t>({
{0, 10, 20},
{0, 5, 10, 15, 20},
{0, 2, 5, 7, 10, 12, 15, 17, 20}
});
I am not sure which is more readable, but C++ 11 make initialization of an std container very easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto lod = std::make_shared<LODTensor::lod_t>({
{0, 2, 5, 7, 10, 12, 15, 17, 20}
{0, 5, 10, 15, 20},
{0, 10, 20},
});
上次讨论的是,从小粒度开始存吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod->back()
。。 还没写完的版本
我下午写完,再推上来 @luotao1
paddle/framework/detail/tensor-inl.h
Outdated
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it_begin & it_end could be not found. Add a PADDLE_ENFORCE
here.
paddle/framework/detail/tensor-inl.h
Outdated
auto new_tensor = tensor_->Slice<T>(start, end); | ||
|
||
LODTensor res; | ||
res.set_tensor(new_tensor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe set_tensor
and set_lod
should be constructor of LODTensor. Because all valid LODTensor
should set them both.
paddle/framework/detail/tensor-inl.h
Outdated
@@ -138,5 +138,33 @@ inline void Tensor::Resize(const DDim& dims) { dims_ = dims; } | |||
|
|||
inline const DDim& Tensor::dims() const { return dims_; } | |||
|
|||
template <typename T> | |||
LODTensor LODTensor::Slice(uint32_t level, uint32_t elem_begin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit-test for Slice
method to make sure that code is implemented right.
paddle/framework/lod_tensor.h
Outdated
* 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has_lod() ? lod_start_pos_->size() : 0UL;
paddle/framework/lod_tensor.cc
Outdated
auto start = lod.at(level)[elem_begin]; | ||
auto end = lod.at(level)[elem_end]; | ||
|
||
LOG(INFO) << "start: " << start << " end: " << end; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this line.
paddle/framework/lod_tensor.h
Outdated
|
||
std::shared_ptr<LODTensor::lod_t> SliceLOD(const LODTensor::lod_t &lod, | ||
size_t level, size_t elem_begin, | ||
size_t elem_end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit test for these two SliceLOD interfaces. And these interfaces need comments. Some examples like:
lod={{0, 3, 7, 9}} ,
level=0, elem_begin=1, elem_end=2,
return new_load = {{3,7}}
It is useful for understanding to other developers.
paddle/framework/lod_tensor.h
Outdated
auto new_tensor = std::make_shared<Tensor>(); | ||
new_tensor->template CopyFrom<T>(sliced_tensor, dst_place); | ||
|
||
return LODTensor(new_tensor, new_lod); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod_start_pos_的slice从上面的实现来看,没有对index减去起始值。比如3条句子:
a b c
e f g h
j k
lod={{0, 3, 7, 9}} ,
level=0, elem_begin=1, elem_end=2,
slice之后 new_lod = {{3,7}}, 而不是 {{0,4}}
tensor_
进行了Slice,并且拷贝。
这样,新的LODTensor依据new_lod来访问,会有越界吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
paddle/framework/lod_tensor.h
Outdated
auto new_tensor = std::make_shared<Tensor>(); | ||
new_tensor->CopyFrom<T>(*tensor_, dst_place); | ||
|
||
return LODTensor(new_tensor, new_lod); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
level级别的slice,这里对lod_start_pos_
进行了slice,tensor_
没有slice,是完整拷贝?
觉得最好多加一些注释,或者例子解释,不然developers看到还得思考半天~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
paddle/framework/lod_tensor.h
Outdated
typedef std::vector<level_t> lod_t; | ||
|
||
LODTensor() {} | ||
LODTensor(std::shared_ptr<Tensor> tensor, std::shared_ptr<lod_t> lod) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If use shared_ptr, always use const std::shared_ptr<Tensor>&
to pass them into a function.
std::shared_ptr<T>
could be very slow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here need to share resource, so no const& here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here need to share resource, so no const& here.
const std::shared_ptr<T>&
does not mean that the value of T
cannot be changed. It means that the pointer of T
cannot be changed.
paddle/framework/lod_tensor.h
Outdated
Reset(tensor, lod); | ||
} | ||
|
||
void Reset(std::shared_ptr<Tensor> tensor, std::shared_ptr<lod_t> lod) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
paddle/framework/lod_tensor.h
Outdated
PADDLE_ENFORCE(elem < Elements(level), | ||
"element begin [%d] out of range [%d]", elem, | ||
Elements(level)); | ||
return lod_start_pos_->at(level)[elem]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod_start_pos_[level][elem];
is better, because the previous PADDLE_ENFORCE
has check the index of lod_start_pos_
, it is not necessary use at
to check it again.
The different between at
and []
is at will perform a range check, and throw a std::runtime_error
when out of range.
paddle/framework/lod_tensor.h
Outdated
/* | ||
* Number of elements in a level. | ||
*/ | ||
size_t Elements(size_t level = 0) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Levels
and Elements
are quite confusing names. Maybe just simple NumOfLevels
and NumOfElements
are better name? Or NumLevels
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://google.github.io/styleguide/cppguide.html#General_Naming_Rules
num_errors
is a good name.
paddle/framework/lod_tensor.h
Outdated
/* | ||
* Determine whether LODTensor has a valid LOD info. | ||
*/ | ||
bool has_lod() const { return lod_start_pos_.get(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return lod_start_pos_;
paddle/framework/lod_tensor.h
Outdated
* Determine whether LODTensor has a valid LOD info. | ||
*/ | ||
bool has_lod() const { return lod_start_pos_.get(); } | ||
std::shared_ptr<lod_t> const lod() const { return lod_start_pos_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
http://www.cplusplus.com/reference/memory/const_pointer_cast/
std::shared_ptr<const lod_t> lod() const { return std::const_pointer_cast<const lod_t>(lod_start_pos_)}
paddle/framework/lod_tensor.h
Outdated
|
||
private: | ||
mutable std::shared_ptr<lod_t> lod_start_pos_; | ||
mutable std::shared_ptr<Tensor> tensor_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not use mutable
.
paddle/framework/lod_tensor.cc
Outdated
return LODTensor(tensor_, new_lod); | ||
} | ||
|
||
namespace details { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The details
namespace is not necessarily declared in the header file.
Just declare them in *.cc
is simpler.
paddle/framework/lod_tensor.h
Outdated
// 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<level_t> lod_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod_t => LOD
Following Google C++ style guide: https://google.github.io/styleguide/cppguide.html#Type_Names
paddle/framework/lod_tensor.h
Outdated
/* | ||
* Determine whether LODTensor has a valid LOD info. | ||
*/ | ||
bool has_lod() const { return lod_start_pos_.get(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
has_lod => HasLOD
Follow Google C++ style guide https://google.github.io/styleguide/cppguide.html#Function_Names
paddle/framework/lod_tensor.h
Outdated
mutable std::shared_ptr<Tensor> tensor_; | ||
}; | ||
|
||
namespace details { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to C++ style https://google.github.io/styleguide/cppguide.html#Namespace_Names, if we want to add namespace details
, we must create a corresponding sub-directory named details
.
Here it seems that we don't need this namespace nor the sub-directory -- if SliceLOD
is supposed to be called outside of framework/lod_tensor*
, let's just remove namespace details
; otherwise, let's move it into lod_tensor.cc
and in the anonymous namespace as described in https://google.github.io/styleguide/cppguide.html#Unnamed_Namespaces_and_Static_Variables
* Slice of levels[level_begin:level_end], with tensor copied. | ||
*/ | ||
template <typename T> | ||
LODTensor SliceCopied(size_t level_begin, size_t level_end, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
T
doesn't appear in the definition of SliceCopied
. Do we really need this method a function template?
I have the same question with SliceShared
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tensor's CopyFrom need a T
, SliceShared's T will be removed.
paddle/framework/tensor.cc
Outdated
@@ -15,5 +15,5 @@ | |||
#include "paddle/framework/tensor.h" | |||
|
|||
namespace paddle { | |||
namespace framework {} | |||
namespace framework {} // namespace framework |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would we need this empty .cc file?
paddle/framework/lod_tensor.cc
Outdated
std::shared_ptr<LODTensor::lod_t> SliceLOD(const LODTensor::lod_t &lod, | ||
size_t level_begin, | ||
size_t level_end) { | ||
auto new_lod = std::make_shared<LODTensor::lod_t>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new_lod.reserve
.
Always reserve
vector.
paddle/framework/lod_tensor.cc
Outdated
bool tensor_shared) { | ||
// slice the lod. | ||
auto new_lod = std::make_shared<LODTensor::lod_t>(); | ||
auto start = lod.at(level)[elem_begin]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is at
necessary?
paddle/framework/lod_tensor.cc
Outdated
size_t elem_end, | ||
bool tensor_shared) { | ||
// slice the lod. | ||
auto new_lod = std::make_shared<LODTensor::lod_t>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reserve
if you can.
paddle/framework/lod_tensor.h
Outdated
* @level_begin: level to begin slice. | ||
* @level_end: level to end slice. | ||
*/ | ||
std::shared_ptr<LODTensor::lod_t> SliceLOD(const LODTensor::lod_t &lod, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace details
is not necessarily in the header file.
paddle/framework/lod_tensor_test.cc
Outdated
|
||
TEST_F(LODTensorTester, SliceShared_Level) { | ||
// slice 1 level | ||
for (int level = 0; level < 3; level++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always use size_t
for loop index. always use ++level
.
https://google.github.io/styleguide/cppguide.html#Preincrement_and_Predecrement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LODTensor is a Tensor, so it should be derived from class Tensor, so could it inherit all methods from Tensor.
LOD type should be exported in lod.{h,cc,_test.cc}
, so that it could be assigned to a Variable
instance.
In our applications, many LODTensor instances might share the same LOD instance. We can save the LOD instance in a variable in the global scope, so that it would be referred to by all LODTensor instances.
The constructor of an LODTensor should be
class LODTensor {
public:
LODTensor(const LOD& lod, ...) : lod_(lod), Tensor(...) {}
LODTensor doesn't need SliceCopied
. Let us remvoe it.
LODTensor needs SliceLevels
and SliceInLevel
.
Variable type inference along the network should be implemented using simple C++ features. Consider that an RNNOp instance would require its inputs are of type LODTensor, and should return outputs in LODTensor too. An FCOp instance requires Tensor-typed inputs and would return Tensor-typed outputs. However, it is possible that an LODTensor input feeds into an RNNOp instance, the output feeds into a FCOp instance, and the output of FCOp instance feeds in a second RNNOp instance. In such case, we want the FCOp instance creates its outputs in type LODTensor. To implement this features, we need to:
- Add
virtual Tensor* Tensor::Close() const
- Override it in LODTensor as
class LODTensor { public: virtual Tensor* Clone() const { return new LODTensor(lod_); }
- In RNNOp and FCOp, the creation of output must be cloned from the input. For example:
Tensor* output = Input(0)->Clone();
|
||
LODTensor LODTensor::SliceShared(size_t level, size_t elem_begin, | ||
size_t elem_end) const { | ||
PADDLE_ENFORCE(HasLOD(), "has no LOD info, can't be sliced."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
一个LODTensor instance里不是一定总有LOD 信息的?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tensor* output = Input(0)->Clone();
这里是否应该改成
output_var.clone(input_var); // clone the tensor type
Tensor* output = output_var.Get<Tensor>();
/* | ||
* Get a element from LOD. | ||
*/ | ||
size_t lod_element(size_t level, size_t elem) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod_element => StartPosition
/* | ||
* Number of elements in a level. | ||
*/ | ||
size_t NumElements(size_t level = 0) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NumElements => ElementsOfLevel
} | ||
|
||
/* | ||
* Slice of levels[level_begin:level_end], with tensor copied. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Copy the slice of data from *this into a new LODTensor and return the new LODTensor.
/* | ||
* Slice of levels[level_begin:level_end], with tensor shared. | ||
*/ | ||
LODTensor SliceShared(size_t level_begin, size_t level_end) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Returns a new LODTensor that shares data with *this but provides a view of the specified slice.
* Slice of levels[level_begin:level_end], with tensor copied. | ||
*/ | ||
template <typename T> | ||
LODTensor SliceCopied(size_t level_begin, size_t level_end, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this method slice some levels, or elements in a level?
Tensor *raw_tensor() { return tensor_.get(); } | ||
|
||
private: | ||
std::shared_ptr<LOD> lod_start_pos_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lod_start_pos_ = > lod_
About the name, see level of detail