Files
alibaba--mnn/source/backend/vulkan/buffer/execution/VulkanPRelu.cpp
T
2026-07-13 13:33:03 +08:00

107 lines
3.8 KiB
C++

//
// VulkanPRelu.cpp
// MNN
//
// Created by MNN on 2019/01/31.
// Copyright © 2018, Alibaba Group Holding Limited
//
#include "VulkanPRelu.hpp"
#include "VulkanUnary.hpp"
#include "core/Macro.h"
#include "core/TensorUtils.hpp"
namespace MNN {
struct GpuReluParam {
ivec4 imgSize;
};
//--------------------------Prelu--------------------------//
VulkanPrelu::VulkanPrelu(Backend *bn, const Op *op, Tensor * tensor) : VulkanBasicExecution(bn) {
std::vector<VkDescriptorType> types{
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
};
auto vulkanBn = static_cast<VulkanBackend *>(bn);
bool useFP16 = tensor->getType().code == halide_type_float && vulkanBn->useFP16();
std::string pKey = "glsl_preluWithChannel_";
if (useFP16) {
pKey += "FP16_";
}
pKey += "comp";
mPreluPipeline = vulkanBn->getPipeline(pKey, types);
const auto prelu = op->main_as_PRelu();
mGpuPreluParam = vulkanBn->allocUniform();
int count = ALIGN_UP4(prelu->slope()->size());
{
int bytes = useFP16 ? sizeof(int16_t) : sizeof(float);
std::shared_ptr<VulkanBuffer> slopeBuffer(new VulkanBuffer(
vulkanBn->getMemoryPool(), false, bytes * count, nullptr, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT));
auto slope = slopeBuffer->map();
::memset(slope, 0, count * bytes);
if (useFP16) {
FLOAT_TO_HALF(prelu->slope()->data(), (int16_t *)slope, prelu->slope()->size());
} else {
::memcpy(slope, prelu->slope()->data(), prelu->slope()->size() * sizeof(float));
}
slopeBuffer->unmap();
mSlope = slopeBuffer;
}
mDescriptorSet.reset(mPreluPipeline->createSet());
}
VulkanPrelu::~VulkanPrelu() {
auto extra = static_cast<VulkanBackend*>(backend());
extra->recycleUniform(mGpuPreluParam);
}
ErrorCode VulkanPrelu::onEncode(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs,
const VulkanCommandPool::Buffer *cmdBuffer) {
auto input = inputs[0];
auto output = outputs[0];
auto preluParam = reinterpret_cast<GpuReluParam *>(mGpuPreluParam->map());
::memset(preluParam, 0, sizeof(GpuReluParam));
auto vkBn = static_cast<VulkanBackend *>(backend());
const int channelDiv4 = UP_DIV(input->channel(), 4);
auto planeSize = input->width() * input->height() * input->batch();
preluParam->imgSize[0] = planeSize;
preluParam->imgSize[1] = channelDiv4;
preluParam->imgSize[2] = 1;
preluParam->imgSize[3] = channelDiv4 * planeSize;
mGpuPreluParam->unmap();
auto total = planeSize * channelDiv4;
auto vkOutput = vkBn->getBuffer(output);
auto vkInput = vkBn->getBuffer(input);
mDescriptorSet->writeBuffer(vkOutput, 0);
mDescriptorSet->writeBuffer(vkInput, 1);
mDescriptorSet->writeBuffer(mSlope->buffer(), 2, mSlope->size());
mDescriptorSet->writeBuffer(mGpuPreluParam->buffer(), 3, mGpuPreluParam->size());
mPreluPipeline->bind(cmdBuffer->get(), mDescriptorSet->get());
vkCmdDispatch(cmdBuffer->get(), UP_DIV(total, 256), 1, 1);
return NO_ERROR;
}
class VulkanReluCreator : public VulkanBackend::Creator {
public:
virtual VulkanBasicExecution *onCreate(const std::vector<Tensor *> &inputs, const std::vector<Tensor*>& outputs, const MNN::Op *op, Backend *bn) const override {
if (1 == op->main_as_PRelu()->slopeCount()) {
return new VulkanUnary("RELU", bn, false, op->main_as_PRelu()->slope()->data()[0]);
}
return new VulkanPrelu(bn, op, outputs[0]);
}
};
static bool gr = []() {
VulkanBackend::addCreator(OpType_PReLU, new VulkanReluCreator);
return true;
}();
} // namespace MNN