Skip to content

Commit 47622d7

Browse files
authored
Merge pull request #7624 from tonyyang-svail/7450
Make merge and split support lodtensor
2 parents 259fcc3 + d002f60 commit 47622d7

File tree

2 files changed

+111
-22
lines changed

2 files changed

+111
-22
lines changed

paddle/framework/lod_tensor.cc

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -286,62 +286,86 @@ void DeserializeFromStream(std::istream &is, LoDTensor *tensor,
286286
DeserializeFromStream(is, static_cast<Tensor *>(tensor), dev_ctx);
287287
}
288288

289-
// TODO(tonyyang-svail): make this function support LoD
290289
std::vector<LoDTensor> LoDTensor::SplitLoDTensor(
291290
const std::vector<platform::Place> places) const {
292291
check_memory_size();
293-
PADDLE_ENFORCE(lod().empty(), "Disable parallel lod for now");
294-
size_t result_size = std::min(static_cast<size_t>(dims()[0]), places.size());
295-
size_t remainder = dims()[0] % places.size();
292+
int batch_size =
293+
lod().empty() ? dims()[0] : static_cast<int>(lod()[0].size()) - 1;
294+
size_t result_size = std::min(static_cast<size_t>(batch_size), places.size());
295+
size_t remainder = batch_size % places.size();
296296

297297
std::vector<LoDTensor> results;
298298
results.reserve(result_size);
299299

300-
int step_width = static_cast<int>(dims()[0] / result_size);
300+
int step_width = static_cast<int>(batch_size / result_size);
301301
for (size_t i = 0; i < result_size; ++i) {
302302
int begin = static_cast<int>(i * step_width);
303303
int end = static_cast<int>((i + 1) * step_width);
304304
if (i + 1 == places.size()) { // last
305305
end += remainder;
306306
}
307307

308-
auto src = Slice(begin, end);
309-
auto &dst_place = places[i];
310308
LoDTensor dst;
311-
if (!(dst_place == place())) {
309+
if (lod().empty()) {
310+
auto src = Slice(begin, end);
311+
auto &dst_place = places[i];
312312
framework::Copy(src, dst_place, &dst);
313-
} else { // It is no need to copy if src_place and dst_place are same.
314-
dst.ShareDataWith(src);
313+
} else {
314+
auto lod_and_offset = GetSubLoDAndAbsoluteOffset(lod(), begin, end, 0);
315+
316+
auto &offset = lod_and_offset.second;
317+
auto src = Slice(offset.first, offset.second);
318+
auto &dst_place = places[i];
319+
framework::Copy(src, dst_place, &dst);
320+
321+
LoD my_lod;
322+
for (auto &l : lod_and_offset.first) {
323+
std::vector<size_t> v{0};
324+
for (auto &ll : l) {
325+
v.push_back(ll + v.back());
326+
}
327+
my_lod.emplace_back(v);
328+
}
329+
dst.set_lod(my_lod);
315330
}
316331
results.emplace_back(dst);
317332
}
318333

319334
return results;
320335
}
321336

322-
// TODO(tonyyang-svail): make this function support LoD
323337
void LoDTensor::MergeLoDTensor(
324338
const std::vector<const LoDTensor *> &lod_tensors,
325339
platform::Place dst_place) {
326340
PADDLE_ENFORCE(!lod_tensors.empty());
341+
327342
framework::DDim new_dim = lod_tensors[0]->dims();
328343
std::type_index new_type = lod_tensors[0]->type();
329-
auto new_layout = lod_tensors[0]->layout();
330-
int64_t new_height = 0;
331-
for (auto *lod : lod_tensors) {
332-
new_height += lod->dims()[0];
333-
for (int i = 1; i < new_dim.size(); ++i) {
334-
PADDLE_ENFORCE_EQ(new_dim[i], lod->dims()[i]);
344+
framework::DataLayout new_layout = lod_tensors[0]->layout();
345+
LoD new_lod = lod_tensors[0]->lod();
346+
for (size_t i = 1; i < lod_tensors.size(); ++i) {
347+
auto *t = lod_tensors[i];
348+
PADDLE_ENFORCE_EQ(new_type.hash_code(), t->type().hash_code());
349+
PADDLE_ENFORCE_EQ(new_layout, t->layout());
350+
351+
PADDLE_ENFORCE_EQ(framework::product(new_dim) / new_dim[0],
352+
framework::product(t->dims()) / t->dims()[0]);
353+
new_dim[0] += t->dims()[0];
354+
355+
auto &lod = t->lod();
356+
for (size_t j = 0; j < lod.size(); ++j) {
357+
auto &sub_lod = new_lod[j];
358+
auto &offset = sub_lod.back();
359+
for (size_t k = 1; k < lod[j].size(); ++k) {
360+
sub_lod.push_back(lod[j][k] + offset);
361+
}
335362
}
336-
337-
PADDLE_ENFORCE_EQ(new_type, lod->type());
338-
PADDLE_ENFORCE_EQ(new_layout, lod->layout());
339363
}
340-
new_dim[0] = new_height;
341364
Resize(new_dim);
342365
set_layout(new_layout);
343-
366+
set_lod(new_lod);
344367
mutable_data(dst_place, new_type);
368+
345369
int begin = 0;
346370
for (auto *src : lod_tensors) {
347371
int end = begin + src->dims()[0];

paddle/framework/lod_tensor_test.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,71 @@ TEST(LoD, ToAbsOffset) {
100100
EXPECT_EQ(abs_lod, expected);
101101
}
102102

103+
TEST(LoD, SplitLoDTensor) {
104+
LoD lod;
105+
lod.push_back(std::vector<size_t>({0, 2, 4, 5, 6}));
106+
lod.push_back(std::vector<size_t>({0, 1, 6, 8, 13, 15, 20}));
107+
108+
platform::CPUPlace place;
109+
LoDTensor lod_tensor;
110+
lod_tensor.Resize({20, 1});
111+
float* dst_ptr = lod_tensor.mutable_data<float>(place);
112+
for (int i = 0; i < lod_tensor.numel(); ++i) {
113+
dst_ptr[i] = i;
114+
}
115+
lod_tensor.set_lod(lod);
116+
117+
std::vector<platform::Place> places{platform::CPUPlace(),
118+
platform::CPUPlace()};
119+
LoD lod0;
120+
lod0.push_back(std::vector<size_t>({0, 2, 4}));
121+
lod0.push_back(std::vector<size_t>({0, 1, 6, 8, 13}));
122+
LoD lod1;
123+
lod1.push_back(std::vector<size_t>({0, 1, 2}));
124+
lod1.push_back(std::vector<size_t>({0, 2, 7}));
125+
126+
auto lods = lod_tensor.SplitLoDTensor(places);
127+
EXPECT_EQ(lods[0].lod(), lod0);
128+
EXPECT_EQ(lods[1].lod(), lod1);
129+
}
130+
131+
TEST(LoD, MergeLoDTensor) {
132+
LoD lod;
133+
lod.push_back(std::vector<size_t>({0, 2, 4, 5, 6}));
134+
lod.push_back(std::vector<size_t>({0, 1, 6, 8, 13, 15, 20}));
135+
136+
platform::CPUPlace place;
137+
138+
LoDTensor lod_tensor0;
139+
LoD lod0;
140+
lod0.push_back(std::vector<size_t>({0, 2, 4}));
141+
lod0.push_back(std::vector<size_t>({0, 1, 6, 8, 13}));
142+
lod_tensor0.set_lod(lod0);
143+
144+
lod_tensor0.Resize({13, 1});
145+
float* dst_ptr = lod_tensor0.mutable_data<float>(place);
146+
for (int i = 0; i < lod_tensor0.numel(); ++i) {
147+
dst_ptr[i] = i;
148+
}
149+
150+
LoDTensor lod_tensor1;
151+
LoD lod1;
152+
lod1.push_back(std::vector<size_t>({0, 1, 2}));
153+
lod1.push_back(std::vector<size_t>({0, 2, 7}));
154+
lod_tensor1.set_lod(lod1);
155+
lod_tensor1.Resize({7, 1});
156+
dst_ptr = lod_tensor1.mutable_data<float>(place);
157+
for (int i = 0; i < lod_tensor1.numel(); ++i) {
158+
dst_ptr[i] = i;
159+
}
160+
161+
std::vector<const LoDTensor*> lods{&lod_tensor0, &lod_tensor1};
162+
163+
LoDTensor lod_tensor;
164+
lod_tensor.MergeLoDTensor(lods, place);
165+
EXPECT_EQ(lod_tensor.lod(), lod);
166+
}
167+
103168
TEST(LoD, CheckLoD) {
104169
LoD relative_lod;
105170
relative_lod.push_back(std::vector<size_t>({0, 2}));

0 commit comments

Comments
 (0)