Support Convolution, Deconvolution, and Fully Connected operators without bias
PiperOrigin-RevId: 277524405
diff --git a/test/convolution-operator-tester.h b/test/convolution-operator-tester.h
index e637fac..115b846 100644
--- a/test/convolution-operator-tester.h
+++ b/test/convolution-operator-tester.h
@@ -467,6 +467,15 @@
return this->depthwise_layout_;
}
+ inline ConvolutionOperatorTester& has_bias(bool has_bias) {
+ this->has_bias_ = has_bias;
+ return *this;
+ }
+
+ inline bool has_bias() const {
+ return this->has_bias_;
+ }
+
inline ConvolutionOperatorTester& iterations(size_t iterations) {
this->iterations_ = iterations;
return *this;
@@ -500,17 +509,21 @@
std::fill(output.begin(), output.end(), 0xA5);
// Compute reference results, without renormalization.
- for (size_t i = 0; i < batch_size(); i++) {
- for (size_t oy = 0; oy < output_height(); oy++) {
- for (size_t ox = 0; ox < output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- accumulators[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < batch_size(); i++) {
+ for (size_t oy = 0; oy < output_height(); oy++) {
+ for (size_t ox = 0; ox < output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ accumulators[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(accumulators.begin(), accumulators.end(), 0);
}
if (depthwise_layout()) {
ASSERT_EQ(group_input_channels(), 1);
@@ -596,7 +609,7 @@
input_pixel_stride(), output_pixel_stride(),
input_zero_point, 1.0f /* input scale */,
kernel_zero_point, 1.0f /* kernel scale */,
- kernel.data(), bias.data(),
+ kernel.data(), has_bias() ? bias.data() : nullptr,
output_zero_point, output_scale, qmin(), qmax(),
(depthwise_layout() ? XNN_FLAG_DEPTHWISE_CONVOLUTION : 0) | (padding_tf_same() ? XNN_FLAG_TENSORFLOW_SAME_PADDING : 0),
&convolution_op));
@@ -656,17 +669,21 @@
std::fill(output.begin(), output.end(), nanf(""));
// Compute reference results, without clamping.
- for (size_t i = 0; i < batch_size(); i++) {
- for (size_t oy = 0; oy < output_height(); oy++) {
- for (size_t ox = 0; ox < output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- output_ref[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < batch_size(); i++) {
+ for (size_t oy = 0; oy < output_height(); oy++) {
+ for (size_t ox = 0; ox < output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ output_ref[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(output_ref.begin(), output_ref.end(), 0.0f);
}
if (depthwise_layout()) {
ASSERT_EQ(group_input_channels(), 1);
@@ -747,7 +764,7 @@
dilation_height(), dilation_width(),
groups(), group_input_channels(), group_output_channels(),
input_pixel_stride(), output_pixel_stride(),
- kernel.data(), bias.data(),
+ kernel.data(), has_bias() ? bias.data() : nullptr,
output_min, output_max,
(depthwise_layout() ? XNN_FLAG_DEPTHWISE_CONVOLUTION : 0) | (padding_tf_same() ? XNN_FLAG_TENSORFLOW_SAME_PADDING : 0),
&convolution_op));
@@ -819,17 +836,21 @@
std::fill(output.begin(), output.end(), 0xA5);
// Compute reference results, without renormalization.
- for (size_t i = 0; i < batch_size(); i++) {
- for (size_t oy = 0; oy < output_height(); oy++) {
- for (size_t ox = 0; ox < output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- accumulators[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < batch_size(); i++) {
+ for (size_t oy = 0; oy < output_height(); oy++) {
+ for (size_t ox = 0; ox < output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ accumulators[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(accumulators.begin(), accumulators.end(), 0);
}
for (size_t i = 0; i < batch_size(); i++) {
for (size_t oy = 0; oy < output_height(); oy++) {
@@ -886,7 +907,7 @@
input_pixel_stride(), output_pixel_stride(),
input_zero_point, 1.0f /* input scale */,
kernel_zero_point, 1.0f /* kernel scale */,
- kernel.data(), bias.data(),
+ kernel.data(), has_bias() ? bias.data() : nullptr,
output_zero_point, output_scale, qmin(), qmax(),
0, &convolution_op));
@@ -929,17 +950,21 @@
std::fill(output.begin(), output.end(), 0xA5);
// Compute reference results for the second run, including renormalization.
- for (size_t i = 0; i < next_batch_size(); i++) {
- for (size_t oy = 0; oy < next_output_height(); oy++) {
- for (size_t ox = 0; ox < next_output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- next_accumulators[(((i * next_output_height() + oy) * next_output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < next_batch_size(); i++) {
+ for (size_t oy = 0; oy < next_output_height(); oy++) {
+ for (size_t ox = 0; ox < next_output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ next_accumulators[(((i * next_output_height() + oy) * next_output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(next_accumulators.begin(), next_accumulators.end(), 0);
}
for (size_t i = 0; i < next_batch_size(); i++) {
for (size_t oy = 0; oy < next_output_height(); oy++) {
@@ -1030,17 +1055,21 @@
std::fill(output.begin(), output.end(), nanf(""));
// Compute reference results, without clamping.
- for (size_t i = 0; i < batch_size(); i++) {
- for (size_t oy = 0; oy < output_height(); oy++) {
- for (size_t ox = 0; ox < output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- output_ref[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < batch_size(); i++) {
+ for (size_t oy = 0; oy < output_height(); oy++) {
+ for (size_t ox = 0; ox < output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ output_ref[(((i * output_height() + oy) * output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(output_ref.begin(), output_ref.end(), 0.0f);
}
for (size_t i = 0; i < batch_size(); i++) {
for (size_t oy = 0; oy < output_height(); oy++) {
@@ -1092,7 +1121,7 @@
dilation_height(), dilation_width(),
groups(), group_input_channels(), group_output_channels(),
input_pixel_stride(), output_pixel_stride(),
- kernel.data(), bias.data(),
+ kernel.data(), has_bias() ? bias.data() : nullptr,
output_min, output_max,
0, &convolution_op));
@@ -1135,17 +1164,21 @@
std::fill(output.begin(), output.end(), nanf(""));
// Compute reference results for the second run, including clamping.
- for (size_t i = 0; i < next_batch_size(); i++) {
- for (size_t oy = 0; oy < next_output_height(); oy++) {
- for (size_t ox = 0; ox < next_output_width(); ox++) {
- for (size_t g = 0; g < groups(); g++) {
- for (size_t oc = 0; oc < group_output_channels(); oc++) {
- next_output_ref[(((i * next_output_height() + oy) * next_output_width() + ox) * groups() + g) * group_output_channels() + oc] =
- bias[g * group_output_channels() + oc];
+ if (has_bias()) {
+ for (size_t i = 0; i < next_batch_size(); i++) {
+ for (size_t oy = 0; oy < next_output_height(); oy++) {
+ for (size_t ox = 0; ox < next_output_width(); ox++) {
+ for (size_t g = 0; g < groups(); g++) {
+ for (size_t oc = 0; oc < group_output_channels(); oc++) {
+ next_output_ref[(((i * next_output_height() + oy) * next_output_width() + ox) * groups() + g) * group_output_channels() + oc] =
+ bias[g * group_output_channels() + oc];
+ }
}
}
}
}
+ } else {
+ std::fill(next_output_ref.begin(), next_output_ref.end(), 0.0f);
}
for (size_t i = 0; i < next_batch_size(); i++) {
for (size_t oy = 0; oy < next_output_height(); oy++) {
@@ -1236,5 +1269,6 @@
uint8_t qmin_{0};
uint8_t qmax_{255};
bool depthwise_layout_{false};
+ bool has_bias_{true};
size_t iterations_{1};
};