| 126 | } |
| 127 | |
| 128 | ErrorCode CPUConvolution3D::onResize(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) { |
| 129 | auto input = inputs[0]; |
| 130 | auto output = outputs[0]; |
| 131 | |
| 132 | if (mPadMode == PadMode_SAME) { |
| 133 | mPads.clear(); |
| 134 | for (int i = 0; i < 3; ++i) { |
| 135 | int inputNeeded = (output->length(i + 2) - 1) * mStrides[i] + (mKernels[i] - 1) * mDilates[i] + 1; |
| 136 | mPads.push_back((inputNeeded - input->length(i + 2)) / 2); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | const int batch = input->length(0), inputChannel = input->length(1), outputChannel = output->length(1); |
| 141 | const int inputDepth = input->length(2), inputHeight = input->length(3), inputWidth = input->length(4); |
| 142 | const int outputDepth = output->length(2), outputHeight = output->length(3), outputWidth = output->length(4); |
| 143 | const int depthPad = mPads[0], kernelDepth = mKernels[0], kernelHeight = mKernels[1], kernelWidth = mKernels[2]; |
| 144 | auto cpuBackend = (CPUBackend*)backend(); |
| 145 | |
| 146 | mBreakDown = true; |
| 147 | mSubInputTensors.clear(); |
| 148 | mSubExecution.clear(); |
| 149 | |
| 150 | do { |
| 151 | bool useWinograd = ConvolutionWinograd3D::canUseWinograd(mCommon) || cpuBackend->memoryMode() != BackendConfig::Memory_Low; |
| 152 | if (!useWinograd) { |
| 153 | break; |
| 154 | } |
| 155 | auto unit = ConvolutionWinograd3D::bestWinogradUnit(mCommon, input, output, cpuBackend->threadNumber()); |
| 156 | if (unit > 4) { |
| 157 | mSubExecution.emplace_back( |
| 158 | new ConvolutionWinograd3D(mCommon, input, output, cpuBackend, mWeights->host<float>(), |
| 159 | mWeights->elementSize(), mBias->host<float>(), outputChannel, unit)); |
| 160 | } else if (unit > 1 && kernelHeight == 3 && kernelWidth == 3) { |
| 161 | mSubExecution.emplace_back(new Convolution3D3x3(mCommon, cpuBackend, mWeights->host<float>(), mWeights->elementSize(), |
| 162 | mBias->host<float>(), outputChannel)); |
| 163 | } else { |
| 164 | break; |
| 165 | } |
| 166 | mSubExecution[0]->onResize(inputs, outputs); |
| 167 | mBreakDown = false; |
| 168 | return NO_ERROR; |
| 169 | } while(0); |
| 170 | |
| 171 | mCrossDepth = (kernelDepth != 1 || kernelHeight != 1 || depthPad != 0 || mPads[1] != 0); |
| 172 | |
| 173 | if (!mCrossDepth) { |
| 174 | mSubInputTensors.emplace_back(Tensor::create<float>({batch, inputChannel, inputDepth * inputHeight, inputWidth}, |
| 175 | (void*)(input->host<float>()), Tensor::CAFFE_C4)); |
| 176 | mSubOutputTensor.reset(Tensor::create<float>({batch, outputChannel, outputDepth * outputHeight, outputWidth}, |
| 177 | (void*)(output->host<float>()), Tensor::CAFFE_C4)); |
| 178 | } else { |
| 179 | mInputStorage.reset(Tensor::createDevice<float>({inputDepth + 2 * depthPad, batch, ALIGN_UP4(inputChannel), inputHeight, inputWidth})); |
| 180 | mSubOutputTensor.reset(Tensor::createDevice<float>({outputDepth * batch, outputChannel, outputHeight, outputWidth}, Tensor::CAFFE_C4)); |
| 181 | bool valid = true; |
| 182 | valid = valid && backend()->onAcquireBuffer(mInputStorage.get(), Backend::DYNAMIC); |
| 183 | valid = valid && backend()->onAcquireBuffer(mSubOutputTensor.get(), Backend::DYNAMIC); |
| 184 | if (!valid) { |
| 185 | return OUT_OF_MEMORY; |
nothing calls this directly
no test coverage detected