Skip to content

Commit ac73900

Browse files
authored
enhance/add lod check (#7439)
1 parent 3dc72a2 commit ac73900

File tree

3 files changed

+139
-30
lines changed

3 files changed

+139
-30
lines changed

paddle/framework/lod_tensor.cc

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,65 @@ bool operator==(const LoD &a, const LoD &b) {
135135
return true;
136136
}
137137

138+
bool CheckLoD(const LoD &in, int tensor_height) {
139+
if (in.empty()) return true;
140+
for (const auto &level : in) {
141+
// check: there should be more than 2 offsets existing in each level.
142+
if (level.size() < 2) return false;
143+
// check: the first offset(the begin offset) of each level should be 0.
144+
if (level.front() != 0) return false;
145+
// check: all the offsets in a level should be ascending(no same items
146+
// allows).
147+
if (!std::is_sorted(level.begin(), level.begin(), [](size_t a, size_t b) {
148+
if (a < b) return true;
149+
return false;
150+
})) {
151+
LOG(INFO) << "ascending error";
152+
return false;
153+
}
154+
}
155+
// check: the lowest level's last offset should equals `tensor_height` if
156+
// tensor_height>0.
157+
if (tensor_height > 0 && (size_t)tensor_height != in.back().back())
158+
return false;
159+
160+
// check: the higher level's last offset should equals the lower level's
161+
// size-1.
162+
// NOTE LoD store the levels from top to bottom, so the higher level goes
163+
// first.
164+
for (size_t level = 0; level < in.size() - 1; level++) {
165+
if (in[level].back() != in[level + 1].size() - 1) return false;
166+
}
167+
return true;
168+
}
169+
170+
bool CheckAbsLoD(const LoD &in, int tensor_height) {
171+
if (in.empty()) return true;
172+
for (const auto &level : in) {
173+
// check: all the offsets in a level should be ascending(no same items
174+
// allows).
175+
if (!std::is_sorted(level.begin(), level.begin(), [](size_t a, size_t b) {
176+
if (a < b) return true;
177+
return false;
178+
})) {
179+
return false;
180+
}
181+
182+
// check: there should be more than 2 offsets existing in each level.
183+
if (level.size() < 2) return false;
184+
185+
// check: the first offset of each level should be 0, and the last should be
186+
// the same(the height of underlying tensor).
187+
if (level.front() != 0) return false;
188+
if (tensor_height < 0) {
189+
tensor_height = level.back();
190+
} else if ((size_t)tensor_height != level.back()) {
191+
return false;
192+
}
193+
}
194+
return true;
195+
}
196+
138197
using LoDAndOffset = std::pair<LoD, std::pair<size_t, size_t>>;
139198
LoDAndOffset GetSubLoDAndAbsoluteOffset(const LoD &lod, size_t start_idx,
140199
size_t end_idx, size_t start_level) {

paddle/framework/lod_tensor.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,38 @@ LoD ToAbsOffset(const LoD& in);
7171

7272
bool operator==(const LoD& a, const LoD& b);
7373

74+
/*
75+
* Check whether this lod's format is valid.
76+
*
77+
* ATTENTION:
78+
* - Empty lod is treated as valid.
79+
*
80+
* It will check two things:
81+
*
82+
* 1. all the offsets in a level should be ascending(no same items allows).
83+
* 2. there should be more than 2 offsets existing in each level.
84+
* 3. the higher level's last offset should equals the lower level's size-1.
85+
* 4. the first offset(the begin offset) of each level should be 0.
86+
* 5. the lowest level's last offset should equals `tensor_height` if
87+
* tensor_height>0.
88+
*/
89+
90+
bool CheckLoD(const LoD& in, int tensor_height = -1);
91+
/*
92+
* Check whether this absolute lod's format is valid.
93+
*
94+
* ATTENTION:
95+
* - Empty lod is treated as valid.
96+
*
97+
* It will check two things:
98+
* 1. all the offsets in a level should be ascending(no same items allows)
99+
* 2. there should be more than 2 offsets existing in each level.
100+
* 3. the first offset of each level should be 0, and the last should be the
101+
* same(the height of underlying tensor) or `tensor_height` if
102+
* tensor_height>0.
103+
*/
104+
bool CheckAbsLoD(const LoD& in, int tensor_height = -1);
105+
74106
/*
75107
* LoDTensor (Level of details Tensor)
76108
* see https://en.wikipedia.org/wiki/Level_of_details for reference.

paddle/framework/lod_tensor_test.cc

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,36 +37,6 @@ namespace framework {
3737

3838
const int kLodTensorSize = 20 * 128;
3939

40-
class LoDTensorTester : public ::testing::Test {
41-
public:
42-
virtual void SetUp() override {
43-
// tensor's batch_size: 30
44-
// 3 levels
45-
// 0 10 20
46-
// 0 5 10 15 20
47-
// 0 2 5 7 10 12 15 20
48-
LoD lod;
49-
lod.push_back(std::vector<size_t>{0, 2, 3});
50-
lod.push_back(std::vector<size_t>{0, 2, 5, 8});
51-
lod.push_back(std::vector<size_t>{0, 2, 5, 7, 10, 12, 15, 17, 20});
52-
53-
ASSERT_EQ(lod.size(), 3UL);
54-
55-
lod_tensor_.Resize({20 /*batch size*/, 128 /*dim*/});
56-
// malloc memory
57-
float* dst_ptr = lod_tensor_.mutable_data<float>(place);
58-
for (int i = 0; i < kLodTensorSize; ++i) {
59-
dst_ptr[i] = i;
60-
}
61-
62-
lod_tensor_.set_lod(lod);
63-
}
64-
65-
protected:
66-
platform::CPUPlace place;
67-
LoDTensor lod_tensor_;
68-
};
69-
7040
TEST(LodExpand, test) {
7141
LoD lod{{0, 2}};
7242
LoDTensor tensor;
@@ -144,5 +114,53 @@ TEST(LoD, ToAbsOffset) {
144114
EXPECT_EQ(abs_lod, expected);
145115
}
146116

117+
TEST(LoD, CheckLoD) {
118+
LoD relative_lod;
119+
relative_lod.push_back(std::vector<size_t>({0, 2}));
120+
relative_lod.push_back(std::vector<size_t>({0, 1, 3}));
121+
relative_lod.push_back(std::vector<size_t>({0, 2, 4, 5}));
122+
123+
// check compatible
124+
ASSERT_TRUE(CheckLoD(relative_lod));
125+
relative_lod[1].back()++;
126+
ASSERT_FALSE(CheckLoD(relative_lod));
127+
relative_lod[1].back()--; // recover it
128+
129+
// check empty
130+
LoD empty_lod;
131+
ASSERT_TRUE(CheckLoD(empty_lod));
132+
133+
// check less than 2 offsets in a level
134+
LoD some_lod0;
135+
some_lod0.push_back(std::vector<size_t>({0}));
136+
ASSERT_FALSE(CheckLoD(some_lod0));
137+
138+
// check with underlying tensor storage.
139+
ASSERT_TRUE(CheckLoD(relative_lod, 5));
140+
ASSERT_FALSE(CheckLoD(relative_lod, 9));
141+
}
142+
143+
TEST(LoD, CheckAbsLoD) {
144+
LoD relative_lod;
145+
relative_lod.push_back(std::vector<size_t>({0, 2}));
146+
relative_lod.push_back(std::vector<size_t>({0, 1, 3}));
147+
relative_lod.push_back(std::vector<size_t>({0, 2, 4, 5}));
148+
149+
auto abs_lod = ToAbsOffset(relative_lod);
150+
151+
ASSERT_TRUE(CheckAbsLoD(abs_lod));
152+
153+
// check less than 2 offsets in a level.
154+
155+
// check the last item should be compatible with tensor height.
156+
abs_lod.back().back()++;
157+
ASSERT_FALSE(CheckAbsLoD(abs_lod));
158+
abs_lod.back().back()--; // restore
159+
160+
// check less than 2 offsets in a lod.
161+
LoD abs_lod0;
162+
abs_lod0.push_back(std::vector<size_t>({0}));
163+
ASSERT_FALSE(CheckAbsLoD(abs_lod0));
164+
}
147165
} // namespace framework
148166
} // namespace paddle

0 commit comments

Comments
 (0)