| 63 | } |
| 64 | |
| 65 | void mergeConvolutionAndPrelu(Node* root, MNNForwardType forwardType){ |
| 66 | if (root->cmd->op != nullptr && root->cmd->op->type() == OpType_Convolution && root->succ.size() == 1) { |
| 67 | auto child = root->succ[0]; |
| 68 | if(child->cmd->op->type() == OpType_PReLU){ |
| 69 | if(root->cmd->op->externalPath() != nullptr){ |
| 70 | return; |
| 71 | } |
| 72 | std::shared_ptr<Command> cmdPlugin; |
| 73 | auto inputs = root->cmd->inputs; |
| 74 | auto outputs = root->cmd->outputs; |
| 75 | auto convOp = root->cmd->op->main_as_Convolution2D(); |
| 76 | if(convOp->quanParameter() != nullptr || convOp->symmetricQuan() != nullptr || convOp->sparseParameter() != nullptr || convOp->external() != nullptr || convOp->common()->outputCount() != child->cmd->op->main_as_PRelu()->slopeCount()){ |
| 77 | return; |
| 78 | } |
| 79 | std::unique_ptr<OpT> fuseOp(new OpT); |
| 80 | fuseOp->type = OpType_Extra; |
| 81 | fuseOp->name = root->cmd->op->name()->str(); |
| 82 | ExtraT* extra_param = new ExtraT; |
| 83 | extra_param->type = "ExtraConvolution2DPrelu"; |
| 84 | extra_param->attr.resize(2); |
| 85 | // copy convolution2D param |
| 86 | AttributeT* convAtr = new AttributeT; |
| 87 | BlobT* convParamBlob = new BlobT; |
| 88 | { |
| 89 | std::unique_ptr<Convolution2DT> convolutionParam(convOp->UnPack()); |
| 90 | flatbuffers::FlatBufferBuilder builder; |
| 91 | auto lastOffset = Convolution2D::Pack(builder, convolutionParam.get()); |
| 92 | builder.Finish(lastOffset); |
| 93 | |
| 94 | const uint8_t* buffer_ptr = builder.GetBufferPointer(); |
| 95 | const size_t size = builder.GetSize(); |
| 96 | convParamBlob->uint8s.resize(size); |
| 97 | ::memcpy(convParamBlob->uint8s.data(), buffer_ptr, size); |
| 98 | } |
| 99 | convAtr->tensor.reset(convParamBlob); |
| 100 | extra_param->attr[0].reset(convAtr); |
| 101 | |
| 102 | // copy prelu param |
| 103 | AttributeT* preluAtr = new AttributeT; |
| 104 | BlobT* preluParamBlob = new BlobT; |
| 105 | { |
| 106 | std::unique_ptr<PReluT> preluParam(child->cmd->op->main_as_PRelu()->UnPack()); |
| 107 | flatbuffers::FlatBufferBuilder builder; |
| 108 | auto lastOffset = PRelu::Pack(builder, preluParam.get()); |
| 109 | builder.Finish(lastOffset); |
| 110 | const uint8_t* buffer_ptr = builder.GetBufferPointer(); |
| 111 | const size_t size = builder.GetSize(); |
| 112 | preluParamBlob->uint8s.resize(size); |
| 113 | ::memcpy(preluParamBlob->uint8s.data(), buffer_ptr, size); |
| 114 | } |
| 115 | preluAtr->tensor.reset(preluParamBlob); |
| 116 | extra_param->attr[1].reset(preluAtr); |
| 117 | |
| 118 | fuseOp->main.type = OpParameter_Extra; |
| 119 | fuseOp->main.value = extra_param; |
| 120 | flatbuffers::FlatBufferBuilder builder; |
| 121 | auto lastOffset = Op::Pack(builder, fuseOp.get()); |
| 122 | builder.Finish(lastOffset); |