// // ScaleBufExecution.cpp // MNN // // Created by MNN on 2019/02/28. // Copyright © 2018, Alibaba Group Holding Limited // #ifndef MNN_OPENCL_BUFFER_CLOSED #include "backend/opencl/execution/buffer/ScaleBufExecution.hpp" namespace MNN { namespace OpenCL { ScaleBufExecution::ScaleBufExecution(const std::vector &inputs, const MNN::Op *op, Backend *backend) : CommonExecution(backend, op) { #ifdef LOG_VERBOSE MNN_PRINT("Start ScaleBufExecution init !\n"); #endif mUnits.resize(1); auto &unit = mUnits[0]; auto openclBackend = (OpenCLBackend *)backend; mOpenCLBackend = static_cast(backend); const auto *scaleParams = op->main_as_Scale(); int scaleSize = scaleParams->scaleData()->size(); const float *scaleDataPtr = scaleParams->scaleData()->data(); int buffer_size = ALIGN_UP4(scaleSize); if (mOpenCLBackend->getPrecision() != BackendConfig::Precision_High) { buffer_size *= sizeof(half_float::half); } else { buffer_size *= sizeof(float); } mScale.reset(Tensor::createDevice({1, 1, 1, ALIGN_UP4(scaleSize)})); OPENCL_CHECK_ALLOC_CTOR(backend->onAcquireBuffer(mScale.get(), Backend::STATIC)); if (mOpenCLBackend->getRuntime()->hint().useCachedMmap <= 1){ cl::Buffer &scaleBuffer = openCLBuffer(mScale.get()); cl_int error; auto scalePtrCL = openclBackend->getOpenCLRuntime()->commandQueue().enqueueMapBuffer(scaleBuffer, true, CL_MAP_WRITE, 0, buffer_size, nullptr, nullptr, &error); if(nullptr != scalePtrCL && error == CL_SUCCESS){ if (mOpenCLBackend->getPrecision() != BackendConfig::Precision_High) { for (int i = 0; i < scaleSize; i++) { ((half_float::half *)scalePtrCL)[i] = (half_float::half)(scaleDataPtr[i]); } for(int i=scaleSize; igetOpenCLRuntime()->commandQueue().enqueueUnmapMemObject(scaleBuffer, scalePtrCL); } std::set buildOptions; if (nullptr != scaleParams->biasData() && nullptr != scaleParams->biasData()->data()) { int biasSize = scaleParams->biasData()->size(); MNN_ASSERT(biasSize == scaleSize); const float *biasDataPtr = scaleParams->biasData()->data(); int buffer_size = ALIGN_UP4(biasSize); if (mOpenCLBackend->getPrecision() != BackendConfig::Precision_High) { buffer_size *= sizeof(half_float::half); } else { buffer_size *= sizeof(float); } mBias.reset(Tensor::createDevice({1, 1, 1, ALIGN_UP4(biasSize)})); OPENCL_CHECK_ALLOC_CTOR(backend->onAcquireBuffer(mBias.get(), Backend::STATIC)); if (mOpenCLBackend->getRuntime()->hint().useCachedMmap <= 1){ cl::Buffer &biasBuffer = openCLBuffer(mBias.get()); cl_int error; auto biasPtrCL = openclBackend->getOpenCLRuntime()->commandQueue().enqueueMapBuffer(biasBuffer, true, CL_MAP_WRITE, 0, buffer_size, nullptr, nullptr, &error); if(nullptr != biasPtrCL && error == CL_SUCCESS){ if (mOpenCLBackend->getPrecision() != BackendConfig::Precision_High) { for (int i = 0; i < biasSize; i++) { ((half_float::half *)biasPtrCL)[i] = (half_float::half)(biasDataPtr[i]); } for(int i=biasSize; igetOpenCLRuntime()->commandQueue().enqueueUnmapMemObject(biasBuffer, biasPtrCL); } mBuildOptions.emplace("-DBIAS"); mHasBias = true; } #ifdef LOG_VERBOSE MNN_PRINT("end ScaleBufExecution init !\n"); #endif } ScaleBufExecution::~ScaleBufExecution() { // Do nothing } ErrorCode ScaleBufExecution::onEncode(const std::vector &inputs, const std::vector &outputs) { #ifdef LOG_VERBOSE MNN_PRINT("Start ScaleBufExecution onResize !\n"); #endif auto &unit = mUnits[0]; std::vector inputShape = tensorShapeFormat(inputs[0]); auto runtime = mOpenCLBackend->getOpenCLRuntime(); const int batch = inputShape.at(0); const int height = inputShape.at(1); const int width = inputShape.at(2); const int channels = inputShape.at(3); const int inside = width * height; const int channelBlocks = UP_DIV(channels, 4); std::set buildOptions = mBuildOptions; unit.kernel = runtime->buildKernel("scale_buf", "scale_buf", buildOptions, mOpenCLBackend->getPrecision()); mMaxWorkGroupSize = static_cast(runtime->getMaxWorkGroupSize(unit.kernel)); mGlobalWorkSize = {static_cast(inside), static_cast(channelBlocks * batch)}; uint32_t idx = 0; cl_int ret = CL_SUCCESS; ret |= unit.kernel->get().setArg(idx++, mGlobalWorkSize[0]); ret |= unit.kernel->get().setArg(idx++, mGlobalWorkSize[1]); ret |= unit.kernel->get().setArg(idx++, openCLBuffer(inputs[0])); ret |= unit.kernel->get().setArg(idx++, openCLBuffer(mScale.get())); if (mHasBias) { ret |= unit.kernel->get().setArg(idx++, openCLBuffer(mBias.get())); } ret |= unit.kernel->get().setArg(idx++, openCLBuffer(outputs[0])); ret |= unit.kernel->get().setArg(idx++, channelBlocks); ret |= unit.kernel->get().setArg(idx++, batch); ret |= unit.kernel->get().setArg(idx++, inside); MNN_CHECK_CL_SUCCESS(ret, "setArg ScaleBufExecution"); std::string name = "scale_buf"; mLocalWorkSize = localWS2DDefault(mGlobalWorkSize, mMaxWorkGroupSize, mOpenCLBackend->getOpenCLRuntime(), name, unit.kernel, mOpenCLBackend->getCLTuneLevel(), "scale_buf").first; mOpenCLBackend->recordKernel2d(unit.kernel, mGlobalWorkSize, mLocalWorkSize); unit.globalWorkSize = {mGlobalWorkSize[0], mGlobalWorkSize[1]}; unit.localWorkSize = {mLocalWorkSize[0], mLocalWorkSize[1]}; return NO_ERROR; } class ScaleBufCreator : public OpenCLBackend::Creator { public: virtual ~ScaleBufCreator() = default; virtual Execution *onCreate(const std::vector &inputs, const std::vector &outputs, const MNN::Op *op, Backend *backend) const override { for (int i = 0; i < inputs.size(); ++i) { TensorUtils::setTensorSupportPack(inputs[i], false); } for (int i = 0; i < outputs.size(); ++i) { TensorUtils::setTensorSupportPack(outputs[i], false); } OPENCL_CREATOR_CHECK(new ScaleBufExecution(inputs, op, backend)); } }; REGISTER_OPENCL_OP_CREATOR(ScaleBufCreator, OpType_Scale, BUFFER); } // namespace OpenCL } // namespace MNN #endif /* MNN_OPENCL_BUFFER_CLOSED */