Files
2026-07-13 13:33:03 +08:00

194 lines
6.7 KiB
C++

//
// torchOpConverter.hpp
// MNNConverter
//
// Created by MNN on 2021/04/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef TORCHOPCONVERTER_HPP
#define TORCHOPCONVERTER_HPP
#include <map>
#include <memory>
#include "MNN_generated.h"
#include <MNN/MNNDefine.h>
#include <torch/script.h>
#include "OpCount.hpp"
#include "ConverterScope.hpp"
template <typename T>
static inline T getValue(const torch::jit::Value* value) {
auto optional_ivalue = toIValue(value);
T res;
if (!optional_ivalue) {
MNN_ERROR("getValue: must Constant Node.\n");
return res;
}
c10::IValue& val = optional_ivalue.value();
auto optional_res = val.toOptional<T>();
if (!optional_res) {
// MNN_ERROR("getValue: value is None.");
return res;
}
return optional_res.value();
}
template <typename T>
static std::vector<T> getValue(const torch::jit::Value* value, std::vector<int>& shape) {
std::vector<T> data;
const auto tensor = getValue<at::Tensor>(value);
int size = tensor.numel();
if (!size) {
return data;
}
auto shapes = tensor.sizes().vec();
auto strides = tensor.strides().vec();
if (shapes.empty()) {
shapes.push_back(size);
strides.push_back(1);
}
shape.resize(shapes.size());
for (int i = 0; i < shapes.size(); i++) {
shape[i] = static_cast<int>(shapes[i]);
}
data.resize(size);
int idx = 0;
std::function<void(int, int)> copyData = [&](int dim, int offset) {
if (dim == shapes.size()-1) {
for (int i = 0; i < shapes[dim]; i++) {
data[idx++] = tensor.data_ptr<T>()[offset + i * strides[dim]];
}
} else {
for (int i = 0; i < shapes[dim]; i++) {
copyData(dim + 1, offset + i * strides[dim]);
}
}
};
copyData(0, 0);
return data;
}
static std::vector<int> getShape(const torch::jit::Value* value) {
const auto tensor = getValue<at::Tensor>(value);
auto shape = tensor.sizes().vec();
std::vector<int> res(shape.begin(), shape.end());
return res;
}
static std::string getRealOpType(const torch::jit::Node *node) {
const auto kind = node->kind();
// custom op
if (!(kind.is_attr() || kind.is_aten() || kind.is_cuda() ||
kind.is_prim() || kind.is_onnx() || kind.is_user() ||
kind.is_caffe2() || kind.is_dimname())) {
return "__custom__";
}
std::string opType(kind.toUnqualString());
// convert _xxx_ to xxx
int last = opType.size() - 1;
int last2 = last - 1;
if (last > 0 && opType[last] == '_' && opType[last2] != '_') {
opType = opType.substr(0, opType.size() - 1);
}
if (opType.size() > 2 && opType[0] == '_' && opType[1] != '_') {
opType = opType.substr(1, opType.size() - 1);
}
// distinguish overload function
auto symb = c10::Symbol::fromQualString("attr::mnn_tag");
if (node->hasAttribute(symb)) {
opType += ("_" + node->s(symb));
}
return opType;
}
static MNN::DataType ScalarType2Dtype(at::ScalarType scalarType) {
switch (scalarType) {
case at::ScalarType::Byte:
return MNN::DataType_DT_UINT8;
case at::ScalarType::Char:
return MNN::DataType_DT_INT8;
case at::ScalarType::Bool:
return MNN::DataType_DT_BOOL;
case at::ScalarType::Int:
case at::ScalarType::Long:
return MNN::DataType_DT_INT32;
case at::ScalarType::Half:
case at::ScalarType::Float:
case at::ScalarType::Double:
return MNN::DataType_DT_FLOAT;
default:
return MNN::DataType_DT_FLOAT;
}
}
class TorchScope : public ConverterScope {
public:
TorchScope(MNN::NetT* net) : ConverterScope(net) {}
TorchScope(MNN::SubGraphProtoT* subnet, MNN::NetT* parentNet, TorchScope* parentScope)
: ConverterScope(subnet, parentNet, parentScope) {}
bool dealPrime(const torch::jit::Node* node);
void buildMNNOp(const torch::jit::Node *node);
virtual int lookupTensor(std::string name);
void declareVar(std::string name, const torch::jit::Node* var);
const torch::jit::Node* lookupVar(std::string name) const;
void buildSubGraph(const torch::jit::Block* block, const std::string& name, bool increment = false);
private:
std::map<std::string, const torch::jit::Node*> varTable;
};
class torchOpConverter {
public:
virtual void run(MNN::OpT* dstOp, const torch::jit::Node* node, TorchScope* scop) = 0;
virtual MNN::OpParameter type() = 0;
virtual MNN::OpType opType() = 0;
virtual std::vector<int> inputTensorIdx() { return { 0 }; }
torchOpConverter() {}
virtual ~torchOpConverter() {}
friend class torchOpConverterSuit;
};
class torchOpConverterSuit {
public:
torchOpConverterSuit() {}
~torchOpConverterSuit();
static torchOpConverterSuit* get();
void insert(torchOpConverter* t, const char* name);
torchOpConverter* search(const std::string& name);
private:
static torchOpConverterSuit* global;
std::map<std::string, torchOpConverter*> mConverterContainer;
};
template <class T>
class torchOpConverterRegister {
public:
torchOpConverterRegister(const char* name) {
T* converter = new T;
torchOpConverterSuit* container = torchOpConverterSuit::get();
MNN::OpCount::get()->insertOp("TORCH", name);
container->insert(converter, name);
}
~torchOpConverterRegister() {
}
};
#define DECLARE_OP_CONVERTER(name) \
class name : public torchOpConverter { \
public: \
name() { \
} \
virtual ~name() { \
} \
virtual void run(MNN::OpT* dstOp, const torch::jit::Node* node, TorchScope* scope); \
virtual MNN::OpType opType(); \
virtual MNN::OpParameter type(); \
virtual std::vector<int> inputTensorIdx(); \
}
#define REGISTER_CONVERTER(name, opType) static torchOpConverterRegister<name> _Convert_##opType(#opType)
#endif // TORCHOPCONVERTER_HPP