From ac7cb949d04f03e64970302b5c3b74cccfeea13c Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Fri, 13 Apr 2018 16:37:41 +0800 Subject: [PATCH 1/7] auto-grown sparse table --- paddle/fluid/framework/selected_rows.cc | 91 ++++++++++++++++++++ paddle/fluid/framework/selected_rows.h | 44 ++++++++-- paddle/fluid/framework/selected_rows_test.cc | 23 ++++- 3 files changed, 152 insertions(+), 6 deletions(-) diff --git a/paddle/fluid/framework/selected_rows.cc b/paddle/fluid/framework/selected_rows.cc index d9d6b7dd67..f1dbd75e40 100644 --- a/paddle/fluid/framework/selected_rows.cc +++ b/paddle/fluid/framework/selected_rows.cc @@ -17,6 +17,53 @@ limitations under the License. */ namespace paddle { namespace framework { +struct ReAllocateVisitor { + ReAllocateVisitor(framework::Tensor* tensor, const framework::DDim& dims) + : tensor_(tensor), dims_(dims) {} + + template + void operator()() const { + framework::Tensor cpu_tensor; + platform::CPUPlace cpu; + T* ptr = cpu_tensor.mutable_data(dims_, cpu); + const T* old_ptr = + tensor_->memory_size() == 0 ? nullptr : tensor_->data(); + if (old_ptr != nullptr) { + std::copy(old_ptr, old_ptr + tensor_->numel(), ptr); + } + tensor_->ShareDataWith(cpu_tensor); + } + + framework::Tensor* tensor_; + framework::DDim dims_; +}; + +struct TensorSlicedCopyVisitor { + TensorSlicedCopyVisitor(const platform::Place& place, framework::Tensor* dst, + int64_t dst_offset, const framework::Tensor src, + int64_t src_offset, int64_t size) + : place_(place), + dst_(dst), + dst_offset_(dst_offset), + src_(src), + src_offset_(src_offset), + size_(size) {} + + template + void operator()() const { + std::copy(src_.data() + src_offset_, + src_.data() + src_offset_ + size_, + dst_->mutable_data(place_) + dst_offset_); + } + + platform::Place place_; + framework::Tensor* dst_; + int64_t dst_offset_; + framework::Tensor src_; + int64_t src_offset_; + int64_t size_; +}; + void SerializeToStream(std::ostream& os, const SelectedRows& selected_rows, const platform::DeviceContext& dev_ctx) { { // the 1st field, uint32_t version @@ -69,5 +116,49 @@ void DeserializeFromStream(std::istream& is, SelectedRows* selected_rows, TensorFromStream(is, selected_rows->mutable_value(), dev_ctx); } +bool SelectedRows::HasKey(int64_t key) const { + return std::find(rows_.begin(), rows_.end(), key) == rows_.end() ? false + : true; +} + +Tensor SelectedRows::Get(int64_t key) const { + int64_t index = Index(key); + PADDLE_ENFORCE_GE(index, 0, "The key should be exists in the Table."); + return value_->Slice(index, index + 1); +} + +bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { + PADDLE_ENFORCE(value.IsInitialized(), "The value should be initialized."); + if (value_->IsInitialized()) { + PADDLE_ENFORCE_EQ( + value.type(), value_->type(), + "The type of the value should be same with the original value"); + } + PADDLE_ENFORCE_EQ(value.dims()[0], static_cast(1), + "The first dim of value should be 1."); + auto index = Index(key); + platform::Place cpu = platform::CPUPlace(); + bool is_new_key = false; + if (index == -1) { + rows_.push_back(key); + index = rows_.size() - 1; + is_new_key = true; + // whether need to resize the value + if (static_cast(rows_.size()) > value_->dims()[0]) { + auto dims = value_->dims(); + dims[0] = (dims[0] + 1) << 1; + framework::VisitDataType(framework::ToDataType(value.type()), + ReAllocateVisitor(value_.get(), dims)); + } + } + + framework::VisitDataType( + framework::ToDataType(value.type()), + TensorSlicedCopyVisitor(cpu, value_.get(), + index * value_->numel() / value_->dims()[0], + value, static_cast(0), value.numel())); + return is_new_key; +} + } // namespace framework } // namespace paddle diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index 8e2d9470d3..6a125d59ec 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -14,6 +14,7 @@ limitations under the License. */ #pragma once +#include #include #include "paddle/fluid/framework/lod_tensor.h" @@ -50,12 +51,45 @@ class SelectedRows { void set_rows(const Vector& rows) { rows_ = rows; } - /** - * get the index of id in rows + /* + * @brief wheter has the specified key in the table. + * + * @return true if the key is exists. */ - int64_t index(int64_t id) const { - auto it = std::find(rows_.begin(), rows_.end(), id); - PADDLE_ENFORCE(it != rows_.end(), "id should be in rows"); + bool HasKey(int64_t key) const; + + /* + * @brief Get a value by the specified key, if the + * key does not exists, this function would throw an exception. + * + * @return a sliced tensor + */ + Tensor Get(int64_t key) const; + + /* + * @brief Set a key-value pair into the table. + * This function will double the value memory if it's not engouth. + * + * @note: + * 1. The first dim of the value should be 1 + * 2. The value should be initialized and the data type + * should be the same with the table. + * + * @return true if the key is a new one, otherwise false + * + */ + bool Set(int64_t key, const Tensor& value); + + /* + * @brief Get the index of key in rows + * + * @return -1 if the key does not exists. + */ + int64_t Index(int64_t key) const { + auto it = std::find(rows_.begin(), rows_.end(), key); + if (it == rows_.end()) { + return static_cast(-1); + } return static_cast(std::distance(rows_.begin(), it)); } diff --git a/paddle/fluid/framework/selected_rows_test.cc b/paddle/fluid/framework/selected_rows_test.cc index 960d8d64f0..2cbf2bfea2 100644 --- a/paddle/fluid/framework/selected_rows_test.cc +++ b/paddle/fluid/framework/selected_rows_test.cc @@ -17,7 +17,7 @@ namespace framework { class SelectedRowsTester : public ::testing::Test { public: - virtual void SetUp() override { + void SetUp() override { std::vector rows{0, 4, 7}; int64_t height = 10; int64_t row_numel = 100; @@ -59,5 +59,26 @@ TEST_F(SelectedRowsTester, SerializeAndDeseralize) { ASSERT_EQ(selected_rows_->GetCompleteDims(), dst_tensor.GetCompleteDims()); } +TEST_F(SelectedRowsTester, Table) { + platform::CPUPlace cpu; + SelectedRows table; + + int64_t key = 10000; + framework::Tensor value; + value.Resize(framework::make_ddim({1, 100})); + auto ptr = value.mutable_data(cpu); + ptr[0] = static_cast(10); + + ASSERT_EQ(table.rows().size(), static_cast(0)); + ASSERT_EQ(table.HasKey(key), false); + + table.Set(key, value); + + ASSERT_EQ(table.rows().size(), static_cast(1)); + ASSERT_EQ(table.HasKey(key), true); + ASSERT_EQ(table.value().dims()[0], static_cast(2)); + ASSERT_EQ(table.Get(key).data()[0], static_cast(10)); +} + } // namespace framework } // namespace paddle From 19152541b231190020c06efb82d954a098d55e6a Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Fri, 13 Apr 2018 16:44:24 +0800 Subject: [PATCH 2/7] fix ci --- paddle/fluid/operators/lookup_table_op.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/paddle/fluid/operators/lookup_table_op.h b/paddle/fluid/operators/lookup_table_op.h index cb088c267b..d482506bf0 100644 --- a/paddle/fluid/operators/lookup_table_op.h +++ b/paddle/fluid/operators/lookup_table_op.h @@ -103,7 +103,8 @@ class LookupTableKernel : public framework::OpKernel { memset(output + i * row_width, 0, row_width * sizeof(T)); } else { PADDLE_ENFORCE_GE(ids[i], 0); - auto id_index = table_t.index(ids[i]); + auto id_index = table_t.Index(ids[i]); + PADDLE_ENFORCE_GE(id_index, 0, "the input key should be exists."); memcpy(output + i * row_width, table + id_index * row_width, row_width * sizeof(T)); } From ca327508ccbac09cf92841d2cb026a9478e40faf Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Tue, 17 Apr 2018 18:36:18 +0800 Subject: [PATCH 3/7] update --- paddle/fluid/framework/selected_rows.cc | 37 ++++++++++++++------ paddle/fluid/framework/selected_rows.h | 5 +-- paddle/fluid/framework/selected_rows_test.cc | 18 +++++++--- paddle/fluid/operators/sgd_op.h | 4 ++- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/paddle/fluid/framework/selected_rows.cc b/paddle/fluid/framework/selected_rows.cc index f1dbd75e40..ec82611d2e 100644 --- a/paddle/fluid/framework/selected_rows.cc +++ b/paddle/fluid/framework/selected_rows.cc @@ -38,10 +38,10 @@ struct ReAllocateVisitor { framework::DDim dims_; }; -struct TensorSlicedCopyVisitor { - TensorSlicedCopyVisitor(const platform::Place& place, framework::Tensor* dst, - int64_t dst_offset, const framework::Tensor src, - int64_t src_offset, int64_t size) +struct TensorCopyVisitor { + TensorCopyVisitor(const platform::Place& place, framework::Tensor* dst, + int64_t dst_offset, const framework::Tensor src, + int64_t src_offset, int64_t size) : place_(place), dst_(dst), dst_offset_(dst_offset), @@ -121,10 +121,27 @@ bool SelectedRows::HasKey(int64_t key) const { : true; } -Tensor SelectedRows::Get(int64_t key) const { +bool SelectedRows::Get(int64_t key, framework::Tensor* value, + int64_t row) const { int64_t index = Index(key); PADDLE_ENFORCE_GE(index, 0, "The key should be exists in the Table."); - return value_->Slice(index, index + 1); + PADDLE_ENFORCE(value->IsInitialized(), + "The value tensor should be initialized."); + + int64_t value_width = value->numel() / value->dims()[0]; + PADDLE_ENFORCE_EQ(value_width, value_->numel() / value_->dims()[0], + "output tensor should have the same shape with table " + "execpt the dims[0]."); + + // TODO(Yancey1989): support other place + platform::CPUPlace cpu; + + framework::VisitDataType( + framework::ToDataType(value_->type()), + TensorCopyVisitor(cpu, value, row * value_width, *value_.get(), + index * value_width, value_width)); + + return true; } bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { @@ -143,7 +160,7 @@ bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { rows_.push_back(key); index = rows_.size() - 1; is_new_key = true; - // whether need to resize the value + // whether need to resize the table if (static_cast(rows_.size()) > value_->dims()[0]) { auto dims = value_->dims(); dims[0] = (dims[0] + 1) << 1; @@ -154,9 +171,9 @@ bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { framework::VisitDataType( framework::ToDataType(value.type()), - TensorSlicedCopyVisitor(cpu, value_.get(), - index * value_->numel() / value_->dims()[0], - value, static_cast(0), value.numel())); + TensorCopyVisitor(cpu, value_.get(), + index * value_->numel() / value_->dims()[0], value, + static_cast(0), value.numel())); return is_new_key; } diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index 6a125d59ec..df580c3a14 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -62,9 +62,10 @@ class SelectedRows { * @brief Get a value by the specified key, if the * key does not exists, this function would throw an exception. * - * @return a sliced tensor + * @return true if the Get operation successed. */ - Tensor Get(int64_t key) const; + + bool Get(int64_t key, framework::Tensor* tensor, int64_t row = 0) const; /* * @brief Set a key-value pair into the table. diff --git a/paddle/fluid/framework/selected_rows_test.cc b/paddle/fluid/framework/selected_rows_test.cc index 2cbf2bfea2..21dade1ab9 100644 --- a/paddle/fluid/framework/selected_rows_test.cc +++ b/paddle/fluid/framework/selected_rows_test.cc @@ -62,6 +62,10 @@ TEST_F(SelectedRowsTester, SerializeAndDeseralize) { TEST_F(SelectedRowsTester, Table) { platform::CPUPlace cpu; SelectedRows table; + // initialize a sparse table + table.mutable_value()->Resize(framework::make_ddim({1, 100})); + table.mutable_value()->mutable_data(cpu); + table.mutable_rows()->push_back(1); int64_t key = 10000; framework::Tensor value; @@ -69,15 +73,21 @@ TEST_F(SelectedRowsTester, Table) { auto ptr = value.mutable_data(cpu); ptr[0] = static_cast(10); - ASSERT_EQ(table.rows().size(), static_cast(0)); + ASSERT_EQ(table.rows().size(), static_cast(1)); ASSERT_EQ(table.HasKey(key), false); table.Set(key, value); - ASSERT_EQ(table.rows().size(), static_cast(1)); + ASSERT_EQ(table.rows().size(), static_cast(2)); ASSERT_EQ(table.HasKey(key), true); - ASSERT_EQ(table.value().dims()[0], static_cast(2)); - ASSERT_EQ(table.Get(key).data()[0], static_cast(10)); + // check re-allocate + ASSERT_EQ(table.value().dims()[0], static_cast(4)); + + framework::Tensor get_value; + get_value.mutable_data(framework::make_ddim({20, 100}), cpu); + table.Get(key, &get_value, 10); + + ASSERT_EQ(get_value.data()[10 * 100], static_cast(10)); } } // namespace framework diff --git a/paddle/fluid/operators/sgd_op.h b/paddle/fluid/operators/sgd_op.h index cfc8793e1e..f3e88b0a0b 100644 --- a/paddle/fluid/operators/sgd_op.h +++ b/paddle/fluid/operators/sgd_op.h @@ -107,7 +107,9 @@ class SGDOpKernel : public framework::OpKernel { for (size_t i = 0; i < grad.rows().size(); i++) { PADDLE_ENFORCE(grad.rows()[i] < grad.height(), "Input rows index should less than height"); - int64_t id_index = param.index(grad.rows()[i]); + int64_t id_index = param.Index(grad.rows()[i]); + PADDLE_ENFORCE_GE(id_index, static_cast(0), + "id should be in the table"); for (size_t j = 0; j < grad_row_width; j++) { out_data[id_index * grad_row_width + j] -= lr[0] * grad_data[i * grad_row_width + j]; From 2917a75b7a5dccde79d67a5493d7d8f5319f85cb Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Wed, 18 Apr 2018 11:41:25 +0800 Subject: [PATCH 4/7] add some comments for sparse table --- paddle/fluid/framework/selected_rows.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index df580c3a14..a6e9687251 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -24,6 +24,22 @@ namespace paddle { namespace framework { class SelectedRows { + /* + * @brief We can use the SelectedRows structure to reproduce a sparse table. + * A sparse table is a key-value structure that the key is an `int64_t` + * number, + * and the value is a Tensor which the first dimension is 0. + * You can use the following interface to operate the sparse table, and you + * can find + * some detail information from the comments of each interface: + * + * HasKey(key), whether the sparse table has the specified key. + * Set(key, value), set a key-value pair into the sparse table. + * Get(key, value*, offset), get a value by key and apply it to the given + * value pointer + * with the specified offset. + * + */ public: SelectedRows(const std::vector& rows, const int64_t& height) : rows_(rows), height_(height) { From b920b51686d77db07fde4449e2225ae3e363b3f7 Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Wed, 18 Apr 2018 13:46:52 +0800 Subject: [PATCH 5/7] rename parameter --- paddle/fluid/framework/selected_rows.cc | 4 ++-- paddle/fluid/framework/selected_rows.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/paddle/fluid/framework/selected_rows.cc b/paddle/fluid/framework/selected_rows.cc index ec82611d2e..b1837ca3c4 100644 --- a/paddle/fluid/framework/selected_rows.cc +++ b/paddle/fluid/framework/selected_rows.cc @@ -122,7 +122,7 @@ bool SelectedRows::HasKey(int64_t key) const { } bool SelectedRows::Get(int64_t key, framework::Tensor* value, - int64_t row) const { + int64_t offset) const { int64_t index = Index(key); PADDLE_ENFORCE_GE(index, 0, "The key should be exists in the Table."); PADDLE_ENFORCE(value->IsInitialized(), @@ -138,7 +138,7 @@ bool SelectedRows::Get(int64_t key, framework::Tensor* value, framework::VisitDataType( framework::ToDataType(value_->type()), - TensorCopyVisitor(cpu, value, row * value_width, *value_.get(), + TensorCopyVisitor(cpu, value, offset * value_width, *value_.get(), index * value_width, value_width)); return true; diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index a6e9687251..f329ae8939 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -81,7 +81,7 @@ class SelectedRows { * @return true if the Get operation successed. */ - bool Get(int64_t key, framework::Tensor* tensor, int64_t row = 0) const; + bool Get(int64_t key, framework::Tensor* tensor, int64_t offset = 0) const; /* * @brief Set a key-value pair into the table. From 70bf732f8259f94622134c5a2eb930e3e365a882 Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Wed, 18 Apr 2018 19:37:17 +0800 Subject: [PATCH 6/7] refine get interface --- paddle/fluid/framework/selected_rows.cc | 29 ++++++++++++-------- paddle/fluid/framework/selected_rows.h | 11 ++++---- paddle/fluid/framework/selected_rows_test.cc | 10 +++++-- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/paddle/fluid/framework/selected_rows.cc b/paddle/fluid/framework/selected_rows.cc index b1837ca3c4..2eefe79588 100644 --- a/paddle/fluid/framework/selected_rows.cc +++ b/paddle/fluid/framework/selected_rows.cc @@ -121,27 +121,32 @@ bool SelectedRows::HasKey(int64_t key) const { : true; } -bool SelectedRows::Get(int64_t key, framework::Tensor* value, - int64_t offset) const { - int64_t index = Index(key); - PADDLE_ENFORCE_GE(index, 0, "The key should be exists in the Table."); +std::vector SelectedRows::Get(std::vector keys, + framework::Tensor* value) const { PADDLE_ENFORCE(value->IsInitialized(), "The value tensor should be initialized."); - int64_t value_width = value->numel() / value->dims()[0]; - PADDLE_ENFORCE_EQ(value_width, value_->numel() / value_->dims()[0], + std::vector non_keys; + int64_t value_width = value_->numel() / value_->dims()[0]; + PADDLE_ENFORCE_EQ(value_width, value->numel() / value->dims()[0], "output tensor should have the same shape with table " "execpt the dims[0]."); // TODO(Yancey1989): support other place platform::CPUPlace cpu; - framework::VisitDataType( - framework::ToDataType(value_->type()), - TensorCopyVisitor(cpu, value, offset * value_width, *value_.get(), - index * value_width, value_width)); - - return true; + for (size_t i = 0; i < keys.size(); ++i) { + int64_t index = Index(keys[i]); + if (index == -1) { + non_keys.push_back(keys[i]); + } else { + framework::VisitDataType( + framework::ToDataType(value_->type()), + TensorCopyVisitor(cpu, value, i * value_width, *value_.get(), + index * value_width, value_width)); + } + } + return non_keys; } bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index f329ae8939..cef3ddab47 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -35,7 +35,7 @@ class SelectedRows { * * HasKey(key), whether the sparse table has the specified key. * Set(key, value), set a key-value pair into the sparse table. - * Get(key, value*, offset), get a value by key and apply it to the given + * Get(keys, value*), get value by given key list and apply it to the given * value pointer * with the specified offset. * @@ -75,13 +75,12 @@ class SelectedRows { bool HasKey(int64_t key) const; /* - * @brief Get a value by the specified key, if the - * key does not exists, this function would throw an exception. + * @brief Get value by the key list, if the * - * @return true if the Get operation successed. + * @return a list of keys which does not exists in table */ - - bool Get(int64_t key, framework::Tensor* tensor, int64_t offset = 0) const; + std::vector Get(std::vector keys, + framework::Tensor* tensor) const; /* * @brief Set a key-value pair into the table. diff --git a/paddle/fluid/framework/selected_rows_test.cc b/paddle/fluid/framework/selected_rows_test.cc index 21dade1ab9..39fe6d9294 100644 --- a/paddle/fluid/framework/selected_rows_test.cc +++ b/paddle/fluid/framework/selected_rows_test.cc @@ -68,6 +68,7 @@ TEST_F(SelectedRowsTester, Table) { table.mutable_rows()->push_back(1); int64_t key = 10000; + int64_t non_key = 999; framework::Tensor value; value.Resize(framework::make_ddim({1, 100})); auto ptr = value.mutable_data(cpu); @@ -84,10 +85,13 @@ TEST_F(SelectedRowsTester, Table) { ASSERT_EQ(table.value().dims()[0], static_cast(4)); framework::Tensor get_value; - get_value.mutable_data(framework::make_ddim({20, 100}), cpu); - table.Get(key, &get_value, 10); + get_value.mutable_data(framework::make_ddim({2, 100}), cpu); + std::vector keys({non_key, key}); + auto non_keys = table.Get(keys, &get_value); - ASSERT_EQ(get_value.data()[10 * 100], static_cast(10)); + ASSERT_EQ(get_value.data()[100], static_cast(10)); + ASSERT_EQ(non_keys.size(), static_cast(1)); + ASSERT_EQ(non_keys[0], non_key); } } // namespace framework From f12b3f36173e6bda8b3d26d02f86523c81a85f19 Mon Sep 17 00:00:00 2001 From: Yancey1989 Date: Wed, 18 Apr 2018 20:40:47 +0800 Subject: [PATCH 7/7] use memcpy --- paddle/fluid/framework/selected_rows.cc | 26 ++++++++++--------------- paddle/fluid/framework/selected_rows.h | 1 + 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/paddle/fluid/framework/selected_rows.cc b/paddle/fluid/framework/selected_rows.cc index 2eefe79588..794e7f7434 100644 --- a/paddle/fluid/framework/selected_rows.cc +++ b/paddle/fluid/framework/selected_rows.cc @@ -39,11 +39,10 @@ struct ReAllocateVisitor { }; struct TensorCopyVisitor { - TensorCopyVisitor(const platform::Place& place, framework::Tensor* dst, - int64_t dst_offset, const framework::Tensor src, - int64_t src_offset, int64_t size) - : place_(place), - dst_(dst), + TensorCopyVisitor(framework::Tensor* dst, int64_t dst_offset, + const framework::Tensor src, int64_t src_offset, + int64_t size) + : dst_(dst), dst_offset_(dst_offset), src_(src), src_offset_(src_offset), @@ -51,12 +50,12 @@ struct TensorCopyVisitor { template void operator()() const { - std::copy(src_.data() + src_offset_, - src_.data() + src_offset_ + size_, - dst_->mutable_data(place_) + dst_offset_); + // TODO(Yancey1989): support other place + platform::CPUPlace cpu; + memory::Copy(cpu, dst_->mutable_data(cpu) + dst_offset_, cpu, + src_.data() + src_offset_, size_ * sizeof(T)); } - platform::Place place_; framework::Tensor* dst_; int64_t dst_offset_; framework::Tensor src_; @@ -125,16 +124,12 @@ std::vector SelectedRows::Get(std::vector keys, framework::Tensor* value) const { PADDLE_ENFORCE(value->IsInitialized(), "The value tensor should be initialized."); - std::vector non_keys; int64_t value_width = value_->numel() / value_->dims()[0]; PADDLE_ENFORCE_EQ(value_width, value->numel() / value->dims()[0], "output tensor should have the same shape with table " "execpt the dims[0]."); - // TODO(Yancey1989): support other place - platform::CPUPlace cpu; - for (size_t i = 0; i < keys.size(); ++i) { int64_t index = Index(keys[i]); if (index == -1) { @@ -142,7 +137,7 @@ std::vector SelectedRows::Get(std::vector keys, } else { framework::VisitDataType( framework::ToDataType(value_->type()), - TensorCopyVisitor(cpu, value, i * value_width, *value_.get(), + TensorCopyVisitor(value, i * value_width, *value_.get(), index * value_width, value_width)); } } @@ -159,7 +154,6 @@ bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { PADDLE_ENFORCE_EQ(value.dims()[0], static_cast(1), "The first dim of value should be 1."); auto index = Index(key); - platform::Place cpu = platform::CPUPlace(); bool is_new_key = false; if (index == -1) { rows_.push_back(key); @@ -176,7 +170,7 @@ bool SelectedRows::Set(int64_t key, const framework::Tensor& value) { framework::VisitDataType( framework::ToDataType(value.type()), - TensorCopyVisitor(cpu, value_.get(), + TensorCopyVisitor(value_.get(), index * value_->numel() / value_->dims()[0], value, static_cast(0), value.numel())); return is_new_key; diff --git a/paddle/fluid/framework/selected_rows.h b/paddle/fluid/framework/selected_rows.h index cef3ddab47..d6c9507b16 100644 --- a/paddle/fluid/framework/selected_rows.h +++ b/paddle/fluid/framework/selected_rows.h @@ -19,6 +19,7 @@ limitations under the License. */ #include "paddle/fluid/framework/lod_tensor.h" #include "paddle/fluid/framework/tensor.h" +#include "paddle/fluid/memory/memcpy.h" namespace paddle { namespace framework {