diff --git a/paddle/framework/lod_tensor.cc b/paddle/framework/lod_tensor.cc index e4a2f5765a10cbeb24b71b5cea7677172c058875..49d9e56689246e55b3c59866ce0ae061dbe5f305 100644 --- a/paddle/framework/lod_tensor.cc +++ b/paddle/framework/lod_tensor.cc @@ -103,28 +103,28 @@ void LoDTensor::ShrinkInLevel(size_t level, size_t elem_begin, lod_ = new_lod; } -Vector repeat_lod(Vector data, Vector starts, - Vector times, bool is_first) { +Vector expand_lod(Vector level, Vector starts, + Vector scales, bool repeat) { Vector result; - result.push_back(data[0]); + result.push_back(level[0]); size_t p = 0, start = 0, end = 0; - if (is_first == true) { - for (size_t i = 0; i < times.size(); ++i) { - result.push_back(result.back() + times[i] * (data[i + 1] - data[i])); + if (!repeat) { + for (size_t i = 0; i < scales.size(); ++i) { + result.push_back(result.back() + scales[i] * (level[i + 1] - level[i])); } } else { - for (size_t i = 0; i < times.size(); ++i) { - while (starts[i] != data[p] && p < data.size()) { + for (size_t i = 0; i < scales.size(); ++i) { + while (starts[i] != level[p] && p < level.size()) { ++p; } start = p; - while (starts[i + 1] != data[p] && p < data.size()) { + while (starts[i + 1] != level[p] && p < level.size()) { ++p; } end = p + 1; - for (size_t j = 0; j < times[i]; ++j) { + for (size_t j = 0; j < scales[i]; ++j) { for (size_t index = start; index < end - 1; ++index) { - result.push_back(result.back() + data[index + 1] - data[index]); + result.push_back(result.back() + level[index + 1] - level[index]); } } } diff --git a/paddle/framework/lod_tensor.h b/paddle/framework/lod_tensor.h index 41c83a11649a927673c2f72468328b20722e55a6..c64ee94405b791393345d1187ca39e17ad72e2c5 100644 --- a/paddle/framework/lod_tensor.h +++ b/paddle/framework/lod_tensor.h @@ -15,9 +15,6 @@ #pragma once #include -#include "paddle/memory/memcpy.h" -#include "paddle/platform/device_context.h" -#include "paddle/platform/place.h" #ifdef PADDLE_WITH_CUDA #include #include @@ -126,8 +123,8 @@ class LoDTensor : public Tensor { LoD lod_; }; -Vector repeat_lod(Vector data, Vector starts, - Vector times, bool is_first); +Vector expand_lod(Vector level, Vector starts, + Vector scales, bool repeat); } // namespace framework } // namespace paddle diff --git a/paddle/operators/seq_expand_op.cc b/paddle/operators/seq_expand_op.cc index 59d713548930e4e80e0db0225bfabca4da35f95a..b9633721e296c0889c6ac7d359570e9d59153e6a 100644 --- a/paddle/operators/seq_expand_op.cc +++ b/paddle/operators/seq_expand_op.cc @@ -50,28 +50,68 @@ class SeqExpandOpMaker : public framework::OpProtoAndCheckerMaker { SeqExpandOpMaker(framework::OpProto* proto, framework::OpAttrChecker* op_checker) : OpProtoAndCheckerMaker(proto, op_checker) { - // TODO(wanghaoshuang): Add more comments - AddInput("X", "The input('X') of seq_expand op."); - AddInput("Y", "The reference input('Y') of seq_expand op."); - AddOutput("Out", "The output of seq_expand op."); - AddAttr("repeat", "repeat times").SetDefault(0); + AddInput( + "X", + "The input('X') of seq_expand op. It can be LoDTensor or base Tensor."); + AddInput( + "Y", + "The reference input('Y') of seq_expand op." + "It must be a LoDTensor with k-level(k>0)." + "This reference input is essential if 'repeat' attribute is not " + "configured." + "Input(X) will be expanded by LoD of input(Y) while repeat == 0."); + AddOutput("Out", + "The output of seq_expand op." + "The output is a (k+1)-level LoDTensor" + "while input(X) being k-level LoDTensor." + "(Given base tensor is 0-level LoDTensor.)"); + AddAttr("repeat", + "(type:int; default value: 0)" + "Repeatting times of each element while expanding input(X)." + "It works while input(Y) is not configured.") + .SetDefault(0); AddComment(R"DOC( -As an example: +Expand k-level LoDTensor to (k+1)-level LoDTensor +by lod of input(Y) or 'repeat' attribute. -Given: - -X.data = [1, 2 , 3, 4] -X.lod = [[0, 3, 4], [0, 1, 3, 4]] +Case 1: +Given a 2-level LoDTensor X: + X.data = [1, 2 , 3, 4] + X.lod = [[0, 3, 4], [0, 1, 3, 4]] and - -repeat = 2 - - -then we get - -Out.data = [1, 2, 3, 1, 2, 3, 4, 4] -Out.lod = [[0, 6, 8], [0, 3, 6, 7, 8], [0, 1, 3, 4, 6, 7, 8]] + repeat = 2 +then we get 3-level LoDTensor + Out.data = [1, 2, 3, 1, 2, 3, 4, 4] + Out.lod = [[0, 6, 8], + [0, 3, 6, 7, 8], + [0, 1, 3, 4, 6, 7, 8]] + +Case 2: + +Given 2-level a LoDTensor X + X.data = [1, 2, 3, 4] + X.lod = [[0, 3, 4], [0, 1, 3, 4]] +and + Y.lod = [[0, 6, 8], + [0, 3, 6, 7, 8], + [0,1,3,4,6,7,8]] +then we get 3-level LoDTensor + Out.data = [1, 2, 3, 1, 2, 3, 4, 4] + Out.lod = [[0, 6, 8], + [0, 3, 6, 7, 8], + [0, 1, 3, 4, 6, 7, 8]] + +Case 3: + +Given a 0-level LoDTensor X + X.data = [1, 2, 3, 4] + X.lod = NULL +and + repeat = 2 +then we get 1-level LoDTensor + Out.data = [1, 1, 2, 2, 3, 3, 4, 4] + Out.lod = [[0, 2, 4, 6, 8]] )DOC"); } diff --git a/paddle/operators/seq_expand_op.h b/paddle/operators/seq_expand_op.h index 8b7bda54c05d101a448911461d59d7501c92ec1f..e990f125127e507ed84d67a2e49443324edf37b1 100644 --- a/paddle/operators/seq_expand_op.h +++ b/paddle/operators/seq_expand_op.h @@ -44,10 +44,10 @@ class SeqExpandKernel : public framework::OpKernel { } size_t repeat = static_cast(context.Attr("repeat")); - framework::Vector repeats; + framework::Vector scales; if (repeat != 0) { for (int i = 0; i < x_lod[0].size() - 1; ++i) { - repeats.push_back(repeat); + scales.push_back(repeat); } std::vector dims = framework::vectorize(x->dims()); dims[0] = dims[0] * repeat; @@ -57,18 +57,18 @@ class SeqExpandKernel : public framework::OpKernel { auto* y = context.Input("Y"); auto y_lod = y->lod(); for (int i = 0; i < y_lod[0].size() - 1; ++i) { - repeats.push_back((y_lod[0][i + 1] - y_lod[0][i]) / - (x_lod[0][i + 1] - x_lod[0][i])); + scales.push_back((y_lod[0][i + 1] - y_lod[0][i]) / + (x_lod[0][i + 1] - x_lod[0][i])); } out->Resize(y->dims()); } framework::LoD out_lod; - auto level0 = framework::repeat_lod(x_lod[0], x_lod[0], repeats, true); + auto level0 = framework::expand_lod(x_lod[0], x_lod[0], scales, false); out_lod.push_back(level0); for (int i = 1; i < x_lod.size(); ++i) { out_lod.push_back( - framework::repeat_lod(x_lod[i], x_lod[0], repeats, false)); + framework::expand_lod(x_lod[i], x_lod[0], scales, true)); } size_t element_len = framework::product(x_dims) / x_dims[0]; @@ -77,9 +77,9 @@ class SeqExpandKernel : public framework::OpKernel { // copy data Place place = boost::get(context.GetPlace()); size_t count = 0; - for (size_t i = 0; i < repeats.size(); ++i) { + for (size_t i = 0; i < scales.size(); ++i) { count = element_len * (x_lod[0][i + 1] - x_lod[0][i]); - for (size_t j = 0; j < repeats[i]; ++j) { + for (size_t j = 0; j < scales[i]; ++j) { memory::Copy(place, out_data, place, x_data, sizeof(T) * count); out_data += count; } @@ -95,9 +95,9 @@ class SeqExpandGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* d_out = context.Input(framework::GradVarName("Out")); - auto* d_x = context.Output(framework::GradVarName("X")); auto* x = context.Input("X"); auto* out = context.Input("Out"); + auto* d_x = context.Output(framework::GradVarName("X")); auto out_lod = out->lod(); d_x->set_lod(x->lod()); const T* d_out_data = d_out->data();