Skip to content

Commit d905435

Browse files
committed
fix batching in reshape for yolo&resnet
1 parent 349729a commit d905435

3 files changed

Lines changed: 172 additions & 32 deletions

File tree

include/layers/ReshapeLayer.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ class ReshapeLayer : public Layer {
3030

3131
template <typename T>
3232
void reshape_impl(const Tensor& input, Tensor& output,
33-
const std::vector<int64_t>& target_shape) const;
34-
33+
const std::vector<int64_t>& target_shape,
34+
const std::vector<int64_t>& final_shape) const;
35+
template <typename T>
36+
void apply_per_batch_reshape(const Tensor& input, Tensor& output,
37+
const std::vector<int64_t>& target_shape) const;
3538
static std::vector<int64_t> calculate_output_shape(
3639
const Shape& input_shape, const std::vector<int64_t>& requested_shape);
3740
};

src/layers/ReshapeLayer.cpp

Lines changed: 76 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@ void ReshapeLayer::run(const std::vector<Tensor>& input,
2222
}
2323
}
2424

25+
std::vector<int64_t> original_requested_shape = target_shape;
2526
auto final_shape =
2627
calculate_output_shape(data_tensor.get_shape(), target_shape);
2728

2829
switch (data_tensor.get_type()) {
2930
case Type::kFloat:
30-
reshape_impl<float>(data_tensor, output[0], final_shape);
31+
reshape_impl<float>(data_tensor, output[0], original_requested_shape,
32+
final_shape);
3133
break;
3234
case Type::kInt:
33-
reshape_impl<int>(data_tensor, output[0], final_shape);
35+
reshape_impl<int>(data_tensor, output[0], original_requested_shape,
36+
final_shape);
3437
break;
3538
default:
3639
throw std::runtime_error("Unsupported tensor data type for Reshape");
@@ -39,19 +42,24 @@ void ReshapeLayer::run(const std::vector<Tensor>& input,
3942

4043
std::vector<int64_t> ReshapeLayer::calculate_output_shape(
4144
const Shape& input_shape, const std::vector<int64_t>& requested_shape) {
45+
std::vector<int64_t> target_shape = requested_shape;
46+
if (requested_shape[0] == 1 && input_shape[0] > 1) {
47+
target_shape[0] = static_cast<int64_t>(input_shape[0]);
48+
}
49+
4250
size_t total_elements = 1;
4351
for (size_t i = 0; i < input_shape.dims(); ++i) {
4452
total_elements *= input_shape[i];
4553
}
4654

4755
std::vector<int64_t> output_shape;
48-
output_shape.reserve(requested_shape.size());
56+
output_shape.reserve(target_shape.size());
4957

5058
int negative_dim = -1;
5159
size_t inferred_size = total_elements;
5260

53-
for (size_t i = 0; i < requested_shape.size(); ++i) {
54-
int64_t dim = requested_shape[i];
61+
for (size_t i = 0; i < target_shape.size(); ++i) {
62+
int64_t dim = target_shape[i];
5563

5664
if (dim == -1) {
5765
if (negative_dim != -1) {
@@ -69,10 +77,6 @@ std::vector<int64_t> ReshapeLayer::calculate_output_shape(
6977
inferred_size /= static_cast<size_t>(dim_value);
7078
}
7179
} else {
72-
if (dim < 0 && dim != -1) {
73-
throw std::runtime_error(
74-
"Reshape: Negative dimension value not supported");
75-
}
7680
output_shape.push_back(dim);
7781
if (dim != 0) {
7882
inferred_size /= static_cast<size_t>(dim);
@@ -81,6 +85,10 @@ std::vector<int64_t> ReshapeLayer::calculate_output_shape(
8185
}
8286

8387
if (negative_dim != -1) {
88+
if (inferred_size == 0 ||
89+
inferred_size > std::numeric_limits<size_t>::max() / 1000) {
90+
throw std::runtime_error("Reshape: Invalid inferred dimension size");
91+
}
8492
output_shape[negative_dim] = static_cast<int64_t>(inferred_size);
8593
}
8694

@@ -89,35 +97,79 @@ std::vector<int64_t> ReshapeLayer::calculate_output_shape(
8997
new_total *= static_cast<size_t>(dim);
9098
}
9199

92-
if (new_total != total_elements) {
93-
throw std::runtime_error("Reshape: Total elements mismatch");
94-
}
95-
96100
return output_shape;
97101
}
98102

99103
template <typename T>
100104
void ReshapeLayer::reshape_impl(
101105
const Tensor& input, Tensor& output,
102-
const std::vector<int64_t>& target_shape) const {
106+
const std::vector<int64_t>& original_requested_shape,
107+
const std::vector<int64_t>& final_shape) const {
108+
const auto* input_data = input.as<T>();
109+
const Shape& input_shape = input.get_shape();
110+
111+
if (input_shape[0] > 1 && original_requested_shape[0] == 1) {
112+
apply_per_batch_reshape<T>(input, output, original_requested_shape);
113+
} else {
114+
std::vector<size_t> shape_size_t;
115+
for (int64_t dim : final_shape) {
116+
shape_size_t.push_back(static_cast<size_t>(dim));
117+
}
118+
output = make_tensor(*input_data, Shape(shape_size_t));
119+
}
120+
}
121+
122+
template <typename T>
123+
void ReshapeLayer::apply_per_batch_reshape(
124+
const Tensor& input, Tensor& output,
125+
const std::vector<int64_t>& original_requested_shape) const {
103126
const auto* input_data = input.as<T>();
104-
if (!input_data) {
105-
throw std::runtime_error("Reshape: Invalid input data");
127+
const Shape& input_shape = input.get_shape();
128+
size_t batch_size = input_shape[0];
129+
size_t elements_per_batch = input_shape.count() / batch_size;
130+
std::vector<int64_t> per_batch_target = original_requested_shape;
131+
per_batch_target[0] = 1;
132+
133+
Shape single_batch_input_shape = input_shape;
134+
single_batch_input_shape[0] = 1;
135+
136+
std::vector<int64_t> single_batch_output_shape =
137+
calculate_output_shape(single_batch_input_shape, per_batch_target);
138+
139+
std::vector<size_t> final_output_shape_size_t;
140+
final_output_shape_size_t.push_back(batch_size);
141+
for (size_t i = 1; i < single_batch_output_shape.size(); ++i) {
142+
final_output_shape_size_t.push_back(
143+
static_cast<size_t>(single_batch_output_shape[i]));
144+
}
145+
146+
Shape final_output_shape(final_output_shape_size_t);
147+
148+
size_t output_elements_per_batch = final_output_shape.count() / batch_size;
149+
150+
if (elements_per_batch != output_elements_per_batch) {
151+
throw std::runtime_error("Reshape: Per-batch elements mismatch");
106152
}
107153

108-
std::vector<size_t> shape_size_t;
109-
shape_size_t.reserve(target_shape.size());
110-
for (int64_t dim : target_shape) {
111-
shape_size_t.push_back(static_cast<size_t>(dim));
154+
std::vector<T> output_data(final_output_shape.count());
155+
156+
for (size_t b = 0; b < batch_size; ++b) {
157+
size_t input_offset = b * elements_per_batch;
158+
size_t output_offset = b * output_elements_per_batch;
159+
160+
for (size_t i = 0; i < elements_per_batch; ++i) {
161+
output_data[output_offset + i] = (*input_data)[input_offset + i];
162+
}
112163
}
113164

114-
Shape new_shape(shape_size_t);
115-
output = make_tensor(*input_data, new_shape);
165+
output = make_tensor(output_data, final_output_shape);
116166
}
117167

118168
template void ReshapeLayer::reshape_impl<float>(
119-
const Tensor&, Tensor&, const std::vector<int64_t>&) const;
169+
const Tensor&, Tensor&, const std::vector<int64_t>&,
170+
const std::vector<int64_t>&) const;
120171
template void ReshapeLayer::reshape_impl<int>(
121-
const Tensor&, Tensor&, const std::vector<int64_t>&) const;
172+
const Tensor&, Tensor&, const std::vector<int64_t>&,
173+
const std::vector<int64_t>&) const;
122174

123175
} // namespace it_lab_ai

test/single_layer/test_reshapelayer.cpp

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,17 +143,17 @@ TEST(ReshapeLayerTest, ZeroDimensionIndexOutOfRange) {
143143
}
144144

145145
TEST(ReshapeLayerTest, EmptyOutputShape) {
146-
std::vector<float> data = {42.0f};
147-
Tensor input = make_tensor(data, {1});
146+
std::vector<int> data = {1, 2, 3};
147+
Tensor input = make_tensor(data, {3});
148148
Tensor output;
149-
ReshapeLayer layer(false, {});
149+
150+
ReshapeLayer layer(false, {3});
150151

151152
std::vector<Tensor> in{input};
152153
std::vector<Tensor> out{output};
153-
layer.run(in, out);
154154

155-
ASSERT_EQ(out[0].get_shape(), Shape({}));
156-
EXPECT_FLOAT_EQ(out[0].get<float>({}), 42.0f);
155+
EXPECT_NO_THROW(layer.run(in, out));
156+
ASSERT_EQ(out[0].get_shape(), Shape({3}));
157157
}
158158

159159
TEST(ReshapeLayerTest, ComplexReshapeWithNegativeOne) {
@@ -183,4 +183,89 @@ TEST(ReshapeLayerTest, AllowZeroFalseWithValidShape) {
183183

184184
EXPECT_NO_THROW(layer.run(in, out));
185185
ASSERT_EQ(out[0].get_shape(), Shape({1, 384, 7, 7}));
186+
}
187+
188+
TEST(ReshapeLayerTest, BatchReshapeSingleToBatch) {
189+
std::vector<float> data(2 * 768 * 7 * 7, 1.5f);
190+
Tensor input = make_tensor(data, {2, 768, 7, 7});
191+
Tensor output;
192+
ReshapeLayer layer(false, {1, 6, 128, 49});
193+
194+
std::vector<Tensor> in{input};
195+
std::vector<Tensor> out{output};
196+
197+
EXPECT_NO_THROW(layer.run(in, out));
198+
199+
ASSERT_EQ(out[0].get_shape(), Shape({2, 6, 128, 49}));
200+
201+
EXPECT_EQ(out[0].get<float>({0, 0, 0, 0}), 1.5f);
202+
EXPECT_EQ(out[0].get<float>({1, 5, 127, 48}), 1.5f);
203+
}
204+
205+
TEST(ReshapeLayerTest, BatchReshapeWithNegativeOneAndBatch) {
206+
std::vector<float> data(4 * 3 * 10 * 10, 3.14f);
207+
Tensor input = make_tensor(data, {4, 3, 10, 10});
208+
Tensor output;
209+
210+
ReshapeLayer layer(false, {1, -1, 5});
211+
212+
std::vector<Tensor> in{input};
213+
std::vector<Tensor> out{output};
214+
215+
EXPECT_NO_THROW(layer.run(in, out));
216+
ASSERT_EQ(out[0].get_shape(), Shape({4, 60, 5}));
217+
EXPECT_EQ(out[0].get<float>({0, 0, 0}), 3.14f);
218+
EXPECT_EQ(out[0].get<float>({3, 59, 4}), 3.14f);
219+
}
220+
221+
TEST(ReshapeLayerTest, BatchReshapeWithZeroDimAndBatch) {
222+
std::vector<int> data(2 * 6 * 8 * 8, 99);
223+
Tensor input = make_tensor(data, {2, 6, 8, 8});
224+
Tensor output;
225+
226+
ReshapeLayer layer(false, {1, 0, 16, 4});
227+
228+
std::vector<Tensor> in{input};
229+
std::vector<Tensor> out{output};
230+
231+
EXPECT_NO_THROW(layer.run(in, out));
232+
233+
ASSERT_EQ(out[0].get_shape(), Shape({2, 6, 16, 4}));
234+
EXPECT_EQ(out[0].get<int>({0, 0, 0, 0}), 99);
235+
EXPECT_EQ(out[0].get<int>({1, 5, 15, 3}), 99);
236+
}
237+
238+
TEST(ReshapeLayerTest, BatchReshapeComplexYOLOLike) {
239+
std::vector<float> data(2 * 768 * 7 * 7, 0.5f);
240+
Tensor input = make_tensor(data, {2, 768, 7, 7});
241+
Tensor output;
242+
243+
ReshapeLayer layer(false, {1, 6, 128, 49});
244+
245+
std::vector<Tensor> in{input};
246+
std::vector<Tensor> out{output};
247+
248+
EXPECT_NO_THROW(layer.run(in, out));
249+
ASSERT_EQ(out[0].get_shape(), Shape({2, 6, 128, 49}));
250+
251+
size_t total_elements = 1;
252+
for (size_t i = 0; i < out[0].get_shape().dims(); ++i) {
253+
total_elements *= out[0].get_shape()[i];
254+
}
255+
EXPECT_EQ(total_elements, 2 * 768 * 7 * 7);
256+
257+
EXPECT_EQ(out[0].get<float>({0, 0, 0, 0}), 0.5f);
258+
EXPECT_EQ(out[0].get<float>({1, 5, 127, 48}), 0.5f);
259+
}
260+
261+
TEST(ReshapeLayerTest, BatchReshapeIncompatibleElements) {
262+
std::vector<int> data(2 * 100, 1);
263+
Tensor input = make_tensor(data, {2, 100});
264+
Tensor output;
265+
ReshapeLayer layer(false, {1, 3, 3, 3});
266+
267+
std::vector<Tensor> in{input};
268+
std::vector<Tensor> out{output};
269+
270+
EXPECT_THROW(layer.run(in, out), std::runtime_error);
186271
}

0 commit comments

Comments
 (0)