Compare commits

...

3 Commits

Author SHA1 Message Date
wdp
09bdd8007d 【更新】center-face检测功能调试完成 2025-01-18 21:12:51 +08:00
wdp
cd9d81e0e4 【新增】算法模型 2025-01-18 21:11:56 +08:00
wdp
4b43617901 【新增】MNN依赖库 2025-01-18 21:11:17 +08:00
55 changed files with 4633 additions and 22 deletions

View File

@@ -5,6 +5,7 @@
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/3rd/**",
"${workspaceFolder}/models/**",
],
"defines": [
"_DEBUG",

62
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,62 @@
{
"files.associations": {
"*.inc": "c",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"typeinfo": "cpp"
}
}

6
.vscode/tasks.json vendored
View File

@@ -11,13 +11,13 @@
"-build_type",
"Release",
"-build_and_run",
"false",
"true",
"-platform",
"win"
],
"group": {
"kind": "build",
"isDefault": false
"isDefault": true
},
"presentation": {
"reveal": "silent"
@@ -40,7 +40,7 @@
],
"group": {
"kind": "build",
"isDefault": true
"isDefault": false
},
"presentation": {
"reveal": "silent"

View File

@@ -0,0 +1,58 @@
//
// AutoTime.hpp
// MNN
//
// Created by MNN on 2018/07/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef AutoTime_hpp
#define AutoTime_hpp
#include <stdint.h>
#include <stdio.h>
#include <MNN/MNNDefine.h>
namespace MNN {
class MNN_PUBLIC Timer {
public:
Timer();
~Timer();
Timer(const Timer&) = delete;
Timer(const Timer&&) = delete;
Timer& operator=(const Timer&) = delete;
Timer& operator=(const Timer&&) = delete;
// reset timer
void reset();
// get duration (us) from init or latest reset.
uint64_t durationInUs();
protected:
uint64_t mLastResetTime;
};
/** time tracing util. prints duration between init and deinit. */
class MNN_PUBLIC AutoTime : Timer {
public:
AutoTime(int line, const char* func);
~AutoTime();
AutoTime(const AutoTime&) = delete;
AutoTime(const AutoTime&&) = delete;
AutoTime& operator=(const AutoTime&) = delete;
AutoTime& operator=(const AutoTime&&) = delete;
private:
int mLine;
char* mName;
};
} // namespace MNN
#ifdef MNN_OPEN_TIME_TRACE
#define AUTOTIME MNN::AutoTime ___t(__LINE__, __func__)
#else
#define AUTOTIME
#endif
#endif /* AutoTime_hpp */

View File

@@ -0,0 +1,34 @@
//
// ErrorCode.hpp
// MNN
//
// Created by MNN on 2018/09/18.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef ErrorCode_h
#define ErrorCode_h
namespace MNN {
enum ErrorCode {
#ifdef NO_ERROR
#undef NO_ERROR
#endif // NO_ERROR
NO_ERROR = 0,
OUT_OF_MEMORY = 1,
NOT_SUPPORT = 2,
COMPUTE_SIZE_ERROR = 3,
NO_EXECUTION = 4,
INVALID_VALUE = 5,
// User error
INPUT_DATA_ERROR = 10,
CALL_BACK_STOP = 11,
// Op Resize Error
TENSOR_NOT_SUPPORT = 20,
TENSOR_NEED_DIVIDE = 21,
};
} // namespace MNN
#endif /* ErrorCode_h */

View File

@@ -0,0 +1,307 @@
#ifndef HALIDE_HALIDERUNTIME_H
#define HALIDE_HALIDERUNTIME_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
// Note that you should not use "inline" along with HALIDE_ALWAYS_INLINE;
// it is not necessary, and may produce warnings for some build configurations.
#ifdef _MSC_VER
#define HALIDE_ALWAYS_INLINE __forceinline
#define HALIDE_NEVER_INLINE __declspec(noinline)
#else
#define HALIDE_ALWAYS_INLINE __attribute__((always_inline)) inline
#define HALIDE_NEVER_INLINE __attribute__((noinline))
#endif
/** \file
*
* This file declares the routines used by Halide internally in its
* runtime. On platforms that support weak linking, these can be
* replaced with user-defined versions by defining an extern "C"
* function with the same name and signature.
*
* When doing Just In Time (JIT) compilation methods on the Func being
* compiled must be called instead. The corresponding methods are
* documented below.
*
* All of these functions take a "void *user_context" parameter as their
* first argument; if the Halide kernel that calls back to any of these
* functions has been compiled with the UserContext feature set on its Target,
* then the value of that pointer passed from the code that calls the
* Halide kernel is piped through to the function.
*
* Some of these are also useful to call when using the default
* implementation. E.g. halide_shutdown_thread_pool.
*
* Note that even on platforms with weak linking, some linker setups
* may not respect the override you provide. E.g. if the override is
* in a shared library and the halide object files are linked directly
* into the output, the builtin versions of the runtime functions will
* be called. See your linker documentation for more details. On
* Linux, LD_DYNAMIC_WEAK=1 may help.
*
*/
// Forward-declare to suppress warnings if compiling as C.
struct halide_buffer_t;
/** Types in the halide type system. They can be ints, unsigned ints,
* or floats (of various bit-widths), or a handle (which is always 64-bits).
* Note that the int/uint/float values do not imply a specific bit width
* (the bit width is expected to be encoded in a separate value).
*/
typedef enum halide_type_code_t
{
halide_type_int = 0, //!< signed integers
halide_type_uint = 1, //!< unsigned integers
halide_type_float = 2, //!< floating point numbers
halide_type_handle = 3 //!< opaque pointer type (void *)
} halide_type_code_t;
// Note that while __attribute__ can go before or after the declaration,
// __declspec apparently is only allowed before.
#ifndef HALIDE_ATTRIBUTE_ALIGN
#ifdef _MSC_VER
#define HALIDE_ATTRIBUTE_ALIGN(x) __declspec(align(x))
#else
#define HALIDE_ATTRIBUTE_ALIGN(x) __attribute__((aligned(x)))
#endif
#endif
/** A runtime tag for a type in the halide type system. Can be ints,
* unsigned ints, or floats of various bit-widths (the 'bits'
* field). Can also be vectors of the same (by setting the 'lanes'
* field to something larger than one). This struct should be
* exactly 32-bits in size. */
struct halide_type_t {
/** The basic type code: signed integer, unsigned integer, or floating point. */
#if __cplusplus >= 201103L
HALIDE_ATTRIBUTE_ALIGN(1) halide_type_code_t code; // halide_type_code_t
#else
HALIDE_ATTRIBUTE_ALIGN(1) uint8_t code; // halide_type_code_t
#endif
/** The number of bits of precision of a single scalar value of this type. */
HALIDE_ATTRIBUTE_ALIGN(1) uint8_t bits;
/** How many elements in a vector. This is 1 for scalar types. */
HALIDE_ATTRIBUTE_ALIGN(2) uint16_t lanes;
#ifdef __cplusplus
/** Construct a runtime representation of a Halide type from:
* code: The fundamental type from an enum.
* bits: The bit size of one element.
* lanes: The number of vector elements in the type. */
HALIDE_ALWAYS_INLINE halide_type_t(halide_type_code_t code, uint8_t bits, uint16_t lanes = 1)
: code(code), bits(bits), lanes(lanes) {
}
/** Default constructor is required e.g. to declare halide_trace_event
* instances. */
HALIDE_ALWAYS_INLINE halide_type_t() : code((halide_type_code_t)0), bits(0), lanes(0) {}
/** Compare two types for equality. */
HALIDE_ALWAYS_INLINE bool operator==(const halide_type_t &other) const {
return (code == other.code &&
bits == other.bits &&
lanes == other.lanes);
}
HALIDE_ALWAYS_INLINE bool operator!=(const halide_type_t &other) const {
return !(*this == other);
}
/** Size in bytes for a single element, even if width is not 1, of this type. */
HALIDE_ALWAYS_INLINE int bytes() const { return (bits + 7) / 8; }
#endif
};
/** An opaque struct containing per-GPU API implementations of the
* device functions. */
struct halide_device_interface_impl_t;
/** Each GPU API provides a halide_device_interface_t struct pointing
* to the code that manages device allocations. You can access these
* functions directly from the struct member function pointers, or by
* calling the functions declared below. Note that the global
* functions are not available when using Halide as a JIT compiler.
* If you are using raw halide_buffer_t in that context you must use
* the function pointers in the device_interface struct.
*
* The function pointers below are currently the same for every GPU
* API; only the impl field varies. These top-level functions do the
* bookkeeping that is common across all GPU APIs, and then dispatch
* to more API-specific functions via another set of function pointers
* hidden inside the impl field.
*/
struct halide_device_interface_t {
int (*device_malloc)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_free)(void *user_context, struct halide_buffer_t *buf);
int (*device_sync)(void *user_context, struct halide_buffer_t *buf);
void (*device_release)(void *user_context,
const struct halide_device_interface_t *device_interface);
int (*copy_to_host)(void *user_context, struct halide_buffer_t *buf);
int (*copy_to_device)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_and_host_malloc)(void *user_context, struct halide_buffer_t *buf,
const struct halide_device_interface_t *device_interface);
int (*device_and_host_free)(void *user_context, struct halide_buffer_t *buf);
int (*buffer_copy)(void *user_context, struct halide_buffer_t *src,
const struct halide_device_interface_t *dst_device_interface, struct halide_buffer_t *dst);
int (*device_crop)(void *user_context, const struct halide_buffer_t *src,
struct halide_buffer_t *dst);
int (*device_release_crop)(void *user_context, struct halide_buffer_t *buf);
int (*wrap_native)(void *user_context, struct halide_buffer_t *buf, uint64_t handle,
const struct halide_device_interface_t *device_interface);
int (*detach_native)(void *user_context, struct halide_buffer_t *buf);
const struct halide_device_interface_impl_t *impl;
};
typedef struct halide_dimension_t {
int32_t min, extent, stride;
// Per-dimension flags. None are defined yet (This is reserved for future use).
uint32_t flags;
#ifdef __cplusplus
HALIDE_ALWAYS_INLINE halide_dimension_t() : min(0), extent(0), stride(0), flags(0) {}
HALIDE_ALWAYS_INLINE halide_dimension_t(int32_t m, int32_t e, int32_t s, uint32_t f = 0) :
min(m), extent(e), stride(s), flags(f) {}
HALIDE_ALWAYS_INLINE bool operator==(const halide_dimension_t &other) const {
return (min == other.min) &&
(extent == other.extent) &&
(stride == other.stride) &&
(flags == other.flags);
}
HALIDE_ALWAYS_INLINE bool operator!=(const halide_dimension_t &other) const {
return !(*this == other);
}
#endif
} halide_dimension_t;
#ifdef __cplusplus
} // extern "C"
#endif
typedef enum {halide_buffer_flag_host_dirty = 1,
halide_buffer_flag_device_dirty = 2} halide_buffer_flags;
/**
* The raw representation of an image passed around by generated
* Halide code. It includes some stuff to track whether the image is
* not actually in main memory, but instead on a device (like a
* GPU). For a more convenient C++ wrapper, use Halide::Buffer<T>. */
typedef struct halide_buffer_t {
/** A device-handle for e.g. GPU memory used to back this buffer. */
uint64_t device;
/** The interface used to interpret the above handle. */
const struct halide_device_interface_t *device_interface;
/** A pointer to the start of the data in main memory. In terms of
* the Halide coordinate system, this is the address of the min
* coordinates (defined below). */
uint8_t* host;
/** flags with various meanings. */
uint64_t flags;
/** The type of each buffer element. */
struct halide_type_t type;
/** The dimensionality of the buffer. */
int32_t dimensions;
/** The shape of the buffer. Halide does not own this array - you
* must manage the memory for it yourself. */
halide_dimension_t *dim;
/** Pads the buffer up to a multiple of 8 bytes */
void *padding;
} halide_buffer_t;
#ifdef __cplusplus
namespace {
template<typename T> struct check_is_pointer;
template<typename T> struct check_is_pointer<T *> {};
}
/** Construct the halide equivalent of a C type */
template<typename T>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of() {
// Create a compile-time error if T is not a pointer (without
// using any includes - this code goes into the runtime).
check_is_pointer<T> check;
(void)check;
return halide_type_t(halide_type_handle, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<float>() {
return halide_type_t(halide_type_float, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<double>() {
return halide_type_t(halide_type_float, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<bool>() {
return halide_type_t(halide_type_uint, 1);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint8_t>() {
return halide_type_t(halide_type_uint, 8);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint16_t>() {
return halide_type_t(halide_type_uint, 16);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint32_t>() {
return halide_type_t(halide_type_uint, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<uint64_t>() {
return halide_type_t(halide_type_uint, 64);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int8_t>() {
return halide_type_t(halide_type_int, 8);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int16_t>() {
return halide_type_t(halide_type_int, 16);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int32_t>() {
return halide_type_t(halide_type_int, 32);
}
template<>
HALIDE_ALWAYS_INLINE halide_type_t halide_type_of<int64_t>() {
return halide_type_t(halide_type_int, 64);
}
#endif
#endif // HALIDE_HALIDERUNTIME_H

View File

@@ -0,0 +1,145 @@
//
// ImageProcess.hpp
// MNN
//
// Created by MNN on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef ImageProcess_hpp
#define ImageProcess_hpp
#include <MNN/ErrorCode.hpp>
#include <MNN/Matrix.h>
#include <MNN/Tensor.hpp>
namespace MNN {
namespace CV {
enum ImageFormat {
RGBA = 0,
RGB,
BGR,
GRAY,
BGRA,
YUV_NV21 = 11,
YUV_NV12 = 12,
YUV_I420 = 13,
};
enum Filter { NEAREST = 0, BILINEAR = 1, BICUBIC = 2 };
enum Wrap { CLAMP_TO_EDGE = 0, ZERO = 1, REPEAT = 2 };
/**
* handle image process for tensor.
* step:
* 1: Do transform compute and get points
* 2: Sample line and do format convert
* 3: Turn RGBA to float tensor, and do sub and normalize
*/
class MNN_PUBLIC ImageProcess {
public:
struct Inside;
struct Config {
/** data filter */
Filter filterType = NEAREST;
/** format of source data */
ImageFormat sourceFormat = RGBA;
/** format of destination data */
ImageFormat destFormat = RGBA;
// Only valid if the dest type is float
float mean[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float normal[4] = {1.0f, 1.0f, 1.0f, 1.0f};
/** edge wrapper */
Wrap wrap = CLAMP_TO_EDGE;
};
public:
/**
* @brief create image process with given config for given tensor.
* @param config given config.
* @param dstTensor given tensor.
* @return image processor.
*/
static ImageProcess* create(const Config& config, const Tensor* dstTensor = nullptr);
/**
* @brief create image process with given config for given tensor.
* @param means given means
* @param meanCount given means count
* @param normals given normals
* @param normalCount given normal count
* @param sourceFormat format of source data
* @param destFormat format of destination data
* @param dstTensor given tensor.
* @return image processor.
*/
static ImageProcess* create(const ImageFormat sourceFormat = RGBA, const ImageFormat destFormat = RGBA,
const float* means = nullptr, const int meanCount = 0, const float* normals = nullptr,
const int normalCount = 0, const Tensor* dstTensor = nullptr);
~ImageProcess();
/**
* @brief get affine transform matrix.
* @return affine transform matrix.
*/
inline const Matrix& matrix() const {
return mTransform;
}
void setMatrix(const Matrix& matrix);
/**
* @brief convert source data to given tensor.
* @param source source data.
* @param iw source width.
* @param ih source height.
* @param stride number of elements per row. eg: 100 width RGB contains at least 300 elements.
* @param dest given tensor.
* @return result code.
*/
ErrorCode convert(const uint8_t* source, int iw, int ih, int stride, Tensor* dest);
/**
* @brief convert source data to given tensor.
* @param source source data.
* @param iw source width.
* @param ih source height.
* @param stride number of elements per row. eg: 100 width RGB contains at least 300 elements.
* @param dest dest data.
* @param ow output width.
* @param oh output height.
* @param outputBpp output bpp, if 0, set as the save and config.destFormat.
* @param outputStride output stride, if 0, set as ow * outputBpp.
* @param type Only support halide_type_of<uint8_t> and halide_type_of<float>.
* @return result code.
*/
ErrorCode convert(const uint8_t* source, int iw, int ih, int stride, void* dest, int ow, int oh, int outputBpp = 0,
int outputStride = 0, halide_type_t type = halide_type_of<float>());
/**
* @brief create tensor with given data.
* @param w image width.
* @param h image height.
* @param bpp bytes per pixel.
* @param p pixel data pointer.
* @return created tensor.
*/
template <typename T>
static Tensor* createImageTensor(int w, int h, int bpp, void* p = nullptr) {
return createImageTensor(halide_type_of<T>(), w, h, bpp, p);
}
static Tensor* createImageTensor(halide_type_t type, int w, int h, int bpp, void* p = nullptr);
private:
ImageProcess(const Config& config);
Matrix mTransform;
Matrix mTransformInvert;
Inside* mInside;
};
} // namespace CV
} // namespace MNN
#endif /* ImageProcess_hpp */

View File

@@ -0,0 +1,340 @@
//
// Interpreter.hpp
// MNN
//
// Created by MNN on 2018/07/23.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Interpreter_hpp
#define Interpreter_hpp
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <MNN/ErrorCode.hpp>
#include <MNN/MNNForwardType.h>
#include <MNN/Tensor.hpp>
namespace MNN {
/** session schedule config */
struct ScheduleConfig {
/** which tensor should be kept */
std::vector<std::string> saveTensors;
/** forward type */
MNNForwardType type = MNN_FORWARD_CPU;
/** number of threads in parallel */
int numThread = 4;
/** subpath to run */
struct Path {
std::vector<std::string> inputs;
std::vector<std::string> outputs;
enum Mode {
/**
* Op Mode
* - inputs means the source op, can NOT be empty.
* - outputs means the sink op, can be empty.
* The path will start from source op, then flow when encounter the sink op.
* The sink op will not be compute in this path.
*/
Op = 0,
/**
* Tensor Mode (NOT supported yet)
* - inputs means the inputs tensors, can NOT be empty.
* - outputs means the outputs tensors, can NOT be empty.
* It will find the pipeline that compute outputs from inputs.
*/
Tensor = 1
};
/** running mode */
Mode mode = Op;
};
Path path;
/** backup backend used to create execution when desinated backend do NOT support any op */
MNNForwardType backupType = MNN_FORWARD_CPU;
/** extra backend config */
BackendConfig* backendConfig = nullptr;
};
class Session;
struct Content;
class Tensor;
class Backend;
class Runtime;
class MNN_PUBLIC OperatorInfo {
struct Info;
public:
/** Operator's name*/
const std::string& name() const;
/** Operator's type*/
const std::string& type() const;
/** Operator's flops, in M*/
float flops() const;
protected:
OperatorInfo();
~OperatorInfo();
Info* mContent;
};
typedef std::function<bool(const std::vector<Tensor*>&, const std::string& /*opName*/)> TensorCallBack;
typedef std::function<bool(const std::vector<Tensor*>&, const OperatorInfo*)> TensorCallBackWithInfo;
typedef std::pair<std::map<MNNForwardType, std::shared_ptr<Runtime>>, std::shared_ptr<Runtime>> RuntimeInfo;
/** net data holder. multiple sessions could share same net. */
class MNN_PUBLIC Interpreter {
public:
/**
* @brief create net from file.
* @param file given file.
* @return created net if success, NULL otherwise.
*/
static Interpreter* createFromFile(const char* file);
/**
* @brief create net from buffer.
* @param buffer given data buffer.
* @param size size of data buffer.
* @return created net if success, NULL otherwise.
*/
static Interpreter* createFromBuffer(const void* buffer, size_t size);
~Interpreter();
enum SessionMode {
/** About CallBack, Default Session_Debug*/
/** runSessionWithCallBack is allowed and can get internal op info*/
Session_Debug = 0,
/** runSessionWithCallBack is not valid and can't get any info of op in session*/
Session_Release = 1,
/** About input tenosr, Default Session_Input_Inside*/
/** The input tensor is alloced by session, input data after session resized*/
Session_Input_Inside = 2,
/** The input tensor is alloced by user, set input data before session resize*/
Session_Input_User = 3,
};
/**
* @brief The API shoud be called before create session.
* @param mode session mode
* @return void
*/
void setSessionMode(SessionMode mode);
/**
* @brief The API shoud be called before create session.
* If the cache exist, try to load cache from file.
* After createSession, try to save cache to file.
* @param cacheFile cache file name
* @param keySize the first `keySize` bytes used as the key to check if the `cacheFile` exists.
* @return void
*/
void setCacheFile(const char* cacheFile, size_t keySize = 128);
public:
/**
* @brief create runtimeInfo seperately with schedule config.
* @param config session schedule configs.
*/
static RuntimeInfo createRuntime(const std::vector<ScheduleConfig>& configs);
/**
* @brief create session with schedule config. created session will be managed in net.
* @param config session schedule config.
* @return created session if success, NULL otherwise.
*/
Session* createSession(const ScheduleConfig& config);
/**
* @brief create session with schedule config and user-specified runtime.
* @param config session schedule config, runtime runtimeInfo used by the created session.
* @return created session if success, NULL otherwise.
*/
Session* createSession(const ScheduleConfig& config, const RuntimeInfo& runtime);
/**
* @brief create multi-path session with schedule configs. created session will be managed in net.
* @param configs session schedule configs.
* @return created session if success, NULL otherwise.
*/
Session* createMultiPathSession(const std::vector<ScheduleConfig>& configs);
/**
* @brief create multi-path session with schedule configs and user-specified runtime.
created session will be managed in net.
* @param configs session schedule configs.
* @return created session if success, NULL otherwise.
*/
Session* createMultiPathSession(const std::vector<ScheduleConfig>& configs, const RuntimeInfo& runtime);
/**
* @brief release session.
* @param session given session.
* @return true if given session is held by net and is freed.
*/
bool releaseSession(Session* session);
/**
* @brief call this function to get tensors ready. output tensor buffer (host or deviceId) should be retrieved
* after resize of any input tensor.
* @param session given session.
*/
void resizeSession(Session* session);
/**
* @brief call this function if don't need resize or create session any more, it will save a few memory that equal
* to the size of model buffer
*/
void releaseModel();
/**
* @brief Get the model buffer for user to save
* @return std::make_pair(modleBuffer, modelSize).
* @example:
* std::ofstream output("trainResult.alinn")
* auto buffer = net->getModelBuffer();
* output.write((const char*)buffer.first, buffer.second);
*/
std::pair<const void*, size_t> getModelBuffer() const;
/**
* @brief update Session's Tensor to model's Const Op
* @param session given session.
* @return result of running.
*/
ErrorCode updateSessionToModel(Session* session);
/**
* @brief run session.
* @param session given session.
* @return result of running.
*/
ErrorCode runSession(Session* session) const;
/*
* @brief run session.
* @param session given session.
* @param before callback before each op. return true to run the op; return false to skip the op.
* @param after callback after each op. return true to continue running; return false to interrupt the session.
* @param sync synchronously wait for finish of execution or not.
* @return result of running.
*/
ErrorCode runSessionWithCallBack(const Session* session, const TensorCallBack& before, const TensorCallBack& end,
bool sync = false) const;
/*
* @brief run session.
* @param session given session.
* @param before callback before each op. return true to run the op; return false to skip the op.
* @param after callback after each op. return true to continue running; return false to interrupt the session.
* @param sync synchronously wait for finish of execution or not.
* @return result of running.
*/
ErrorCode runSessionWithCallBackInfo(const Session* session, const TensorCallBackWithInfo& before,
const TensorCallBackWithInfo& end, bool sync = false) const;
/**
* @brief get input tensor for given name.
* @param session given session.
* @param name given name. if NULL, return first input.
* @return tensor if found, NULL otherwise.
*/
Tensor* getSessionInput(const Session* session, const char* name);
/**
* @brief get output tensor for given name.
* @param session given session.
* @param name given name. if NULL, return first output.
* @return tensor if found, NULL otherwise.
*/
Tensor* getSessionOutput(const Session* session, const char* name);
enum SessionInfoCode {
/** memory session used in MB, float* */
MEMORY = 0,
/** float operation needed in session in M, float* */
FLOPS = 1,
/** Backends in session in M, int*, length >= the configs when create session */
BACKENDS = 2,
ALL
};
/**
* @brief get session info
* @param session given session.
* @param code given info code.
* @param void* given info ptr, see SessionInfoCode for detail
* @return true if support the code, false otherwise.
*/
bool getSesionInfo(const Session* session, SessionInfoCode code, void* ptr);
/**
* @brief get all output tensors.
* @param session given session.
* @return all output tensors mapped with name.
*/
const std::map<std::string, Tensor*>& getSessionOutputAll(const Session* session) const;
/**
* @brief get all input tensors.
* @param session given session.
* @return all input tensors mapped with name.
*/
const std::map<std::string, Tensor*>& getSessionInputAll(const Session* session) const;
public:
/**
* @brief resize given tensor.
* @param tensor given tensor.
* @param dims new dims. at most 6 dims.
*/
void resizeTensor(Tensor* tensor, const std::vector<int>& dims);
/**
* @brief resize given tensor by nchw.
* @param batch / N.
* @param channel / C.
* @param height / H.
* @param width / W
*/
void resizeTensor(Tensor* tensor, int batch, int channel, int height, int width);
/**
* @brief get backend used to create given tensor.
* @param session given session.
* @param tensor given tensor.
* @return backend used to create given tensor, may be NULL.
*/
const Backend* getBackend(const Session* session, const Tensor* tensor) const;
/**
* @brief get business code (model identifier).
* @return business code.
*/
const char* bizCode() const;
private:
static Interpreter* createFromBufferInternal(Content* net);
Content* mNet = nullptr;
Interpreter(Content* net);
Interpreter(const Interpreter&) = delete;
Interpreter(const Interpreter&&) = delete;
Interpreter& operator=(const Interpreter&) = delete;
Interpreter& operator=(const Interpreter&&) = delete;
};
} // namespace MNN
#endif /* Interpreter_hpp */

View File

@@ -0,0 +1,64 @@
//
// MNNDefine.h
// MNN
//
// Created by MNN on 2018/08/09.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MNNDefine_h
#define MNNDefine_h
#include <assert.h>
#include <stdio.h>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#define MNN_BUILD_FOR_IOS
#endif
#endif
#ifdef MNN_USE_LOGCAT
#include <android/log.h>
#define MNN_ERROR(format, ...) __android_log_print(ANDROID_LOG_ERROR, "MNNJNI", format, ##__VA_ARGS__)
#define MNN_PRINT(format, ...) __android_log_print(ANDROID_LOG_INFO, "MNNJNI", format, ##__VA_ARGS__)
#else
#define MNN_PRINT(format, ...) printf(format, ##__VA_ARGS__)
#define MNN_ERROR(format, ...) printf(format, ##__VA_ARGS__)
#endif
#ifdef DEBUG
#define MNN_ASSERT(x) \
{ \
int res = (x); \
if (!res) { \
MNN_ERROR("Error for %s, %d\n", __FILE__, __LINE__); \
assert(res); \
} \
}
#else
#define MNN_ASSERT(x)
#endif
#define FUNC_PRINT(x) MNN_PRINT(#x "=%d in %s, %d \n", x, __func__, __LINE__);
#define FUNC_PRINT_ALL(x, type) MNN_PRINT(#x "=" #type " %" #type " in %s, %d \n", x, __func__, __LINE__);
#define MNN_CHECK(success, log) \
if(!(success)){ \
MNN_ERROR("Check failed: %s ==> %s\n", #success, #log); \
}
#if defined(_MSC_VER)
#if defined(BUILDING_MNN_DLL)
#define MNN_PUBLIC __declspec(dllexport)
#elif defined(USING_MNN_DLL)
#define MNN_PUBLIC __declspec(dllimport)
#else
#define MNN_PUBLIC
#endif
#else
#define MNN_PUBLIC __attribute__((visibility("default")))
#endif
#endif /* MNNDefine_h */

View File

@@ -0,0 +1,75 @@
//
// MNNForwardType.h
// MNN
//
// Created by MNN on 2019/01/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MNNForwardType_h
#define MNNForwardType_h
#include <stdint.h>
#include <stddef.h>
typedef enum {
MNN_FORWARD_CPU = 0,
/*
Firtly find the first available backends not equal to CPU
If no other backends, use cpu
*/
MNN_FORWARD_AUTO = 4,
/*Hand write metal*/
MNN_FORWARD_METAL = 1,
/*NVIDIA GPU API*/
MNN_FORWARD_CUDA = 2,
/*Android / Common Device GPU API*/
MNN_FORWARD_OPENCL = 3,
MNN_FORWARD_OPENGL = 6,
MNN_FORWARD_VULKAN = 7,
/*Android 8.1's NNAPI, Not Support yet*/
MNN_FORWARD_NN = 5,
/*User can use API from Backend.hpp to add or search Backend*/
MNN_FORWARD_USER_0 = 8,
MNN_FORWARD_USER_1 = 9,
MNN_FORWARD_USER_2 = 10,
MNN_FORWARD_USER_3 = 11,
MNN_FORWARD_ALL,
/* Apply arm extension instruction set to accelerate some Ops, this forward type
is only used in MNN internal, and will be active automatically when user set forward type
to be MNN_FORWARD_CPU and extension instruction set is valid on hardware.
*/
MNN_FORWARD_CPU_EXTENSION
} MNNForwardType;
#ifdef __cplusplus
namespace MNN {
struct BackendConfig {
enum MemoryMode { Memory_Normal = 0, Memory_High, Memory_Low };
MemoryMode memory = Memory_Normal;
enum PowerMode { Power_Normal = 0, Power_High, Power_Low };
PowerMode power = Power_Normal;
enum PrecisionMode { Precision_Normal = 0, Precision_High, Precision_Low };
PrecisionMode precision = Precision_Normal;
/** user defined context */
union {
void* sharedContext = nullptr;
size_t flags; // Valid for CPU Backend
};
};
}; // namespace MNN
#endif
#endif /* MNNForwardType_h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,580 @@
//
// Rect.h
// MNN
//
// Modified by jiangxiaotang on 2018/09/19.
// Copyright © 2018, Alibaba Group Holding Limited
//
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Generated by tools/bookmaker from include/core/Rect.h and docs/SkRect_Reference.bmh
on 2018-07-13 08:15:11. Additional documentation and examples can be found at:
https://skia.org/user/api/SkRect_Reference
You may edit either file directly. Structural changes to public interfaces require
editing both files. After editing docs/SkRect_Reference.bmh, run:
bookmaker -b docs -i include/core/Rect.h -p
to create an updated version of this file.
*/
#ifndef SkRect_DEFINED
#define SkRect_DEFINED
#include <math.h>
#include <algorithm>
#include <utility>
#include <MNN/MNNDefine.h>
namespace MNN {
namespace CV {
struct Point {
float fX;
float fY;
void set(float x, float y) {
fX = x;
fY = y;
}
};
/** \struct Rect
Rect holds four float coordinates describing the upper and
lower bounds of a rectangle. Rect may be created from outer bounds or
from position, width, and height. Rect describes an area; if its right
is less than or equal to its left, or if its bottom is less than or equal to
its top, it is considered empty.
*/
struct MNN_PUBLIC Rect {
float fLeft; //!< smaller x-axis bounds
float fTop; //!< smaller y-axis bounds
float fRight; //!< larger x-axis bounds
float fBottom; //!< larger y-axis bounds
/** Returns constructed Rect set to (0, 0, 0, 0).
Many other rectangles are empty; if left is equal to or greater than right,
or if top is equal to or greater than bottom. Setting all members to zero
is a convenience, but does not designate a special empty rectangle.
@return bounds (0, 0, 0, 0)
*/
static constexpr Rect MakeEmpty() {
return Rect{0, 0, 0, 0};
}
#ifdef SK_SUPPORT_LEGACY_RECTMAKELARGEST
/** Deprecated.
*/
static Rect MakeLargest() {
return {SK_ScalarMin, SK_ScalarMin, SK_ScalarMax, SK_ScalarMax};
}
#endif
/** Returns constructed Rect set to float values (0, 0, w, h). Does not
validate input; w or h may be negative.
Passing integer values may generate a compiler warning since Rect cannot
represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle.
@param w float width of constructed Rect
@param h float height of constructed Rect
@return bounds (0, 0, w, h)
*/
static constexpr Rect MakeWH(float w, float h) {
return Rect{0, 0, w, h};
}
/** Returns constructed Rect set to integer values (0, 0, w, h). Does not validate
input; w or h may be negative.
Use to avoid a compiler warning that input may lose precision when stored.
Use SkIRect for an exact integer rectangle.
@param w integer width of constructed Rect
@param h integer height of constructed Rect
@return bounds (0, 0, w, h)
*/
static Rect MakeIWH(int w, int h) {
Rect r;
r.set(0, 0, (float)(w), (float)(h));
return r;
}
/** Returns constructed Rect set to (l, t, r, b). Does not sort input; Rect may
result in fLeft greater than fRight, or fTop greater than fBottom.
@param l float stored in fLeft
@param t float stored in fTop
@param r float stored in fRight
@param b float stored in fBottom
@return bounds (l, t, r, b)
*/
static constexpr Rect MakeLTRB(float l, float t, float r, float b) {
return Rect{l, t, r, b};
}
/** Returns constructed Rect set to (x, y, x + w, y + h). Does not validate input;
w or h may be negative.
@param x stored in fLeft
@param y stored in fTop
@param w added to x and stored in fRight
@param h added to y and stored in fBottom
@return bounds at (x, y) with width w and height h
*/
static constexpr Rect MakeXYWH(float x, float y, float w, float h) {
return Rect{x, y, x + w, y + h};
}
/** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal
to or greater than fBottom. Call sort() to reverse rectangles with negative
width() or height().
@return true if width() or height() are zero or negative
*/
bool isEmpty() const {
// We write it as the NOT of a non-empty rect, so we will return true if any values
// are NaN.
return !(fLeft < fRight && fTop < fBottom);
}
/** Returns true if fLeft is equal to or less than fRight, or if fTop is equal
to or less than fBottom. Call sort() to reverse rectangles with negative
width() or height().
@return true if width() or height() are zero or positive
*/
bool isSorted() const {
return fLeft <= fRight && fTop <= fBottom;
}
/** Returns left edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fLeft
*/
float x() const {
return fLeft;
}
/** Returns top edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fTop
*/
float y() const {
return fTop;
}
/** Returns left edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fLeft
*/
float left() const {
return fLeft;
}
/** Returns top edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fTop
*/
float top() const {
return fTop;
}
/** Returns right edge of Rect, if sorted. Call isSorted() to see if Rect is valid.
Call sort() to reverse fLeft and fRight if needed.
@return fRight
*/
float right() const {
return fRight;
}
/** Returns bottom edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid,
and sort() to reverse fTop and fBottom if needed.
@return fBottom
*/
float bottom() const {
return fBottom;
}
/** Returns span on the x-axis. This does not check if Rect is sorted, or if
result fits in 32-bit float; result may be negative or infinity.
@return fRight minus fLeft
*/
float width() const {
return fRight - fLeft;
}
/** Returns span on the y-axis. This does not check if Rect is sorted, or if
result fits in 32-bit float; result may be negative or infinity.
@return fBottom minus fTop
*/
float height() const {
return fBottom - fTop;
}
/** Returns average of left edge and right edge. Result does not change if Rect
is sorted. Result may overflow to infinity if Rect is far from the origin.
@return midpoint in x
*/
float centerX() const {
// don't use floatHalf(fLeft + fBottom) as that might overflow before the 0.5
return 0.5f * (fLeft) + 0.5f * (fRight);
}
/** Returns average of top edge and bottom edge. Result does not change if Rect
is sorted.
@return midpoint in y
*/
float centerY() const {
// don't use floatHalf(fTop + fBottom) as that might overflow before the 0.5
return 0.5f * (fTop) + 0.5f * (fBottom);
}
/** Sets Rect to (0, 0, 0, 0).
Many other rectangles are empty; if left is equal to or greater than right,
or if top is equal to or greater than bottom. Setting all members to zero
is a convenience, but does not designate a special empty rectangle.
*/
void setEmpty() {
*this = MakeEmpty();
}
/** Sets Rect to (left, top, right, bottom).
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left stored in fLeft
@param top stored in fTop
@param right stored in fRight
@param bottom stored in fBottom
*/
void set(float left, float top, float right, float bottom) {
fLeft = left;
fTop = top;
fRight = right;
fBottom = bottom;
}
/** Sets Rect to (left, top, right, bottom).
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left stored in fLeft
@param top stored in fTop
@param right stored in fRight
@param bottom stored in fBottom
*/
void setLTRB(float left, float top, float right, float bottom) {
this->set(left, top, right, bottom);
}
/** Sets Rect to (left, top, right, bottom).
All parameters are promoted from integer to scalar.
left and right are not sorted; left is not necessarily less than right.
top and bottom are not sorted; top is not necessarily less than bottom.
@param left promoted to float and stored in fLeft
@param top promoted to float and stored in fTop
@param right promoted to float and stored in fRight
@param bottom promoted to float and stored in fBottom
*/
void iset(int left, int top, int right, int bottom) {
fLeft = (float)(left);
fTop = (float)(top);
fRight = (float)(right);
fBottom = (float)(bottom);
}
/** Sets Rect to (0, 0, width, height).
width and height may be zero or negative. width and height are promoted from
integer to float, large values may lose precision.
@param width promoted to float and stored in fRight
@param height promoted to float and stored in fBottom
*/
void isetWH(int width, int height) {
fLeft = fTop = 0;
fRight = (float)(width);
fBottom = (float)(height);
}
/** Sets Rect to (x, y, x + width, y + height). Does not validate input;
width or height may be negative.
@param x stored in fLeft
@param y stored in fTop
@param width added to x and stored in fRight
@param height added to y and stored in fBottom
*/
void setXYWH(float x, float y, float width, float height) {
fLeft = x;
fTop = y;
fRight = x + width;
fBottom = y + height;
}
/** Sets Rect to (0, 0, width, height). Does not validate input;
width or height may be negative.
@param width stored in fRight
@param height stored in fBottom
*/
void setWH(float width, float height) {
fLeft = 0;
fTop = 0;
fRight = width;
fBottom = height;
}
/** Returns Rect offset by (dx, dy).
If dx is negative, Rect returned is moved to the left.
If dx is positive, Rect returned is moved to the right.
If dy is negative, Rect returned is moved upward.
If dy is positive, Rect returned is moved downward.
@param dx added to fLeft and fRight
@param dy added to fTop and fBottom
@return Rect offset on axes, with original width and height
*/
Rect makeOffset(float dx, float dy) const {
return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
}
/** Returns Rect, inset by (dx, dy).
If dx is negative, Rect returned is wider.
If dx is positive, Rect returned is narrower.
If dy is negative, Rect returned is taller.
If dy is positive, Rect returned is shorter.
@param dx added to fLeft and subtracted from fRight
@param dy added to fTop and subtracted from fBottom
@return Rect inset symmetrically left and right, top and bottom
*/
Rect makeInset(float dx, float dy) const {
return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
}
/** Returns Rect, outset by (dx, dy).
If dx is negative, Rect returned is narrower.
If dx is positive, Rect returned is wider.
If dy is negative, Rect returned is shorter.
If dy is positive, Rect returned is taller.
@param dx subtracted to fLeft and added from fRight
@param dy subtracted to fTop and added from fBottom
@return Rect outset symmetrically left and right, top and bottom
*/
Rect makeOutset(float dx, float dy) const {
return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
}
/** Offsets Rect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom.
If dx is negative, moves Rect to the left.
If dx is positive, moves Rect to the right.
If dy is negative, moves Rect upward.
If dy is positive, moves Rect downward.
@param dx offset added to fLeft and fRight
@param dy offset added to fTop and fBottom
*/
void offset(float dx, float dy) {
fLeft += dx;
fTop += dy;
fRight += dx;
fBottom += dy;
}
/** Offsets Rect so that fLeft equals newX, and fTop equals newY. width and height
are unchanged.
@param newX stored in fLeft, preserving width()
@param newY stored in fTop, preserving height()
*/
void offsetTo(float newX, float newY) {
fRight += newX - fLeft;
fBottom += newY - fTop;
fLeft = newX;
fTop = newY;
}
/** Insets Rect by (dx, dy).
If dx is positive, makes Rect narrower.
If dx is negative, makes Rect wider.
If dy is positive, makes Rect shorter.
If dy is negative, makes Rect taller.
@param dx added to fLeft and subtracted from fRight
@param dy added to fTop and subtracted from fBottom
*/
void inset(float dx, float dy) {
fLeft += dx;
fTop += dy;
fRight -= dx;
fBottom -= dy;
}
/** Outsets Rect by (dx, dy).
If dx is positive, makes Rect wider.
If dx is negative, makes Rect narrower.
If dy is positive, makes Rect taller.
If dy is negative, makes Rect shorter.
@param dx subtracted to fLeft and added from fRight
@param dy subtracted to fTop and added from fBottom
*/
void outset(float dx, float dy) {
this->inset(-dx, -dy);
}
private:
static bool Intersects(float al, float at, float ar, float ab, float bl, float bt, float br, float bb) {
float L = std::max(al, bl);
float R = std::min(ar, br);
float T = std::max(at, bt);
float B = std::min(ab, bb);
return L < R && T < B;
}
public:
/** Constructs Rect to intersect from (left, top, right, bottom). Does not sort
construction.
Returns true if Rect intersects construction.
Returns false if either construction or Rect is empty, or do not intersect.
@param left x-axis minimum of constructed Rect
@param top y-axis minimum of constructed Rect
@param right x-axis maximum of constructed Rect
@param bottom y-axis maximum of constructed Rect
@return true if construction and Rect have area in common
*/
bool intersects(float left, float top, float right, float bottom) const {
return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
}
/** Returns true if Rect intersects r.
Returns false if either r or Rect is empty, or do not intersect.
@param r Rect to intersect
@return true if r and Rect have area in common
*/
bool intersects(const Rect& r) const {
return Intersects(fLeft, fTop, fRight, fBottom, r.fLeft, r.fTop, r.fRight, r.fBottom);
}
/** Returns true if a intersects b.
Returns false if either a or b is empty, or do not intersect.
@param a Rect to intersect
@param b Rect to intersect
@return true if a and b have area in common
*/
static bool Intersects(const Rect& a, const Rect& b) {
return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom);
}
/** Sets Rect to the union of itself and r.
Asserts if r is empty and SK_DEBUG is defined.
If Rect is empty, sets Rect to r.
May produce incorrect results if r is empty.
@param r expansion Rect
*/
void joinNonEmptyArg(const Rect& r) {
MNN_ASSERT(!r.isEmpty());
// if we are empty, just assign
if (fLeft >= fRight || fTop >= fBottom) {
*this = r;
} else {
this->joinPossiblyEmptyRect(r);
}
}
/** Sets Rect to the union of itself and the construction.
May produce incorrect results if Rect or r is empty.
@param r expansion Rect
*/
void joinPossiblyEmptyRect(const Rect& r) {
fLeft = std::min(fLeft, r.left());
fTop = std::min(fTop, r.top());
fRight = std::max(fRight, r.right());
fBottom = std::max(fBottom, r.bottom());
}
/** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom.
Returns false if Rect is empty.
@param x test Point x-coordinate
@param y test Point y-coordinate
@return true if (x, y) is inside Rect
*/
bool contains(float x, float y) const {
return x >= fLeft && x < fRight && y >= fTop && y < fBottom;
}
/** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps
fTop and fBottom if fTop is greater than fBottom. Result may be empty;
and width() and height() will be zero or positive.
*/
void sort() {
using std::swap;
if (fLeft > fRight) {
swap(fLeft, fRight);
}
if (fTop > fBottom) {
swap(fTop, fBottom);
}
}
/** Returns Rect with fLeft and fRight swapped if fLeft is greater than fRight; and
with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty;
and width() and height() will be zero or positive.
@return sorted Rect
*/
Rect makeSorted() const {
return MakeLTRB(std::min(fLeft, fRight), std::min(fTop, fBottom), std::max(fLeft, fRight),
std::max(fTop, fBottom));
}
/** Returns pointer to first scalar in Rect, to treat it as an array with four
entries.
@return pointer to fLeft
*/
const float* asScalars() const {
return &fLeft;
}
};
} // namespace CV
} // namespace MNN
#endif

View File

@@ -0,0 +1,278 @@
//
// Tensor.hpp
// MNN
//
// Created by MNN on 2018/08/14.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Tensor_hpp
#define Tensor_hpp
#include <vector>
#include <MNN/HalideRuntime.h>
#include <MNN/MNNDefine.h>
#define MNN_MAX_TENSOR_DIM 6
namespace MNN {
/**
* data container.
* data for host tensor is saved in `host` field. its memory is allocated malloc directly.
* data for device tensor is saved in `deviceId` field. its memory is allocated by session's backend.
* usually, device tensors are created by engine (like net, session).
* meanwhile, host tensors could be created by engine or user.
*/
class MNN_PUBLIC Tensor {
public:
struct InsideDescribe;
/** dimension type used to create tensor */
enum DimensionType {
/** for tensorflow net type. uses NHWC as data format. */
TENSORFLOW,
/** for caffe net type. uses NCHW as data format. */
CAFFE,
/** for caffe net type. uses NC4HW4 as data format. */
CAFFE_C4
};
/** handle type */
enum HandleDataType {
/** default handle type */
HANDLE_NONE = 0,
/** string handle type */
HANDLE_STRING = 1
};
public:
/**
* @brief create a tensor with dimension size and type without acquire memory for data.
* @param dimSize dimension size.
* @param type dimension type.
*/
Tensor(int dimSize = 4, DimensionType type = CAFFE);
/**
* @brief create a tensor with same shape as given tensor.
* @param tensor shape provider.
* @param type dimension type.
* @param allocMemory acquire memory for data or not.
* @warning tensor data won't be copied.
*/
Tensor(const Tensor* tensor, DimensionType type = CAFFE, bool allocMemory = true);
/** deinitializer */
~Tensor();
private:
// remove all assignment operator
Tensor(const Tensor& tensor) = delete;
Tensor(const Tensor&& tensor) = delete;
Tensor& operator=(const Tensor&) = delete;
Tensor& operator=(const Tensor&&) = delete;
public:
/**
* @brief create tensor with shape, data type and dimension type.
* @param shape tensor shape.
* @param type data type.
* @param dimType dimension type.
* @return created tensor.
* @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
*/
static Tensor* createDevice(const std::vector<int>& shape, halide_type_t type, DimensionType dimType = TENSORFLOW);
/**
* @brief create tensor with shape and dimension type. data type is represented by `T`.
* @param shape tensor shape.
* @param dimType dimension type.
* @return created tensor.
* @warning memory for data won't be acquired. call backend's onAcquireBuffer to get memory ready.
*/
template <typename T>
static Tensor* createDevice(const std::vector<int>& shape, DimensionType dimType = TENSORFLOW) {
return createDevice(shape, halide_type_of<T>(), dimType);
}
/**
* @brief create tensor with shape, data type, data and dimension type.
* @param shape tensor shape.
* @param type data type.
* @param data data to save.
* @param dimType dimension type.
* @return created tensor.
*/
static Tensor* create(const std::vector<int>& shape, halide_type_t type, void* data = NULL,
DimensionType dimType = TENSORFLOW);
/**
* @brief create tensor with shape, data and dimension type. data type is represented by `T`.
* @param shape tensor shape.
* @param data data to save.
* @param dimType dimension type.
* @return created tensor.
*/
template <typename T>
static Tensor* create(const std::vector<int>& shape, void* data = NULL, DimensionType dimType = TENSORFLOW) {
return create(shape, halide_type_of<T>(), data, dimType);
}
public:
/**
* @brief for DEVICE tensor, copy data from given host tensor.
* @param hostTensor host tensor, the data provider.
* @return true for DEVICE tensor, and false for HOST tensor.
*/
bool copyFromHostTensor(const Tensor* hostTensor);
/**
* @brief for DEVICE tensor, copy data to given host tensor.
* @param hostTensor host tensor, the data consumer.
* @return true for DEVICE tensor, and false for HOST tensor.
*/
bool copyToHostTensor(Tensor* hostTensor) const;
/**
* @brief create HOST tensor from DEVICE tensor, with or without data copying.
* @param deviceTensor given device tensor.
* @param copyData copy data or not.
* @return created host tensor.
*/
static Tensor* createHostTensorFromDevice(const Tensor* deviceTensor, bool copyData = true);
public:
const halide_buffer_t& buffer() const {
return mBuffer;
}
halide_buffer_t& buffer() {
return mBuffer;
}
/**
* @brief get dimension type.
* @return dimension type.
*/
DimensionType getDimensionType() const;
/**
* @brief handle data type. used when data type code is halide_type_handle.
* @return handle data type.
*/
HandleDataType getHandleDataType() const;
/**
* @brief set data type.
* @param type data type defined in 'Type_generated.h'.
*/
void setType(int type);
/**
* @brief get data type.
* @return data type.
*/
inline halide_type_t getType() const {
return mBuffer.type;
}
/**
* @brief visit host memory, data type is represented by `T`.
* @return data point in `T` type.
*/
template <typename T>
T* host() const {
return (T*)mBuffer.host;
}
/**
* @brief visit device memory.
* @return device data ID. what the ID means varies between backends.
*/
uint64_t deviceId() const {
return mBuffer.device;
}
public:
int dimensions() const {
return mBuffer.dimensions;
}
/**
* @brief get all dimensions' extent.
* @return dimensions' extent.
*/
std::vector<int> shape() const;
/**
* @brief calculate number of bytes needed to store data taking reordering flag into account.
* @return bytes needed to store data
*/
int size() const;
/**
* @brief calculate number of elements needed to store data taking reordering flag into account.
* @return elements needed to store data
*/
inline int elementSize() const {
return size() / mBuffer.type.bytes();
}
public:
inline int width() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[2].extent;
}
return mBuffer.dim[3].extent;
}
inline int height() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[1].extent;
}
return mBuffer.dim[2].extent;
}
inline int channel() const {
if (getDimensionType() == TENSORFLOW) {
return mBuffer.dim[3].extent;
}
return mBuffer.dim[1].extent;
}
inline int batch() const {
return mBuffer.dim[0].extent;
}
// visit dimension's extent & stride
inline int stride(int index) const {
return mBuffer.dim[index].stride;
}
inline int length(int index) const {
return mBuffer.dim[index].extent;
}
inline void setStride(int index, int stride) {
mBuffer.dim[index].stride = stride;
}
inline void setLength(int index, int length) {
mBuffer.dim[index].extent = length;
}
public:
/**
* @brief print tensor data. for DEBUG use only.
*/
void print() const;
/**
*@brief print tensor shape
*/
void printShape() const;
private:
halide_buffer_t mBuffer;
struct InsideDescribe* mDescribe;
private:
friend class TensorUtils;
};
} // namespace MNN
#endif /* Tensor_hpp */

View File

@@ -0,0 +1,72 @@
//
// Executor.hpp
// MNN
//
// Created by MNN on 2019/07/25.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Executor_hpp
#define Executor_hpp
#include <MNN/ErrorCode.hpp>
#include <MNN/expr/Expr.hpp>
#include <MNN/Tensor.hpp>
#include <MNN/Interpreter.hpp>
#include <vector>
#include <mutex>
#include <set>
#include <MNN/MNNForwardType.h>
namespace MNN {
class Backend;
class Execution;
class Runtime;
struct Op;
namespace Express {
class MNN_PUBLIC Executor {
public:
class ComputeCache;
struct Unit;
static void setShapeDirty(ComputeCache* cache);
static void setContentDirty(ComputeCache* cache);
static void* mapOutput(ComputeCache* cache, int offset, Tensor* dest);
struct Requirement {
std::vector<bool> contentNeedContent;
std::vector<bool> shapeNeedContent;
};
~Executor();
Requirement getRequirement(Expr* expr) const;
ErrorCode computeInfo(Expr* expr);
void makeCache(const std::vector<EXPRP>& expr, bool forceCPU = false);
ErrorCode runCache(std::shared_ptr<ComputeCache> cache);
void setGlobalExecutorConfig(MNNForwardType type, const BackendConfig& config, int numberThread);
enum GCFlag {
FULL,
PART
};
void gc(GCFlag flag = FULL);
static std::shared_ptr<Executor> getGlobalExecutor();
static std::shared_ptr<Executor> newExecutor(MNNForwardType type,
const BackendConfig& config,
int numberThread);
void resetProfile();
void dumpProfile();
void addOpCostTime(int op, float costTime);
void addOpCostTime(const std::string& type, float costTime);
void addOpFlops(const std::string& type, float flops);
class Profiler;
static RuntimeInfo getRuntime();
private:
void _makeCache(const std::vector<EXPRP>& outputs, bool forceCPU);
void _create(const std::vector<EXPRP>& outputs, std::set<std::shared_ptr<Executor::ComputeCache>>&& inputCaches, std::set<std::shared_ptr<Expr::Inside>>&& inputNode, bool forceCPU);
void _visit(EXPRP expr, std::set<std::shared_ptr<Executor::ComputeCache>>& inputCaches, std::set<std::shared_ptr<Expr::Inside>>& inputNode);
Executor(std::shared_ptr<Runtime> backend, MNNForwardType type);
std::pair<std::shared_ptr<Runtime>, MNNForwardType> mRuntime;
std::pair<std::shared_ptr<Runtime>, MNNForwardType> mBackupRuntime;
std::mutex mMutex;
std::shared_ptr<Profiler> mProfiler;
};
} // namespace Express
} // namespace MNN
#endif

View File

@@ -0,0 +1,264 @@
//
// Expr.hpp
// MNN
//
// Created by MNN on 2019/06/10.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Expr_hpp
#define Expr_hpp
#include <functional>
#include <list>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <MNN/HalideRuntime.h>
#include <MNN/MNNDefine.h>
namespace MNN {
struct OpT;
struct Op;
struct NetT;
namespace Express {
class Variable;
class Expr;
class Executor;
typedef std::shared_ptr<Expr> EXPRP;
typedef std::weak_ptr<Expr> WeakEXPRP;
typedef std::vector<int> INTS;
enum Dimensionformat { NHWC, NC4HW4, NCHW };
class MNN_PUBLIC VARP {
public:
VARP() {
// Do nothing
}
VARP(std::shared_ptr<Variable> c) {
mContent = std::move(c);
}
VARP(Variable* c) {
mContent.reset(c);
}
Variable* get() const {
return mContent.get();
}
~ VARP() {
// Do nothing
}
VARP(const VARP& var) {
mContent = var.mContent;
}
VARP(VARP&& var) {
mContent = std::move(var.mContent);
}
VARP operator+(VARP var) const;
VARP operator-(VARP var) const;
VARP operator*(VARP var) const;
VARP operator/(VARP var) const;
VARP mean(INTS dims) const;
VARP sum(INTS dims) const;
bool operator==(const VARP& var) const {
return var.mContent == mContent;
}
bool operator<(const VARP& var) const {
return mContent < var.mContent;
}
bool operator<=(const VARP& var) const {
return mContent <= var.mContent;
}
VARP& operator=(const VARP& var) {
mContent = var.mContent;
return *this;
}
VARP& operator=(Variable* var) {
mContent.reset(var);
return *this;
}
Variable* operator->() const {
return mContent.get();
}
enum InputType {
INPUT = 0,
CONSTANT = 1,
TRAINABLE = 2,
};
bool fix(InputType type) const;
private:
friend class Variable;
std::shared_ptr<Variable> mContent;
};
inline bool operator==(Variable* src, VARP dst) {
return src == dst.get();
}
inline bool operator!=(Variable* src, VARP dst) {
return src != dst.get();
}
// inline bool operator<(VARP src, VARP dst) {
// return src.get() < dst.get();
// }
typedef std::vector<VARP> VARPS;
class MNN_PUBLIC Variable {
public:
struct Info {
Dimensionformat order = NHWC;
INTS dim;
halide_type_t type;
int size;
void syncSize();
};
const std::string& name() const;
void setName(const std::string& name);
std::pair<EXPRP, int> expr() const {
return std::make_pair(mFrom, mFromIndex);
}
// If compute info error, return nullptr
const Info* getInfo();
bool resize(INTS dims);
template <typename T>
const T* readMap() {
return (const T*)readInternal();
}
template <typename T>
T* writeMap() {
return (T*)writeInternal();
}
//Depecerate
void unMap();
bool input(VARP src);
static void replace(VARP dst, VARP src);
static VARP create(EXPRP expr, int index = 0);
static std::vector<VARP> load(const char* fileName);
static std::map<std::string, VARP> loadMap(const char* fileName);
static std::vector<VARP> load(const uint8_t* buffer, size_t length);
static std::map<std::string, VARP> loadMap(const uint8_t* buffer, size_t length);
static std::pair<std::map<std::string, VARP>, std::map<std::string, VARP>> getInputAndOutput(const std::map<std::string, VARP>& allVariable);
static std::vector<VARP> mapToSequence(const std::map<std::string, VARP>& source);
static std::vector<EXPRP> getExecuteOrder(const std::vector<VARP>& output);
static void save(const std::vector<VARP>& vars, const char* fileName);
static void save(const std::vector<VARP>& vars, NetT* dest);
// Pack a few Variable to compute in one pipeline
static void prepareCompute(const std::vector<VARP>& vars, bool forceCPU = false);
size_t linkNumber() const;
const std::vector<WeakEXPRP>& toExprs() const;
void setExpr(EXPRP expr, int index) {
mFrom = expr;
mFromIndex = index;
}
private:
Variable(EXPRP expr, int index) {
mFrom = expr;
mFromIndex = index;
}
void* readInternal(bool forShape = false);
void* writeInternal(bool inform=true);
void informDirty();
friend class Expr;
EXPRP mFrom;
int mFromIndex;
};
class MNN_PUBLIC Expr {
public:
struct Inside;
static EXPRP create(Variable::Info&& info, const void* ptr, VARP::InputType type, bool copy = true);
static EXPRP create(const OpT* op, std::vector<VARP> inputs, int outputSize = 1);
static EXPRP create(std::pair<std::shared_ptr<char>, int> extra, std::vector<VARP>&& inputs, int outputSize = 1);
static EXPRP create(std::unique_ptr<OpT>&& op, std::vector<VARP> inputs, int outputSize = 1) {
return create(op.get(), inputs, outputSize);
}
void setName(const std::string& name);
const Op* get() const {
return mOp;
}
const std::vector<VARP>& inputs() const {
return mInputs;
}
int outputSize() const {
return (int)mOutputNames.size();
}
static void replace(EXPRP oldExpr, EXPRP newExpr);
bool requireInfo();
void visitOutputs(const std::function<bool(EXPRP, int)>& visit);
static void visit(EXPRP expr, const std::function<bool(EXPRP)>& before, const std::function<bool(EXPRP)>& after);
const std::vector<WeakEXPRP>& outputs() const {
return mTo;
}
~Expr();
bool visited() const {
return mVisited;
}
void setVisited(bool visited) {
mVisited = visited;
}
const std::string& name() const {
return mName;
}
const std::string& outputName(int index) {
return mOutputNames[index];
}
VARP::InputType inputType() const {return mType;}
Variable::Info* outputInfo(int index) const;
std::pair<std::shared_ptr<char>, int> extra() const {
return std::make_pair(mExtraBuffer, mOpBufferSize);
}
bool setInfoDirty();
std::shared_ptr<Inside> inside() const {
return mInside;
}
bool valid() const {
return mValid;
}
void setEntry(const std::vector<VARP>& entries) {
mEntries = entries;
}
const std::vector<VARP>& getEntry() const {
return mEntries;
}
private:
static void _addLinkForInputs(EXPRP expr);
Expr(int outputSize);
friend class Variable;
friend class VARP;
VARP::InputType mType;
const Op* mOp;
std::vector<VARP> mInputs;
std::vector<std::string> mOutputNames;
bool mValid = true;
std::shared_ptr<char> mExtraBuffer;
int mOpBufferSize = 0;
std::string mName;
std::shared_ptr<Inside> mInside = nullptr;
bool mVisited = false;
std::vector<WeakEXPRP> mTo;
// Only the enter input has entries, and it helps to get info for enter
// input expression.
std::vector<VARP> mEntries;
};
} // namespace Express
} // namespace MNN
#endif /* Expr_hpp */

View File

@@ -0,0 +1,16 @@
//
// ExprCreator.hpp
// MNN
//
// Created by MNN on 2019/06/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef ExprCreator_hpp
#define ExprCreator_hpp
#include <MNN/expr/Expr.hpp>
#include <MNN/expr/MathOp.hpp>
#include <MNN/expr/NeuralNetWorkOp.hpp>
#endif

View File

@@ -0,0 +1,128 @@
//
// MathOp.hpp
// MNN
//
// Created by MNN on 2019/06/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef MathOp_HPP
#define MathOp_HPP
namespace MNN {
namespace Express {
//BinaryOPs
MNN_PUBLIC VARP _Add(VARP x, VARP y);
MNN_PUBLIC VARP _Subtract(VARP x, VARP y);
MNN_PUBLIC VARP _Multiply(VARP x, VARP y);
MNN_PUBLIC VARP _Divide(VARP x, VARP y);
MNN_PUBLIC VARP _Pow(VARP x, VARP y);
MNN_PUBLIC VARP _Minimum(VARP x, VARP y);
MNN_PUBLIC VARP _Maximum(VARP x, VARP y);
MNN_PUBLIC VARP _BiasAdd(VARP value, VARP bias);
MNN_PUBLIC VARP _Greater(VARP x, VARP y);
MNN_PUBLIC VARP _GreaterEqual(VARP x, VARP y);
MNN_PUBLIC VARP _Less(VARP x, VARP y);
MNN_PUBLIC VARP _FloorDiv(VARP x, VARP y);
MNN_PUBLIC VARP _SquaredDifference(VARP x, VARP y);
MNN_PUBLIC VARP _Equal(VARP x, VARP y);
MNN_PUBLIC VARP _LessEqual(VARP x, VARP y);
MNN_PUBLIC VARP _FloorMod(VARP x, VARP y);
MNN_PUBLIC VARP _Atan2(VARP x, VARP y);
MNN_PUBLIC VARP _LogicalOr(VARP x, VARP y);
MNN_PUBLIC VARP _NotEqual(VARP x, VARP y);
//UnaryOPs
MNN_PUBLIC VARP _Sign(VARP a);
MNN_PUBLIC VARP _Abs(VARP x);
MNN_PUBLIC VARP _Negative(VARP x);
MNN_PUBLIC VARP _Floor(VARP x);
MNN_PUBLIC VARP _Round(VARP x);
MNN_PUBLIC VARP _Ceil(VARP x);
MNN_PUBLIC VARP _Square(VARP x);
MNN_PUBLIC VARP _Sqrt(VARP x);
MNN_PUBLIC VARP _Rsqrt(VARP x);
MNN_PUBLIC VARP _Exp(VARP x);
MNN_PUBLIC VARP _Log(VARP x);
MNN_PUBLIC VARP _Sin(VARP x);
MNN_PUBLIC VARP _Sinh(VARP x);
MNN_PUBLIC VARP _Cos(VARP x);
MNN_PUBLIC VARP _Cosh(VARP x);
MNN_PUBLIC VARP _Tan(VARP x);
MNN_PUBLIC VARP _Asin(VARP x);
MNN_PUBLIC VARP _Asinh(VARP x);
MNN_PUBLIC VARP _Acos(VARP x);
MNN_PUBLIC VARP _Acosh(VARP x);
MNN_PUBLIC VARP _Atan(VARP x);
MNN_PUBLIC VARP _Atanh(VARP x);
MNN_PUBLIC VARP _Reciprocal(VARP x);
MNN_PUBLIC VARP _Log1p(VARP x);
//Only one but not in UnaryOPs
MNN_PUBLIC VARP _Tanh(VARP x);
MNN_PUBLIC VARP _Sigmoid(VARP x);
MNN_PUBLIC VARP _Erf(VARP x);
MNN_PUBLIC VARP _Erfc(VARP x);
MNN_PUBLIC VARP _Erfinv(VARP x);
MNN_PUBLIC VARP _Expm1(VARP x);
//ReduceOPs
MNN_PUBLIC VARP _ReduceSum(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMean(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMax(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMin(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceProd(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceAny(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceAll(VARP input_variable, INTS axis = {}, bool keepDims = false);
MNN_PUBLIC VARP _ReduceSumMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMeanMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMaxMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceMinMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceProdMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceAnyMutable(VARP input_variable, VARP axis, bool keepDims = false);
MNN_PUBLIC VARP _ReduceAllMutable(VARP input_variable, VARP axis, bool keepDims = false);
//EltwiseOPs
MNN_PUBLIC VARP _Prod(VARP a, VARP b, std::vector<float> coeff);
MNN_PUBLIC VARP _Sum(VARP a, VARP b, std::vector<float> coeff);
MNN_PUBLIC VARP _Max(VARP a, VARP b, std::vector<float> coeff);
MNN_PUBLIC VARP _Sub(VARP a, VARP b, std::vector<float> coeff);
MNN_PUBLIC VARP _EltwiseProdInt8(VARP x, VARP y,
std::vector<int8_t> x_weight, std::vector<int32_t> x_bias, std::vector<float> x_scale, std::vector<float> x_tensorScale,
std::vector<int8_t> y_weight, std::vector<int32_t> y_bias, std::vector<float> y_scale, std::vector<float> y_tensorScale,
std::vector<int8_t> output_weight, std::vector<int32_t> output_bias, std::vector<float> output_scale, std::vector<float> output_tensorScale);
MNN_PUBLIC VARP _EltwiseSumInt8(VARP x, VARP y,
std::vector<int8_t> x_weight, std::vector<int32_t> x_bias, std::vector<float> x_scale, std::vector<float> x_tensorScale,
std::vector<int8_t> y_weight, std::vector<int32_t> y_bias, std::vector<float> y_scale, std::vector<float> y_tensorScale,
std::vector<int8_t> output_weight, std::vector<int32_t> output_bias, std::vector<float> output_scale, std::vector<float> output_tensorScale);
MNN_PUBLIC VARP _EltwiseSubInt8(VARP x, VARP y,
std::vector<int8_t> x_weight, std::vector<int32_t> x_bias, std::vector<float> x_scale, std::vector<float> x_tensorScale,
std::vector<int8_t> y_weight, std::vector<int32_t> y_bias, std::vector<float> y_scale, std::vector<float> y_tensorScale,
std::vector<int8_t> output_weight, std::vector<int32_t> output_bias, std::vector<float> output_scale, std::vector<float> output_tensorScale);
MNN_PUBLIC VARP _EltwiseMaxInt8(VARP x, VARP y,
std::vector<int8_t> x_weight, std::vector<int32_t> x_bias, std::vector<float> x_scale, std::vector<float> x_tensorScale,
std::vector<int8_t> y_weight, std::vector<int32_t> y_bias, std::vector<float> y_scale, std::vector<float> y_tensorScale,
std::vector<int8_t> output_weight, std::vector<int32_t> output_bias, std::vector<float> output_scale, std::vector<float> output_tensorScale);
//OtherOPs
template<typename T>
VARP _Cast(VARP x) {
return _Cast(x, halide_type_of<T>());
}
MNN_PUBLIC VARP _Cast(VARP x, halide_type_t dtype);
MNN_PUBLIC VARP _MatMul(VARP a, VARP b, bool tranposeA = false, bool tranposeB = false);
MNN_PUBLIC VARP _Normalize(VARP x, int32_t acrossSpatial, int32_t channelShared, float eps, std::vector<float> scale);
MNN_PUBLIC VARP _ArgMax(VARP input, int axis = 0);
MNN_PUBLIC VARP _ArgMin(VARP input, int axis = 0);
MNN_PUBLIC VARP _BatchMatMul(VARP x, VARP y, bool adj_x = false, bool adj_y = false);
MNN_PUBLIC VARP _UnravelIndex(VARP indices, VARP dims);
MNN_PUBLIC VARP _ScatterNd(VARP indices, VARP updates, VARP shape);
MNN_PUBLIC VARP _OneHot(VARP indices, VARP depth, VARP onValue, VARP offValue, int axis = -1);
MNN_PUBLIC VARP _BroadcastTo(VARP a, VARP shape);
MNN_PUBLIC VARP _LinSpace(VARP start, VARP stop, VARP num);
}; // namespace Express
}; // namespace MNN
#endif /* MathOp_HPP */

View File

@@ -0,0 +1,142 @@
//
// NeuralNetWorkOp.hpp
// MNN
//
// Created by MNN on 2019/06/27.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef NeuralNetWorkOp_HPP
#define NeuralNetWorkOp_HPP
namespace MNN {
namespace Express {
enum PaddingMode {CAFFE, VALID, SAME};
enum PoolingMode {MAXPOOL, AVEPOOL};
enum PadValueMode {CONSTANT, REFLECT, SYMMETRIC};
MNN_PUBLIC VARP _Input(INTS shape = {}, Dimensionformat data_format = NC4HW4, halide_type_t dtype = halide_type_of<float>()) ;
MNN_PUBLIC VARP _Clone(VARP source, bool deepCopy = false);
MNN_PUBLIC VARP _Scalar(const void* ptr, halide_type_t type);
template <typename T>
VARP _Scalar(T value) {
return _Scalar(&value, halide_type_of<T>());
}
MNN_PUBLIC VARP _Const(float value, INTS shape = {}, Dimensionformat format = NHWC);
MNN_PUBLIC VARP _Const(const void* ptr, INTS shape = {}, Dimensionformat format = NHWC,
halide_type_t type = halide_type_of<float>());
MNN_PUBLIC VARP _TrainableParam(float value, INTS dims, Dimensionformat format);
MNN_PUBLIC VARP _TrainableParam(const void* ptr, INTS dims, Dimensionformat format,
halide_type_t type = halide_type_of<float>());
MNN_PUBLIC VARP _InnerProduct(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS outputShape);
MNN_PUBLIC VARP _Conv(VARP weight, VARP bias, VARP x, PaddingMode pad = VALID, INTS stride = {1, 1},
INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0});
MNN_PUBLIC VARP _Conv(float weight, float bias, VARP x, INTS channel, INTS kernelSize, PaddingMode pad = VALID,
INTS stride = {1, 1}, INTS dilate = {1, 1}, int group = 1);
MNN_PUBLIC VARP _Conv(std::vector<int8_t>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
PaddingMode pad = VALID, INTS stride = {1, 1}, INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0}, bool relu = false, bool relu6 = false, int nbits = 8);
MNN_PUBLIC VARP _Conv(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
PaddingMode pad = VALID, INTS stride = {1, 1}, INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0}, bool relu = false, bool relu6 = false);
MNN_PUBLIC VARP _Deconv(VARP weight, VARP bias, VARP x, PaddingMode pad = VALID, INTS stride = {1, 1},
INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0});
MNN_PUBLIC VARP _Deconv(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
PaddingMode pad, INTS stride = {1, 1}, INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0}, bool relu = false, bool relu6 = false);
MNN_PUBLIC VARP _MaxPool(VARP x, INTS kernel, INTS stride = {1, 1}, PaddingMode pad = VALID, INTS pads= {0, 0});
MNN_PUBLIC VARP _AvePool(VARP x, INTS kernel, INTS stride = {1, 1}, PaddingMode pad = VALID, INTS pads= {0, 0});
MNN_PUBLIC VARP _Reshape(VARP x, INTS shape, Dimensionformat original_format = NCHW);
MNN_PUBLIC VARP _Reshape(VARP x, VARP shape);
MNN_PUBLIC VARP _Scale(VARP x, int channels, std::vector<float>&& scales, std::vector<float>&& bias);
MNN_PUBLIC VARP _Relu(VARP x, float slope = 0.0f);
MNN_PUBLIC VARP _Relu6(VARP x, float minValue = 0.0f, float maxValue = 6.0f);
MNN_PUBLIC VARP _PRelu(VARP x, std::vector<float> &&slopes);
MNN_PUBLIC VARP _Softmax(VARP logits, int axis = -1);
MNN_PUBLIC VARP _Softplus(VARP features);
MNN_PUBLIC VARP _Softsign(VARP features);
MNN_PUBLIC std::vector<VARP> _Split(VARP value, INTS size_splits, int axis = 0);
MNN_PUBLIC VARP _Slice(VARP x, VARP starts, VARP sizes);
MNN_PUBLIC VARP _StridedSlice(VARP input, VARP begin, VARP end, VARP strided,
int32_t beginMask, int32_t endMask, int32_t ellipsisMask,
int32_t newAxisMask, int32_t shrinkAxisMask);
MNN_PUBLIC VARP _Concat(VARPS values, int axis);
MNN_PUBLIC VARP _Convert(VARP input, Dimensionformat format);
MNN_PUBLIC VARP _Transpose(VARP x, INTS perm);
MNN_PUBLIC VARP _Transpose(VARP x, VARP perm);
MNN_PUBLIC VARP _ChannelShuffle(VARP x, int group);
MNN_PUBLIC VARP _ChangeInputFormat(VARP input, Dimensionformat format);
MNN_PUBLIC VARP _Conv2DBackPropFilter(VARP input, VARP inputGrad, INTS kernelSize, PaddingMode pad = VALID, INTS stride = {1, 1}, INTS dilate = {1, 1}, int group = 1, INTS pads = {0, 0});
MNN_PUBLIC VARP _PoolGrad(VARP originInput, VARP originOutput, VARP inputGrad, INTS kernel, INTS stride, PoolingMode type, PaddingMode pad = VALID, INTS pads= {0, 0});
// FIXME: move the api to Array Ops
MNN_PUBLIC VARP _ReverseSequence(VARP x, VARP y, int batchDim, int seqDim);
// FIXME: move the api to Image Ops
MNN_PUBLIC VARP _Crop(VARP images, VARP size, int axis, INTS offset);
MNN_PUBLIC VARP _Resize(VARP images, float xScale, float yScale);
MNN_PUBLIC VARP _Pad(VARP x, VARP paddings, PadValueMode mode = CONSTANT);
MNN_PUBLIC VARP _ExpandDims(VARP input, int axis);
MNN_PUBLIC VARP _ExpandDims(VARP input, VARP axis);
MNN_PUBLIC VARP _Shape(VARP input, bool nchw = false);
MNN_PUBLIC VARP _Stack(VARPS values, int axis=0);
enum InterpolationMethod {BILINEAR, NEAREST};
MNN_PUBLIC VARP _CropAndResize(VARP image, VARP boxes, VARP box_ind, VARP crop_size,
InterpolationMethod method, float extrapolation_value = 0.0);
MNN_PUBLIC VARP _Fill(VARP dims, VARP value);
MNN_PUBLIC VARP _Tile(VARP input, VARP multiples);
MNN_PUBLIC VARP _Gather(VARP params, VARP indices);
MNN_PUBLIC VARP _GatherV2(VARP params, VARP indices, VARP axis = nullptr);
MNN_PUBLIC VARP _Squeeze(VARP input, INTS axis = {});
MNN_PUBLIC VARP _Unsqueeze(VARP input, INTS axis = {});
MNN_PUBLIC VARP _BatchToSpaceND(VARP input, VARP block_shape, VARP crops);
MNN_PUBLIC VARP _GatherND(VARP params, VARP indices);
MNN_PUBLIC VARP _Selu(VARP features, float scale, float alpha);
MNN_PUBLIC VARP _Size(VARP input);
MNN_PUBLIC VARP _Elu(VARP features, float alpha=1.0);
MNN_PUBLIC VARP _Threshold(VARP features, float alpha=1.0);
MNN_PUBLIC VARP _MatrixBandPart(VARP input, VARP num_lower, VARP num_upper);
MNN_PUBLIC std::vector<VARP> _Moments(VARP x, INTS axis, VARP shift, bool keepDims);
MNN_PUBLIC VARP _SetDiff1D(VARP x, VARP y);
MNN_PUBLIC VARP _SpaceToDepth(VARP input, int block_size);
MNN_PUBLIC VARP _SpaceToBatchND(VARP input, VARP block_shape, VARP paddings);
MNN_PUBLIC VARP _ZerosLike(VARP input);
MNN_PUBLIC std::vector<VARP> _Unstack(VARP value, int axis=0);
MNN_PUBLIC VARP _Rank(VARP input);
MNN_PUBLIC VARP _Range(VARP start, VARP limit, VARP delta);
MNN_PUBLIC VARP _DepthToSpace(VARP input, int block_size);
MNN_PUBLIC VARP _PriorBox(VARP feature, VARP image,
std::vector<float> min_size, std::vector<float> max_size, std::vector<float>aspect_ratio,
bool flip, bool clip, std::vector<float>variance,
unsigned int img_h, unsigned int img_w, float step_h, float step_w, float offset = 0.5);
MNN_PUBLIC VARP _Permute(VARP input, INTS dims);
MNN_PUBLIC VARP _DetectionOutput(VARP location, VARP confidence, VARP priorbox,
unsigned int num_classes, bool share_location, int background_label_id,
float nms_threshhold, int nms_topk, int code_type,
bool variance_encoded_in_target,
int keep_top_k, float confidence_threshold, float visualize_threshold);
MNN_PUBLIC std::vector<VARP> _DetectionPostProcess(VARP encode_boxes, VARP class_predictions, VARP anchors,
int num_classes, int max_detections,
int max_class_per_detection, int detections_per_class,
float nms_threshold, float iou_threshold,
bool use_regular_nms, std::vector<float> centersize_encoding);
MNN_PUBLIC VARP _Interp(VARPS xs, float widthScale, float heightScale, int outputWidth, int outputHeight, int resizeType, bool alignCorners);
MNN_PUBLIC VARP _ZeroGrad(VARP x);
// Int8 Inference
MNN_PUBLIC VARP _Conv(std::vector<int8_t>&& weight, std::vector<int>&& bias, std::vector<float>&& scale, VARP x, INTS channel, INTS kernelSize,
PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu, int nbits = 8);
MNN_PUBLIC VARP _CosineSimilarity(VARP input0, VARP input1, VARP inputDim);
MNN_PUBLIC VARP _FloatToInt8(VARP x, VARP scale, char minValue, char maxValue);
MNN_PUBLIC VARP _Int8ToFloat(VARP x, VARP scale);
MNN_PUBLIC VARP _Select(VARP select, VARP input0, VARP input1);
} // namespace Express
} // namespace MNN
#endif /* NeuralNetWorkOp_HPP */

View File

@@ -0,0 +1,64 @@
//
// Optimizer.hpp
// MNN
//
// Created by MNN on 2019/08/20.
// Copyright © 2018, Alibaba Group Holding Limited
//
#ifndef Optimizer_hpp
#define Optimizer_hpp
#include <MNN/expr/Expr.hpp>
#include <MNN/MNNForwardType.h>
namespace MNN {
namespace Express {
class MNN_PUBLIC Optimizer {
public:
enum Device {
CPU = 0,
GPU = 1,
OTHER = 2,
AUTO = 3
};
struct Config {
Device device = CPU;
MNNForwardType forwardType = MNN_FORWARD_ALL;
int numThread = 4;
};
static std::shared_ptr<Optimizer> create(Config config);
struct Cost {
float compute; // MFlops
float memory; // MB
};
class Parameters {
public:
Parameters(int n);
virtual ~Parameters();
float* get() const {
return mValue;
}
int size() const {
return mSize;
}
private:
float* mValue;
int mSize;
};
virtual std::shared_ptr<Parameters> onGetParameters(const std::vector<VARP>& outputs) {
return nullptr;
}
//Given paramters and measure cost, the parameters must be the same as onGetParameters
virtual Cost onMeasure(const std::vector<VARP>& outputs, std::shared_ptr<Parameters> parameters = nullptr) = 0;
//Modify the output directly, the parameters must be the same as onGetParameters
virtual bool onExecute(const std::vector<VARP>& outputs, std::shared_ptr<Parameters> parameters = nullptr) = 0;
Optimizer() = default;
virtual ~Optimizer() = default;
};
} // namespace Express
} // namespace MNN
#endif

BIN
3rd/win/mnn/x64/MNN.lib Normal file

Binary file not shown.

View File

@@ -11,7 +11,10 @@ endif()
# 根据 platform 值设置 CMake 变量
if(${CMAKE_BUILD_PLATFORM} STREQUAL "win")
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rd/win/opencv/x64/vc15/lib)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rd/win/mnn/x64/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rd/win/opencv/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rd/win/mnn/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/models)
else()
message(FATAL_ERROR "不支持的平台: ${CMAKE_BUILD_PLATFORM}")
endif()
@@ -19,13 +22,18 @@ endif()
include_directories(src)
aux_source_directory(./src DIR_SRCS)
aux_source_directory(./src/util DIR_SRCS)
aux_source_directory(./app DIR_SRCS)
add_executable(Demo ${DIR_SRCS})
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_link_libraries(${PROJECT_NAME} opencv_world430d)
target_compile_options(${PROJECT_NAME} PRIVATE /MTd)
target_link_libraries(${PROJECT_NAME} opencv_world430d)
target_link_libraries(${PROJECT_NAME} MNN)
else()
target_link_libraries(${PROJECT_NAME} opencv_world430)
target_compile_options(${PROJECT_NAME} PRIVATE /MT)
target_link_libraries(${PROJECT_NAME} opencv_world430)
target_link_libraries(${PROJECT_NAME} MNN)
endif()

View File

@@ -1,6 +1,27 @@
#include <iostream>
#include <opencv2/opencv.hpp>
#include "util/TimeCount.h"
#include "CenterFaceMnn.h"
int32_t main(int32_t argc, char** argv) {
std::cout << "Hello, World!" << std::endl;
CenterFaceMnn::GetInstance();
std::vector<FaceInfo> faces;
cv::Mat img = cv::imread("F:/33.jpg");
int32_t count = 0;
re_test:
count++;
{
USE_TIME t(USE_TIME_US, "face_detect: ");
CenterFaceMnn::GetInstance()->Detect(img, faces, 1);
}
if (count < 10) {
goto re_test;
}
for(auto& face : faces) {
cv::rectangle(img, cv::Rect(face.x1, face.y1, face.x2 - face.x1, face.y2 - face.y1), cv::Scalar(0, 0, 255), 2);
}
cv::imshow("test", img);
cv::waitKey(0);
return 0;
}

View File

@@ -42,6 +42,6 @@ Write-Host "build done." -ForegroundColor Darkgreen
if($build_and_run -eq "true"){
Write-Host "################## APP Run ##################" -ForegroundColor Blue
$env:PATH += ";3rd\win\opencv\x64\vc15\bin"
$env:PATH += ";3rd\win\opencv\x64\vc15\bin;3rd\win\mnn\x64\"
Start-Process -FilePath "build\\${build_type}\\Demo.exe"
}

BIN
models/3ddfa.onnx Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
models/RGBLiveness.onnx Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
models/landmark68.dat Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
models/pose_onnx.dat Normal file

File diff suppressed because one or more lines are too long

235
src/CenterFaceMnn.cpp Normal file
View File

@@ -0,0 +1,235 @@
#include "CenterFaceMnn.h"
CenterFaceMnn* CenterFaceMnn::m_hInstance = nullptr;
static const unsigned char centerface_model[] = {
#include "centerface_small_mnn.dat"
};
CenterFaceMnn* CenterFaceMnn::GetInstance(){
if (!m_hInstance){
m_hInstance = new CenterFaceMnn();
}
return m_hInstance;
}
CenterFaceMnn::CenterFaceMnn(){
m_detector = std::shared_ptr<MNN::Interpreter>(MNN::Interpreter::createFromBuffer(centerface_model, sizeof(centerface_model)));
MNN::ScheduleConfig config;
MNN::BackendConfig backendConfig;
backendConfig.precision = MNN::BackendConfig::Precision_High;
backendConfig.power = MNN::BackendConfig::Power_High;
backendConfig.memory = MNN::BackendConfig::Memory_High;
config.backendConfig = &backendConfig;
config.type = MNN_FORWARD_CPU;
config.numThread = 4;
m_session = m_detector->createSession(config);
const float mean_vals[3] = { 127.5f, 127.5f, 127.5f };
const float norm_vals[3] = { 0.0078431373f, 0.0078431373f, 0.0078431373f };
::memcpy(m_img_config.mean, mean_vals, sizeof(mean_vals));
::memcpy(m_img_config.normal, norm_vals, sizeof(norm_vals));
m_img_config.sourceFormat = (MNN::CV::ImageFormat)2;
m_img_config.destFormat = (MNN::CV::ImageFormat)1;
m_img_config.filterType = (MNN::CV::Filter)(1);
m_img_config.wrap = (MNN::CV::Wrap)(1);
input_tensor = m_detector->getSessionInput(m_session, NULL);
hm_tensor = m_detector->getSessionOutput(m_session, "hm");
wh_tensor = m_detector->getSessionOutput(m_session, "wh");
reg_tensor = m_detector->getSessionOutput(m_session, "reg");
lm_tensor = m_detector->getSessionOutput(m_session, "lm");
}
CenterFaceMnn::~CenterFaceMnn(){
m_detector->releaseSession(m_session);
}
int CenterFaceMnn::Detect(const cv::Mat& img, std::vector<FaceInfo>& faces, float scale){
std::lock_guard<std::mutex> lock(m_mt);
faces.clear();
if (img.cols * img.rows == 0){
return -1;
}
if (scale <= 0 || scale > 1) {
scale = img.cols > img.rows ? 160.0f / img.cols : 160.0f / img.rows;
}
int resize_w = (int)(img.cols * scale) / 32 * 32;
int resize_h = (int)(img.rows * scale) / 32 * 32;
float scale_w = (float)img.cols / (float)resize_w;
float scale_h = (float)img.rows / (float)resize_h;
cv::Mat input;
cv::resize(img, input, cv::Size(resize_w, resize_h));
m_detector->resizeTensor(input_tensor, 1, 3, resize_h, resize_w);
m_detector->resizeSession(m_session);
//prepare data
std::shared_ptr<MNN::CV::ImageProcess> pretreat(MNN::CV::ImageProcess::create(m_img_config));
pretreat->convert(input.data, resize_w, resize_h, input.step[0], input_tensor);
m_detector->runSession(m_session);
MNN::Tensor tensor_hm(hm_tensor, MNN::Tensor::CAFFE);
MNN::Tensor tensor_wh(wh_tensor, MNN::Tensor::CAFFE);
MNN::Tensor tensor_reg(reg_tensor, MNN::Tensor::CAFFE);
MNN::Tensor tensor_lm(lm_tensor, MNN::Tensor::CAFFE);
hm_tensor->copyToHostTensor(&tensor_hm);
wh_tensor->copyToHostTensor(&tensor_wh);
reg_tensor->copyToHostTensor(&tensor_reg);
lm_tensor->copyToHostTensor(&tensor_lm);
std::vector<int> hm_shape = tensor_hm.shape();
float* heatmap = tensor_hm.host<float>();
float* wh = tensor_wh.host<float>();
float* reg = tensor_reg.host<float>();
float* lm = tensor_lm.host<float>();
Decode(heatmap, wh, reg, lm, hm_shape[2], hm_shape[3], faces, 0.4, 0.3);
for (int i = 0; i < faces.size(); i++){
FaceInfo& tmp = faces[i];
tmp.x1 *= scale_w;
tmp.x2 *= scale_w;
tmp.y1 *= scale_h;
tmp.y2 *= scale_h;
for (int j = 0; j < 5; j++){
tmp.landmarks[j * 2] *= scale_w;
tmp.landmarks[j * 2 + 1] *= scale_h;
}
}
return faces.size();
}
#include <omp.h>
void CenterFaceMnn::Decode(float* heatmap, float* scale, float* offset, float* landmarks, int h, int w, std::vector<FaceInfo>& faces, float scoreThresh, float nmsThresh){
int fea_h = h;
int fea_w = w;
int d_w = w * 4;
int d_h = h * 4;
int spacial_size = fea_w * fea_h;
float *scale1 = (float*)(scale);
float *scale0 = scale1 + spacial_size;
float *offset1 = (float*)(offset);
float *offset0 = offset1 + spacial_size;
std::vector<int> ids = GetIds(heatmap, fea_h, fea_w, scoreThresh);
std::vector<FaceInfo> faces_tmp;
#pragma omp parallel for
for (int i = 0; i < ids.size() / 2; i++) {
int id_h = ids[2 * i];
int id_w = ids[2 * i + 1];
int index = id_h * fea_w + id_w;
float s0 = std::exp(scale0[index]) * 4;
float s1 = std::exp(scale1[index]) * 4;
float o0 = offset0[index];
float o1 = offset1[index];
float x1 = std::max(0., (id_w + o1 + 0.5) * 4 - s1 / 2);
float y1 = std::max(0., (id_h + o0 + 0.5) * 4 - s0 / 2);
float x2 = std::max(0., (id_w + o1 + 0.5) * 4 + s1 / 2);
float y2 = std::max(0., (id_h + o0 + 0.5) * 4 + s0 / 2);
x1 = std::min(x1, (float)d_w);
y1 = std::min(y1, (float)d_h);
x2 = std::min(x2, (float)d_w);
y2 = std::min(y2, (float)d_h);
FaceInfo facebox;
facebox.x1 = x1;
facebox.y1 = y1;
facebox.x2 = x2;
facebox.y2 = y2;
facebox.score = heatmap[index];
float box_w = x2 - x1;
float box_h = y2 - y1;
for (int j = 0; j < 5; j++) {
float *xmap = (float*)landmarks + (2 * j) * spacial_size;
float *ymap = (float*)landmarks + (2 * j + 1) * spacial_size;
facebox.landmarks[2 * j] = x1 + xmap[index] * s1;
facebox.landmarks[2 * j + 1] = y1 + ymap[index] * s0;
}
#pragma omp critical
{
faces_tmp.push_back(facebox);
}
}
NMS(faces_tmp, faces, nmsThresh);
}
void CenterFaceMnn::NMS(std::vector<FaceInfo>& input, std::vector<FaceInfo>& output, float nmsthreshold) {
std::sort(input.begin(), input.end(),
[](const FaceInfo& a, const FaceInfo& b) {
return a.score > b.score;
});
int box_num = input.size();
std::vector<int> merged(box_num, 0);
#pragma omp parallel for
for (int i = 0; i < box_num; i++) {
if (merged[i])
continue;
output.push_back(input[i]);
float h0 = input[i].y2 - input[i].y1 + 1;
float w0 = input[i].x2 - input[i].x1 + 1;
float area0 = h0 * w0;
for (int j = i + 1; j < box_num; j++) {
if (merged[j])
continue;
float inner_x0 = std::max(input[i].x1, input[j].x1);
float inner_y0 = std::max(input[i].y1, input[j].y1);
float inner_x1 = std::min(input[i].x2, input[j].x2);
float inner_y1 = std::min(input[i].y2, input[j].y2);
float inner_h = inner_y1 - inner_y0 + 1;
float inner_w = inner_x1 - inner_x0 + 1;
if (inner_h <= 0 || inner_w <= 0)
continue;
float inner_area = inner_h * inner_w;
float h1 = input[j].y2 - input[j].y1 + 1;
float w1 = input[j].x2 - input[j].x1 + 1;
float area1 = h1 * w1;
float score = inner_area / (area0 + area1 - inner_area);
if (score > nmsthreshold)
merged[j] = 1;
}
}
}
std::vector<int> CenterFaceMnn::GetIds(float *heatmap, int h, int w, float thresh){
std::vector<int> ids;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (heatmap[i*w + j] > thresh) {
ids.push_back(i);
ids.push_back(j);
}
}
}
return ids;
}
const std::string CenterFaceMnn::GetModelVer(){
return m_model_ver;
}

45
src/CenterFaceMnn.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CENTERFACE_H
#define CENTERFACE_H
#include <opencv2/opencv.hpp>
#include <vector>
#include <memory>
#include <mutex>
#include <MNN/Interpreter.hpp>
#include <MNN/MNNDefine.h>
#include <MNN/ImageProcess.hpp>
#include <MNN/Tensor.hpp>
#include "TypeInfo.h"
class CenterFaceMnn{
public:
static CenterFaceMnn* GetInstance();
int Detect(const cv::Mat& img, std::vector<FaceInfo>& faces, float scale = 0);
const std::string GetModelVer();
private:
CenterFaceMnn();
~CenterFaceMnn();
void Decode(float* heatmap, float* scale, float* offset, float* landmarks, int h, int w, std::vector<FaceInfo>& faces, float scoreThresh, float nmsThresh);
void NMS(std::vector<FaceInfo>& input, std::vector<FaceInfo>& output, float nmsthreshold);
std::vector<int> GetIds(float *heatmap, int h, int w, float thresh);
private:
static CenterFaceMnn* m_hInstance;
std::mutex m_mt;
std::shared_ptr<MNN::Interpreter> m_detector;
MNN::Tensor* input_tensor;
MNN::Tensor* hm_tensor;
MNN::Tensor* wh_tensor;
MNN::Tensor* reg_tensor;
MNN::Tensor* lm_tensor;
MNN::Session* m_session;
MNN::CV::ImageProcess::Config m_img_config;
const std::string m_model_ver = "";
};
#endif

1
src/TypeInfo.cpp Normal file
View File

@@ -0,0 +1 @@
#include "TypeInfo.h"

32
src/TypeInfo.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef TYPE_INFO_H
#define TYPE_INFO_H
typedef enum _ret_t {
RET_OK = 0, // 操作成功
RET_AUTHOR, // 授权失败
RET_IMG, // 输入图片错误
RET_INVALID_FEATURE, // 人脸特征数据无效
RET_INVALID_LANDMARK, // 人脸Landmark数据无效
} ret_t;
// #define ERR_FACE_RECT -10 //人脸框无效
// #define ERR_INDEX_INVALID -20 //索引无效
struct FaceInfo {
float x1; //人脸框 左上x坐标
float y1; //人脸框 左上y坐标
float x2; //人脸框 右下x坐标
float y2; //人脸框 右下y坐标
float score; //人脸框 置信度
float landmarks[10]; //人脸框 关键点坐标
int GetWidth() {
return static_cast<int>(x2 - x1);
}
int GetHeight() {
return static_cast<int>(y2 - y1);
}
};
#endif

View File

@@ -1,20 +1,22 @@
#include "TimeCount.h"
#include <iostream>
USE_TIME::USE_TIME(std::string str) :
strTmp(str)
{
start = std::chrono::system_clock::now();
USE_TIME::USE_TIME(USE_TIME_UNIT unit, std::string str) :
strTmp(str),
unit(unit){
start = std::chrono::system_clock::now();
}
USE_TIME::~USE_TIME()
{
USE_TIME::~USE_TIME(){
end = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << strTmp << "\t" << float(duration.count()*1.0) * std::chrono::milliseconds::period::num << "ms \t\n";
//auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
//std::cout << strTmp << "\t" << float(duration.count()*1.0) * std::chrono::microseconds::period::num << "ms \t\n";
if (unit == USE_TIME_MS) {
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << strTmp << "\t" << float(duration.count()*1.0) * std::chrono::milliseconds::period::num << "ms \t\n";
}
else {
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << strTmp << "\t" << float(duration.count()*1.0) * std::chrono::microseconds::period::num << "us \t\n";
}
}

View File

@@ -4,14 +4,20 @@
#include <string>
#include <chrono>
typedef enum {
USE_TIME_MS = 0,
USE_TIME_US = 1,
}USE_TIME_UNIT;
class USE_TIME{
public:
USE_TIME(std::string str = "");
USE_TIME(USE_TIME_UNIT unit, std::string str = "");
~USE_TIME();
private:
std::string strTmp;
std::chrono::system_clock::time_point start;
std::string strTmp;
USE_TIME_UNIT unit;
std::chrono::system_clock::time_point start;
std::chrono::system_clock::time_point end;
};