aboutsummaryrefslogtreecommitdiff
path: root/src/backends/reference/workloads/TransposeConvolution2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/backends/reference/workloads/TransposeConvolution2d.cpp')
-rw-r--r--src/backends/reference/workloads/TransposeConvolution2d.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/backends/reference/workloads/TransposeConvolution2d.cpp b/src/backends/reference/workloads/TransposeConvolution2d.cpp
new file mode 100644
index 0000000000..db15cefe10
--- /dev/null
+++ b/src/backends/reference/workloads/TransposeConvolution2d.cpp
@@ -0,0 +1,248 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "TransposeConvolution2d.hpp"
+
+#include <DataLayoutIndexed.hpp>
+
+namespace armnn
+{
+
+using namespace armnnUtils;
+
+struct TensorData
+{
+ TensorShape shape;
+ std::vector<float> data;
+};
+
+TensorData SetUpStridedInput(const TensorShape& inputShape,
+ Decoder<float>& inputDecoder,
+ const TransposeConvolution2dDescriptor& descriptor,
+ const DataLayoutIndexed& dataLayoutIndexed)
+{
+ const unsigned int cIndex = dataLayoutIndexed.GetChannelsIndex();
+ const unsigned int hIndex = dataLayoutIndexed.GetHeightIndex();
+ const unsigned int wIndex = dataLayoutIndexed.GetWidthIndex();
+
+ const unsigned int batches = inputShape[0];
+ const unsigned int channels = inputShape[cIndex];
+
+ const unsigned int wInput = inputShape[wIndex];
+ const unsigned int hInput = inputShape[hIndex];
+
+ const unsigned int wStridedInput = 1u + descriptor.m_StrideX * (wInput - 1);
+ const unsigned int hStridedInput = 1u + descriptor.m_StrideY * (hInput - 1);
+
+ TensorData stridedInput;
+ stridedInput.data = std::vector<float>(batches * channels * wStridedInput * hStridedInput, 0.0f);
+ stridedInput.shape = TensorShape(4);
+
+ stridedInput.shape[0] = batches;
+ stridedInput.shape[cIndex] = channels;
+ stridedInput.shape[hIndex] = hStridedInput;
+ stridedInput.shape[wIndex] = wStridedInput;
+
+ // expand input data with strides
+ for (unsigned int batchIdx = 0u; batchIdx < batches; ++batchIdx)
+ {
+ for (unsigned int cInput = 0u; cInput < channels; ++cInput)
+ {
+ for (unsigned int yInput = 0u, yStrided = 0u;
+ yInput < hInput && yStrided < hStridedInput;
+ ++yInput, yStrided += descriptor.m_StrideY)
+ {
+ for (unsigned int xInput = 0u, xStrided = 0u;
+ xInput < wInput && xStrided < wStridedInput;
+ ++xInput, xStrided += descriptor.m_StrideX)
+ {
+ unsigned int inputIdx =
+ dataLayoutIndexed.GetIndex(inputShape, batchIdx, cInput, yInput, xInput);
+ unsigned int stridedInputIdx =
+ dataLayoutIndexed.GetIndex(stridedInput.shape, batchIdx, cInput, yStrided, xStrided);
+
+ inputDecoder[inputIdx];
+ stridedInput.data[stridedInputIdx] = inputDecoder.Get();
+ }
+ }
+ }
+ }
+
+ return stridedInput;
+}
+
+TensorData SetUpEmptyPaddedOutput(const TensorShape& outputShape,
+ const TransposeConvolution2dDescriptor& descriptor,
+ const DataLayoutIndexed& dataLayoutIndexed)
+{
+ const unsigned int cIndex = dataLayoutIndexed.GetChannelsIndex();
+ const unsigned int hIndex = dataLayoutIndexed.GetHeightIndex();
+ const unsigned int wIndex = dataLayoutIndexed.GetWidthIndex();
+
+ const unsigned int batches = outputShape[0];
+ const unsigned int channels = outputShape[cIndex];
+
+ const unsigned int wOutput = outputShape[wIndex];
+ const unsigned int hOutput = outputShape[hIndex];
+
+ const unsigned int wPaddedOutput = wOutput + descriptor.m_PadLeft + descriptor.m_PadRight;
+ const unsigned int hPaddedOutput = hOutput + descriptor.m_PadTop + descriptor.m_PadBottom;
+
+ TensorData paddedOutput;
+ paddedOutput.data = std::vector<float>(batches * channels * wPaddedOutput * hPaddedOutput, 0.0f);
+ paddedOutput.shape = TensorShape(4);
+
+ paddedOutput.shape[0] = batches;
+ paddedOutput.shape[cIndex] = channels;
+ paddedOutput.shape[hIndex] = hPaddedOutput;
+ paddedOutput.shape[wIndex] = wPaddedOutput;
+
+ return paddedOutput;
+}
+
+void Deconvolve(const TensorData& stridedInput,
+ TensorData& paddedOutput,
+ const TensorShape& weightsShape,
+ Decoder<float>& weightsDecoder,
+ const DataLayoutIndexed& dataLayoutIndexed)
+{
+ const unsigned int cIndex = dataLayoutIndexed.GetChannelsIndex();
+ const unsigned int hIndex = dataLayoutIndexed.GetHeightIndex();
+ const unsigned int wIndex = dataLayoutIndexed.GetWidthIndex();
+
+ const unsigned int batches = stridedInput.shape[0];
+ const unsigned int channels = stridedInput.shape[cIndex];
+
+ const unsigned int wKernel = weightsShape[wIndex];
+ const unsigned int hKernel = weightsShape[hIndex];
+
+ const unsigned int wStridedInput = stridedInput.shape[wIndex];
+ const unsigned int hStridedInput = stridedInput.shape[hIndex];
+
+ // loop through all input elements
+ for (unsigned int batchIdx = 0u; batchIdx < batches; ++batchIdx)
+ {
+ for (unsigned int cInput = 0u; cInput < channels; ++cInput)
+ {
+ for (unsigned int yInput = 0u; yInput < hStridedInput; ++yInput)
+ {
+ for (unsigned int xInput = 0u; xInput < wStridedInput; ++xInput)
+ {
+ // obtain input value
+ unsigned int inputIdx =
+ dataLayoutIndexed.GetIndex(stridedInput.shape, batchIdx, cInput, yInput, xInput);
+ float inputValue = stridedInput.data[inputIdx];
+
+ // loop through kernel
+ for (unsigned int yKernel = 0u; yKernel < hKernel; ++yKernel)
+ {
+ for (unsigned int xKernel = 0; xKernel < wKernel; ++xKernel)
+ {
+ unsigned int kernelIdx =
+ dataLayoutIndexed.GetIndex(weightsShape, batchIdx, cInput, yKernel, xKernel);
+
+ weightsDecoder[kernelIdx];
+ float kernelValue = weightsDecoder.Get();
+
+ unsigned int xOutput = xInput + xKernel;
+ unsigned int yOutput = yInput + yKernel;
+
+ // compute output increment
+ float outputValue = inputValue * kernelValue;
+
+ unsigned int outputIdx = dataLayoutIndexed.GetIndex(paddedOutput.shape,
+ batchIdx,
+ cInput,
+ yOutput,
+ xOutput);
+
+ // set output value
+ paddedOutput.data[outputIdx] += outputValue;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void TransposeConvolution2dImpl(const TransposeConvolution2dDescriptor& descriptor,
+ const TensorShape& inputShape,
+ Decoder<float>& inputDecoder,
+ const TensorShape& outputShape,
+ Encoder<float>& outputEncoder,
+ const TensorShape& weightsShape,
+ Decoder<float>& weightsDecoder,
+ Decoder<float>* biasesDecoder)
+{
+ if (descriptor.m_BiasEnabled && !biasesDecoder)
+ {
+ throw InvalidArgumentException("Biases enabled but no bias data provided");
+ }
+
+ const DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
+
+ const unsigned int cIndex = dataLayoutIndexed.GetChannelsIndex();
+ const unsigned int hIndex = dataLayoutIndexed.GetHeightIndex();
+ const unsigned int wIndex = dataLayoutIndexed.GetWidthIndex();
+
+ const unsigned int numBatches = inputShape[0];
+ const unsigned int numChannels = inputShape[cIndex];
+
+ // set up temporary strided input
+ TensorData stridedInput = SetUpStridedInput(inputShape, inputDecoder, descriptor, dataLayoutIndexed);
+
+ // set up temporary (empty) padded output
+ TensorData paddedOutput = SetUpEmptyPaddedOutput(outputShape, descriptor, dataLayoutIndexed);
+
+ // run deconvolution (without biases) on strided input to produce padded output
+ Deconvolve(stridedInput, paddedOutput, weightsShape, weightsDecoder, dataLayoutIndexed);
+
+ const unsigned int wPaddedOutput = paddedOutput.shape[wIndex];
+ const unsigned int hPaddedOutput = paddedOutput.shape[hIndex];
+
+ // remove padding and apply bias (if enabled)
+ for (unsigned int batchIdx = 0u; batchIdx < numBatches; ++batchIdx)
+ {
+ for (unsigned int cOutput = 0u; cOutput < numChannels; ++cOutput)
+ {
+ // update bias decoder iterator
+ if (descriptor.m_BiasEnabled)
+ {
+ (*biasesDecoder)[cOutput];
+ }
+
+ for (unsigned int yPaddedOutput = descriptor.m_PadTop;
+ yPaddedOutput < (hPaddedOutput - descriptor.m_PadBottom);
+ ++yPaddedOutput)
+ {
+ for (unsigned int xPaddedOutput = descriptor.m_PadLeft;
+ xPaddedOutput < (wPaddedOutput - descriptor.m_PadRight);
+ ++xPaddedOutput)
+ {
+ unsigned int xOutput = xPaddedOutput - descriptor.m_PadLeft;
+ unsigned int yOutput = yPaddedOutput - descriptor.m_PadTop;
+
+ unsigned int outputIdx =
+ dataLayoutIndexed.GetIndex(outputShape, batchIdx, cOutput, yOutput, xOutput);
+ unsigned int paddedOutputIdx =
+ dataLayoutIndexed.GetIndex(paddedOutput.shape, batchIdx, cOutput, yPaddedOutput, xPaddedOutput);
+
+ // encode (copy) output data
+ outputEncoder[outputIdx];
+ outputEncoder.Set(paddedOutput.data[paddedOutputIdx]);
+
+ // apply bias (if enabled)
+ if (descriptor.m_BiasEnabled)
+ {
+ outputEncoder.Set(outputEncoder.Get() + biasesDecoder->Get());
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace armnn \ No newline at end of file