165 lines
5.4 KiB
C++
165 lines
5.4 KiB
C++
//
|
|
// MatMulOnnx.cpp
|
|
// MNNConverter
|
|
//
|
|
// Created by MNN on 2019/01/31.
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include "onnxOpConverter.hpp"
|
|
|
|
DECLARE_OP_CONVERTER(GemmOnnx);
|
|
|
|
MNN::OpType GemmOnnx::opType() {
|
|
return MNN::OpType_InnerProduct;
|
|
}
|
|
MNN::OpParameter GemmOnnx::type() {
|
|
return MNN::OpParameter_InnerProduct;
|
|
}
|
|
|
|
void GemmOnnx::run(MNN::OpT* dstOp, const onnx::NodeProto* onnxNode, OnnxScope* scope) {
|
|
// get input initializers of gemm
|
|
std::vector<const onnx::TensorProto*> initializers;
|
|
for (int k = 0; k < onnxNode->input_size(); ++k) {
|
|
const auto& inputName = onnxNode->input(k);
|
|
const auto it = scope->mInitializers.find(inputName);
|
|
if (it != scope->mInitializers.end()) {
|
|
initializers.push_back(it->second);
|
|
}
|
|
}
|
|
const int size = initializers.size();
|
|
DCHECK(size <= 2 && size >= 1) << "Gemm Input ERROR!";
|
|
auto gemmParam = new MNN::InnerProductT;
|
|
|
|
bool transA = false;
|
|
bool transB = false;
|
|
float alpha = 1.0f;
|
|
float beta = 1.0f;
|
|
|
|
for (int i = 0; i < onnxNode->attribute_size(); ++i) {
|
|
const auto& attributeProto = onnxNode->attribute(i);
|
|
const auto& attributeName = attributeProto.name();
|
|
if (attributeName == "transA") {
|
|
DCHECK(attributeProto.type() == ::onnx::AttributeProto_AttributeType_INT) << "Node Attribute ERROR";
|
|
transA = static_cast<bool>(attributeProto.i());
|
|
} else if (attributeName == "transB") {
|
|
DCHECK(attributeProto.type() == ::onnx::AttributeProto_AttributeType_INT) << "Node Attribute ERROR";
|
|
transB = static_cast<bool>(attributeProto.i());
|
|
} else if (attributeName == "alpha") {
|
|
DCHECK(attributeProto.type() == ::onnx::AttributeProto_AttributeType_FLOAT) << "Node Attribute ERROR";
|
|
alpha = attributeProto.f();
|
|
} else if (attributeName == "beta") {
|
|
DCHECK(attributeProto.type() == ::onnx::AttributeProto_AttributeType_FLOAT) << "Node Attribute ERROR";
|
|
beta = attributeProto.f();
|
|
}
|
|
}
|
|
|
|
// TODO, MNN implement (alpha * A * B + beta * C), now (A * B + C)
|
|
DCHECK(1 == alpha);
|
|
DCHECK(1 == beta);
|
|
|
|
DCHECK(!transA) << "Now GEMM not support transpose the intput tensor!";
|
|
|
|
int weightSize = 1;
|
|
const auto weightProto = initializers[0];
|
|
DCHECK(2 == weightProto->dims_size()) << "Gemm weight dimensions should be 2";
|
|
int bK = weightProto->dims(0);
|
|
int bN = weightProto->dims(1);
|
|
|
|
if (transB) {
|
|
int temp = bK;
|
|
bK = bN;
|
|
bN = temp;
|
|
}
|
|
for (int i = 0; i < weightProto->dims_size(); ++i) {
|
|
weightSize *= weightProto->dims(i);
|
|
}
|
|
|
|
std::vector<float> weightContainer(weightSize);
|
|
auto weightPtr = weightContainer.data();
|
|
|
|
if (weightProto->float_data_size() != 0) {
|
|
for (int i = 0; i < weightSize; ++i) {
|
|
weightPtr[i] = weightProto->float_data(i);
|
|
}
|
|
} else if (weightProto->raw_data().data()) {
|
|
::memcpy(weightPtr, reinterpret_cast<const float*>(weightProto->raw_data().data()), weightSize * sizeof(float));
|
|
} else {
|
|
DLOG(ERROR) << "ERROR";
|
|
}
|
|
|
|
auto weightBlob = new MNN::BlobT;
|
|
// tranpose weight if necessary
|
|
weightBlob->dims.resize(2);
|
|
weightBlob->dims[0] = bK;
|
|
weightBlob->dims[1] = bN;
|
|
if (transB) {
|
|
auto& weightVector = weightBlob->float32s;
|
|
weightVector.resize(weightSize);
|
|
for (int i = 0; i < bK; ++i) {
|
|
for (int j = 0; j < bN; ++j) {
|
|
weightVector[i * bN + j] = weightContainer[j * bK + i];
|
|
}
|
|
}
|
|
} else {
|
|
weightBlob->float32s = weightContainer;
|
|
}
|
|
gemmParam->weight = weightContainer;
|
|
|
|
// bias
|
|
std::vector<float> biasContainer(bN);
|
|
const auto biasProto = size == 2 ? initializers[1] : nullptr;
|
|
if (biasProto) {
|
|
int biasSize = 1;
|
|
DCHECK(1 == biasProto->dims_size()) << "Gemm bias dimension should be 1";
|
|
for (int i = 0; i < biasProto->dims_size(); ++i) {
|
|
biasSize *= biasProto->dims(i);
|
|
}
|
|
// TODO, MNN support broadcast add for( + C)
|
|
DCHECK(bN == biasSize) << "Gemm Now not support for broadcast mode(+ C)";
|
|
auto biasPtr = biasContainer.data();
|
|
if (biasProto->float_data_size() != 0) {
|
|
for (int i = 0; i < biasSize; ++i) {
|
|
biasPtr[i] = biasProto->float_data(i);
|
|
}
|
|
} else if (biasProto->raw_data().data()) {
|
|
::memcpy(biasPtr, reinterpret_cast<const float*>(biasProto->raw_data().data()), biasSize * sizeof(float));
|
|
} else {
|
|
DLOG(ERROR) << "ERROR";
|
|
}
|
|
}
|
|
gemmParam->bias = biasContainer;
|
|
|
|
gemmParam->outputCount = bN;
|
|
gemmParam->axis = 1;
|
|
gemmParam->transpose = false;
|
|
gemmParam->biasTerm = 1;
|
|
|
|
dstOp->main.value = gemmParam;
|
|
}
|
|
|
|
//REGISTER_CONVERTER(GemmOnnx, Gemm);
|
|
|
|
|
|
DECLARE_OP_CONVERTER(MatMulOnnx);
|
|
|
|
MNN::OpType MatMulOnnx::opType(){
|
|
return MNN::OpType_MatMul;
|
|
}
|
|
|
|
MNN::OpParameter MatMulOnnx::type(){
|
|
return MNN::OpParameter_MatMul;
|
|
}
|
|
|
|
void MatMulOnnx::run(MNN::OpT *dstOp, const onnx::NodeProto *onnxNode, OnnxScope* scope){
|
|
|
|
CHECK(2 == onnxNode->input_size()) << "ONNX Matmul input error!";
|
|
auto param = new MNN::MatMulT;
|
|
param->T = MNN::DataType_DT_FLOAT;
|
|
|
|
dstOp->main.value = param;
|
|
}
|
|
|
|
REGISTER_CONVERTER(MatMulOnnx, MatMul);
|