2019-04-17 10:49:11 +08:00
|
|
|
//
|
|
|
|
// Interpreter.cpp
|
|
|
|
// MNN
|
|
|
|
//
|
|
|
|
// Created by MNN on 2018/07/30.
|
|
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
#include "MNN_generated.h"
|
2019-12-27 22:16:57 +08:00
|
|
|
#include "core/AutoStorage.h"
|
|
|
|
#include <MNN/Interpreter.hpp>
|
|
|
|
#include "core/Session.hpp"
|
|
|
|
#include "core/FileLoader.hpp"
|
2019-04-17 10:49:11 +08:00
|
|
|
namespace MNN {
|
|
|
|
|
|
|
|
struct Content {
|
|
|
|
AutoStorage<uint8_t> buffer;
|
|
|
|
const Net* net = nullptr;
|
|
|
|
std::vector<std::unique_ptr<Session>> sessions;
|
|
|
|
std::map<const Tensor*, const Session*> tensorMap;
|
|
|
|
};
|
|
|
|
|
|
|
|
Interpreter* Interpreter::createFromFile(const char* file) {
|
|
|
|
if (nullptr == file) {
|
2020-03-22 20:16:29 +08:00
|
|
|
MNN_PRINT("NULL file for create interpreter\n");
|
2019-04-17 10:49:11 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
std::unique_ptr<FileLoader> loader(new FileLoader(file));
|
|
|
|
if (!loader->valid()) {
|
|
|
|
MNN_PRINT("Create interpreter failed, open %s error\n", file);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
bool result = loader->read();
|
|
|
|
if (!result) {
|
|
|
|
MNN_PRINT("Read file error\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (loader->size() == 0) {
|
|
|
|
MNN_PRINT("Create interpreter failed, %s is empty\n", file);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto net = new Content;
|
|
|
|
bool success = loader->merge(net->buffer);
|
|
|
|
if (!success) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
loader.reset();
|
|
|
|
return createFromBufferInternal(net);
|
|
|
|
}
|
|
|
|
Interpreter* Interpreter::createFromBuffer(const void* buffer, size_t size) {
|
- dynamic computation graph (beta)
- add supports (/express)
- add tests
- add benchmarks with it (/benchmark/exprModels)
- Python
- MNN engine and tools were submitted to pip
- available on Windows/macOS/Linux
- Engine/Converter
- add supports for each op benchmarking
- refactor optimizer by separating steps
- CPU
- add supports for Conv3D, Pool3D, ELU, ReverseSequence
- fix ArgMax, Permute, Scale, BinaryOp, Slice, SliceTf
- OpenCL
- add half transform in CPU
- add broadcast supports for binary
- optimize Conv2D, Reshape, Eltwise, Gemm, etc.
- OpenGL
- add sub, real div supports for binary
- add supports for unary
- optimize Conv2D, Reshape
- Vulkan
- add max supports for eltwise
- Metal
- fix metallib missing problem
- Train/Quantization
- use express to refactor training codes
2019-09-26 21:02:07 +08:00
|
|
|
if (nullptr == buffer || 0 == size) {
|
2019-04-17 10:49:11 +08:00
|
|
|
MNN_PRINT("Buffer is null for create interpreter\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto net = new Content;
|
|
|
|
net->buffer.reset((int)size);
|
|
|
|
if (nullptr == net->buffer.get()) {
|
|
|
|
MNN_ERROR("Memory not enought!\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
::memcpy(net->buffer.get(), buffer, size);
|
|
|
|
|
|
|
|
return createFromBufferInternal(net);
|
|
|
|
}
|
|
|
|
|
|
|
|
Interpreter* Interpreter::createFromBufferInternal(Content* net) {
|
|
|
|
if (nullptr == net) {
|
|
|
|
MNN_PRINT("Buffer is null for create interpreter\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
flatbuffers::Verifier verify((const uint8_t*)(net->buffer.get()), net->buffer.size());
|
|
|
|
if (false == VerifyNetBuffer(verify)) {
|
|
|
|
MNN_PRINT("Invalidate buffer to create interpreter\n");
|
- dynamic computation graph (beta)
- add supports (/express)
- add tests
- add benchmarks with it (/benchmark/exprModels)
- Python
- MNN engine and tools were submitted to pip
- available on Windows/macOS/Linux
- Engine/Converter
- add supports for each op benchmarking
- refactor optimizer by separating steps
- CPU
- add supports for Conv3D, Pool3D, ELU, ReverseSequence
- fix ArgMax, Permute, Scale, BinaryOp, Slice, SliceTf
- OpenCL
- add half transform in CPU
- add broadcast supports for binary
- optimize Conv2D, Reshape, Eltwise, Gemm, etc.
- OpenGL
- add sub, real div supports for binary
- add supports for unary
- optimize Conv2D, Reshape
- Vulkan
- add max supports for eltwise
- Metal
- fix metallib missing problem
- Train/Quantization
- use express to refactor training codes
2019-09-26 21:02:07 +08:00
|
|
|
delete net;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
net->net = GetNet(net->buffer.get());
|
|
|
|
if (nullptr == net->net->oplists()) {
|
|
|
|
MNN_ERROR("Model has no oplist\n");
|
|
|
|
delete net;
|
2019-04-17 10:49:11 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2020-03-09 17:43:56 +08:00
|
|
|
int opSize = net->net->oplists()->size();
|
|
|
|
for (int i=0; i<opSize; ++i) {
|
|
|
|
auto op = net->net->oplists()->GetAs<Op>(i);
|
|
|
|
if (nullptr == op || nullptr == op->outputIndexes()) {
|
|
|
|
MNN_ERROR("Invalid Model, the %d op is empty\n", i);
|
|
|
|
delete net;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 10:49:11 +08:00
|
|
|
return new Interpreter(net);
|
|
|
|
}
|
|
|
|
|
|
|
|
Interpreter::Interpreter(Content* net) {
|
|
|
|
MNN_ASSERT(nullptr != net);
|
|
|
|
mNet = net;
|
|
|
|
}
|
|
|
|
|
|
|
|
Interpreter::~Interpreter() {
|
|
|
|
delete mNet;
|
|
|
|
}
|
|
|
|
|
|
|
|
Session* Interpreter::createMultiPathSession(const std::vector<ScheduleConfig>& configs) {
|
|
|
|
if (nullptr == mNet->buffer.get()) {
|
|
|
|
MNN_ERROR("The model buffer has been released. Can't create session\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
- dynamic computation graph (beta)
- add supports (/express)
- add tests
- add benchmarks with it (/benchmark/exprModels)
- Python
- MNN engine and tools were submitted to pip
- available on Windows/macOS/Linux
- Engine/Converter
- add supports for each op benchmarking
- refactor optimizer by separating steps
- CPU
- add supports for Conv3D, Pool3D, ELU, ReverseSequence
- fix ArgMax, Permute, Scale, BinaryOp, Slice, SliceTf
- OpenCL
- add half transform in CPU
- add broadcast supports for binary
- optimize Conv2D, Reshape, Eltwise, Gemm, etc.
- OpenGL
- add sub, real div supports for binary
- add supports for unary
- optimize Conv2D, Reshape
- Vulkan
- add max supports for eltwise
- Metal
- fix metallib missing problem
- Train/Quantization
- use express to refactor training codes
2019-09-26 21:02:07 +08:00
|
|
|
auto info = Schedule::schedule(mNet->net, configs);
|
2019-04-17 10:49:11 +08:00
|
|
|
auto newSession = std::unique_ptr<Session>(new Session(info));
|
|
|
|
if (!newSession->valid()) {
|
|
|
|
MNN_PRINT("Invalide Session!!\n");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto result = newSession.get();
|
- build:
- unify schema building in core and converter;
- add more build script for android;
- add linux build script for python;
- ops impl:
- add floor mod support in binary;
- use eltwise impl in add/max/sub/mul binary for optimization;
- remove fake double support in cast;
- fix 5d support for concat;
- add adjX and adjY support for batch matmul;
- optimize conv2d back prop filter;
- add pad mode support for conv3d;
- fix bug in conv2d & conv depthwise with very small feature map;
- optimize binary without broacast;
- add data types support for gather;
- add gather ND support;
- use uint8 data type in gather v2;
- add transpose support for matmul;
- add matrix band part;
- add dim != 4 support for padding, reshape & tensor convert;
- add pad type support for pool3d;
- make ops based on TensorFlow Lite quantization optional;
- add all & any support for reduction;
- use type in parameter as output type in reduction;
- add int support for unary;
- add variable weight support for conv2d;
- fix conv2d depthwise weights initialization;
- fix type support for transpose;
- fix grad outputs count for reduce grad and reshape grad;
- fix priorbox & detection output;
- fix metal softmax error;
- python:
- add runSessionWithCallBackInfo interface;
- add max nodes limit (1400) for visualization tool;
- fix save error in python3;
- align default dim;
- convert:
- add extra design for optimization;
- add more post converting optimizers;
- add caffe v1 weights blob support;
- add cast, unary, conv transpose support for onnx model;
- optimize batchnorm, conv with variable weights, prelu, reshape, slice, upsample for onnx model;
- add cos/sin/atan/tan support for unary for tensorflow model;
- add any/all support for reduction for tensorflow model;
- add elu, conv3d, pool3d support for tensorflow model;
- optimize argmax, batchnorm, concat, batch to space, conv with variable weights, prelu, slice for tensorflow model;
- others:
- fix size computer lock;
- fix thread pool deadlock;
- add express & parameters in express;
- rewrite blitter chooser without static map;
- add tests for expr;
2019-10-29 13:37:26 +08:00
|
|
|
if (info.validForResize) {
|
|
|
|
result->resize();
|
|
|
|
}
|
2019-04-17 10:49:11 +08:00
|
|
|
mNet->sessions.emplace_back(std::move(newSession));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
- dynamic computation graph (beta)
- add supports (/express)
- add tests
- add benchmarks with it (/benchmark/exprModels)
- Python
- MNN engine and tools were submitted to pip
- available on Windows/macOS/Linux
- Engine/Converter
- add supports for each op benchmarking
- refactor optimizer by separating steps
- CPU
- add supports for Conv3D, Pool3D, ELU, ReverseSequence
- fix ArgMax, Permute, Scale, BinaryOp, Slice, SliceTf
- OpenCL
- add half transform in CPU
- add broadcast supports for binary
- optimize Conv2D, Reshape, Eltwise, Gemm, etc.
- OpenGL
- add sub, real div supports for binary
- add supports for unary
- optimize Conv2D, Reshape
- Vulkan
- add max supports for eltwise
- Metal
- fix metallib missing problem
- Train/Quantization
- use express to refactor training codes
2019-09-26 21:02:07 +08:00
|
|
|
Session* Interpreter::createSession(const ScheduleConfig& config) {
|
|
|
|
return createMultiPathSession({config});
|
|
|
|
}
|
|
|
|
|
2019-04-17 10:49:11 +08:00
|
|
|
bool Interpreter::releaseSession(Session* session) {
|
|
|
|
for (auto iter = mNet->sessions.begin(); iter != mNet->sessions.end(); iter++) {
|
|
|
|
// TODO Delete tensormap
|
|
|
|
for (auto tIter = mNet->tensorMap.begin(); tIter != mNet->tensorMap.end();) {
|
|
|
|
if (tIter->second == session) {
|
|
|
|
tIter = mNet->tensorMap.erase(tIter);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tIter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*iter).get() == session) {
|
|
|
|
mNet->sessions.erase(iter);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode Interpreter::runSession(Session* session) const {
|
|
|
|
return session->run();
|
|
|
|
}
|
|
|
|
|
|
|
|
Tensor* Interpreter::getSessionInput(const Session* session, const char* name) {
|
|
|
|
MNN_ASSERT(nullptr != session);
|
|
|
|
if (session == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
auto tensor = session->getInput(name);
|
|
|
|
mNet->tensorMap.insert(std::make_pair(tensor, session));
|
|
|
|
return tensor;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tensor* Interpreter::getSessionOutput(const Session* session, const char* name) {
|
|
|
|
MNN_ASSERT(nullptr != session);
|
|
|
|
auto tensor = session->getOutput(name);
|
|
|
|
mNet->tensorMap.insert(std::make_pair(tensor, session));
|
|
|
|
return tensor;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::map<std::string, Tensor*>& Interpreter::getSessionInputAll(const Session* session) const {
|
2019-08-08 14:42:14 +08:00
|
|
|
auto& tensors = session->getInputAll();
|
|
|
|
for (auto& iter : tensors) {
|
|
|
|
mNet->tensorMap.insert(std::make_pair(iter.second, session));
|
|
|
|
}
|
|
|
|
return tensors;
|
2019-04-17 10:49:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::map<std::string, Tensor*>& Interpreter::getSessionOutputAll(const Session* session) const {
|
2019-08-08 14:42:14 +08:00
|
|
|
auto& tensors = session->getOutputAll();
|
|
|
|
for (auto& iter : tensors) {
|
|
|
|
mNet->tensorMap.insert(std::make_pair(iter.second, session));
|
|
|
|
}
|
|
|
|
return tensors;
|
2019-04-17 10:49:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Interpreter::resizeSession(Session* session) {
|
|
|
|
if (mNet->buffer.get() == nullptr) {
|
|
|
|
MNN_ERROR("The model buffer has been released. Can't resize session\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (session->getNeedResize()) {
|
|
|
|
session->resize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode Interpreter::runSessionWithCallBack(const Session* session, const TensorCallBack& before,
|
|
|
|
const TensorCallBack& after, bool sync) const {
|
|
|
|
auto beforeWrap = [&before](const std::vector<Tensor*>& tensors, const OperatorInfo* info) {
|
|
|
|
return before(tensors, info->name());
|
|
|
|
};
|
|
|
|
auto afterWrap = [&after](const std::vector<Tensor*>& tensors, const OperatorInfo* info) {
|
|
|
|
return after(tensors, info->name());
|
|
|
|
};
|
|
|
|
return runSessionWithCallBackInfo(session, beforeWrap, afterWrap, sync);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorCode Interpreter::runSessionWithCallBackInfo(const Session* session, const TensorCallBackWithInfo& before,
|
|
|
|
const TensorCallBackWithInfo& callBack, bool sync) const {
|
|
|
|
return session->runWithCallBack(before, callBack, sync);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Backend* Interpreter::getBackend(const Session* session, const Tensor* tensor) const {
|
|
|
|
return session->getBackEnd(tensor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Interpreter::releaseModel() {
|
|
|
|
mNet->buffer.release();
|
|
|
|
for (auto& iter : mNet->sessions) {
|
|
|
|
iter->releaseCache();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 20:27:57 +08:00
|
|
|
void Interpreter::resizeTensor(Tensor* tensor, int batch, int channel, int height, int width) {
|
|
|
|
if (tensor->getDimensionType() == Tensor::TENSORFLOW) {
|
|
|
|
resizeTensor(tensor, {batch, height, width, channel});
|
|
|
|
} else {
|
|
|
|
resizeTensor(tensor, {batch, channel, height, width});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-17 10:49:11 +08:00
|
|
|
void Interpreter::resizeTensor(Tensor* tensor, const std::vector<int>& dims) {
|
|
|
|
MNN_ASSERT(nullptr != tensor);
|
|
|
|
bool dirty = false;
|
|
|
|
if (tensor->buffer().dimensions != dims.size()) {
|
|
|
|
dirty = true;
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < dims.size(); ++i) {
|
|
|
|
if (tensor->buffer().dim[i].extent != dims[i]) {
|
|
|
|
dirty = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dirty) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tensor->buffer().dimensions = (int)dims.size();
|
|
|
|
for (int i = 0; i < dims.size(); ++i) {
|
|
|
|
tensor->buffer().dim[i].extent = dims[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
auto relatedSessionIter = mNet->tensorMap.find(tensor);
|
|
|
|
MNN_ASSERT(relatedSessionIter != mNet->tensorMap.end());
|
|
|
|
((MNN::Session*)relatedSessionIter->second)->setNeedResize();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* Interpreter::bizCode() const {
|
|
|
|
const flatbuffers::String* code = mNet->net->bizCode();
|
|
|
|
return code->c_str();
|
|
|
|
}
|
2019-06-17 20:10:35 +08:00
|
|
|
|
|
|
|
std::pair<const void*, size_t> Interpreter::getModelBuffer() const {
|
|
|
|
return std::make_pair(mNet->buffer.get(), mNet->buffer.size());
|
|
|
|
}
|
|
|
|
ErrorCode Interpreter::updateSessionToModel(Session* session) {
|
|
|
|
if (mNet->buffer.get() == nullptr) {
|
|
|
|
MNN_ERROR("Can't updateSessionToModel because you called releaseModel before\n");
|
|
|
|
return INPUT_DATA_ERROR;
|
|
|
|
}
|
|
|
|
return session->updateToModel((Net*)mNet->net);
|
|
|
|
}
|
|
|
|
|
2019-04-17 10:49:11 +08:00
|
|
|
} // namespace MNN
|