Ncnn demo sdk (#164)
* fix different dims and data sync and fp16 macro * fix pad is negative bug, but still need debugging info * split detection_output to dets and labels * fix clang++ compile bug * for fp16 compile macro of cmake * fix pad_val dict input * fix yolox missing normalization and get int tensor * about score_threshold * remove -lstdc++fs for android * move -pthread for android * fix link libraries for CLANG++; * fix clang-format * for mobileyolov3 conf_thre * fix lint * fix bug * support ncnn vulkan net * remove unused debugging info; * Change INFO to DEBUG * support vulkan precision mapping * fix pad * optimize getdetslabels * remove EVAL_MODE * ncnn_net support 4-dim data. * remove FP16 compile options * remove use_gpu_vulkan compile options * fix pad.cpp * fix yapf * fix clang-format * rm redundant lines * fix pad according to mmdet * add android build docs * fix lint * use cpp style string comparision * fix use after free bug * Add missing -DBUILD_SHARED_LIBS=OFF for en * Add missing -DBUILD_SHARED_LIBS=OFF for ZH-CN * reset img2tensor_impl * reset img2tensor_impl * add blank line * sync android.md docs * fix some dirs * fix docs * update docs * fix codepull/278/head
parent
e01056cc0a
commit
6948e3d04b
|
@ -1 +1 @@
|
|||
backend_config = dict(type='ncnn')
|
||||
backend_config = dict(type='ncnn', precision='FP32', use_vulkan=False)
|
||||
|
|
|
@ -12,19 +12,66 @@ namespace mmdeploy::mmdet {
|
|||
|
||||
ResizeBBox::ResizeBBox(const Value& cfg) : MMDetection(cfg) {
|
||||
if (cfg.contains("params")) {
|
||||
score_thr_ = cfg["params"].value("score_thr", 0.f);
|
||||
if (cfg["params"].contains("conf_thr")) {
|
||||
// for mobilev2yolov3
|
||||
score_thr_ = cfg["params"].value("conf_thr", 0.f);
|
||||
} else {
|
||||
score_thr_ = cfg["params"].value("score_thr", 0.f);
|
||||
}
|
||||
min_bbox_size_ = cfg["params"].value("min_bbox_size", 0.f);
|
||||
}
|
||||
}
|
||||
std::vector<Tensor> ResizeBBox::GetDetsLabels(const Value& prep_res, const Value& infer_res) {
|
||||
std::vector<Tensor> results;
|
||||
if (infer_res.contains("dets") && infer_res.contains("labels")) {
|
||||
results.push_back(infer_res["dets"].get<Tensor>());
|
||||
results.push_back(infer_res["labels"].get<Tensor>());
|
||||
return results;
|
||||
} else if (infer_res.contains("detection_output") && (!infer_res.contains("dets")) &&
|
||||
(!infer_res.contains("labels"))) {
|
||||
int img_width = prep_res["img_metas"]["img_shape"][2].get<int>();
|
||||
int img_height = prep_res["img_metas"]["img_shape"][1].get<int>();
|
||||
auto detection_output = infer_res["detection_output"].get<Tensor>();
|
||||
auto* detection_output_ptr = detection_output.data<float>();
|
||||
// detection_output: (1, num_det, 6)
|
||||
TensorDesc labeldesc = detection_output.desc();
|
||||
int batch_size = detection_output.shape()[0];
|
||||
int num_det = detection_output.shape()[1];
|
||||
labeldesc.shape = {batch_size, num_det};
|
||||
Tensor labels(labeldesc);
|
||||
TensorDesc detdesc = detection_output.desc();
|
||||
detdesc.shape = {batch_size, num_det, 5};
|
||||
Tensor dets(detdesc);
|
||||
auto* dets_ptr = dets.data<float>();
|
||||
auto* labels_ptr = labels.data<float>();
|
||||
|
||||
for (int i = 0; i < batch_size * num_det; ++i) {
|
||||
*labels_ptr++ = detection_output_ptr[0] - 1;
|
||||
dets_ptr[4] = detection_output_ptr[1];
|
||||
dets_ptr[0] = detection_output_ptr[2] * img_width;
|
||||
dets_ptr[1] = detection_output_ptr[3] * img_height;
|
||||
dets_ptr[2] = detection_output_ptr[4] * img_width;
|
||||
dets_ptr[3] = detection_output_ptr[5] * img_height;
|
||||
dets_ptr += 5;
|
||||
detection_output_ptr += 6;
|
||||
}
|
||||
results.push_back(dets);
|
||||
results.push_back(labels);
|
||||
return results;
|
||||
} else {
|
||||
MMDEPLOY_ERROR("No support for another key of detection results!");
|
||||
return results;
|
||||
}
|
||||
}
|
||||
Result<Value> ResizeBBox::operator()(const Value& prep_res, const Value& infer_res) {
|
||||
MMDEPLOY_DEBUG("prep_res: {}\ninfer_res: {}", prep_res, infer_res);
|
||||
try {
|
||||
auto dets = infer_res["dets"].get<Tensor>();
|
||||
auto labels = infer_res["labels"].get<Tensor>();
|
||||
|
||||
Tensor dets, labels;
|
||||
vector<Tensor> outputs = GetDetsLabels(prep_res, infer_res);
|
||||
dets = outputs[0];
|
||||
labels = outputs[1];
|
||||
MMDEPLOY_DEBUG("dets.shape: {}", dets.shape());
|
||||
MMDEPLOY_DEBUG("labels.shape: {}", labels.shape());
|
||||
|
||||
// `dets` is supposed to have 3 dims. They are 'batch', 'bboxes_number'
|
||||
// and 'channels' respectively
|
||||
if (!(dets.shape().size() == 3 && dets.data_type() == DataType::kFLOAT)) {
|
||||
|
@ -72,7 +119,6 @@ Result<DetectorOutput> ResizeBBox::GetBBoxes(const Value& prep_res, const Tensor
|
|||
DetectorOutput objs;
|
||||
auto* dets_ptr = dets.data<float>();
|
||||
auto* labels_ptr = labels.data<T>();
|
||||
|
||||
vector<float> scale_factor;
|
||||
if (prep_res.contains("scale_factor")) {
|
||||
from_value(prep_res["scale_factor"], scale_factor);
|
||||
|
|
|
@ -26,6 +26,8 @@ class ResizeBBox : public MMDetection {
|
|||
const float* scale_factor, float x_offset, float y_offset,
|
||||
int ori_width, int ori_height);
|
||||
|
||||
std::vector<Tensor> GetDetsLabels(const Value& prep_res, const Value& infer_res);
|
||||
|
||||
protected:
|
||||
constexpr static Device kHost{0, 0};
|
||||
float score_thr_{0.f};
|
||||
|
|
|
@ -48,7 +48,7 @@ target_include_directories(${PROJECT_NAME}
|
|||
$<INSTALL_INTERFACE:include/cpp>
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${SPDLOG_LIB})
|
||||
if (NOT MSVC)
|
||||
if (NOT (MSVC OR ANDROID))
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
|
||||
endif ()
|
||||
add_library(mmdeploy::core ALIAS ${PROJECT_NAME})
|
||||
|
|
|
@ -36,7 +36,7 @@ std::string Stacktrace::to_string() const {
|
|||
} // namespace mmdeploy
|
||||
|
||||
#else
|
||||
|
||||
#include <string>
|
||||
namespace mmdeploy {
|
||||
|
||||
struct Stacktrace::Impl {};
|
||||
|
|
|
@ -12,7 +12,7 @@ endif ()
|
|||
foreach (MODEL_NAME ${MODEL_NAMES})
|
||||
set(TARGET_MODEL_NAME mmdeploy_${MODEL_NAME})
|
||||
mmdeploy_add_module(${TARGET_MODEL_NAME} ${MODEL_NAME}_impl.cpp)
|
||||
if (NOT MSVC)
|
||||
if (NOT (MSVC OR ANDROID))
|
||||
target_link_libraries(${TARGET_MODEL_NAME} PUBLIC stdc++fs)
|
||||
endif ()
|
||||
if (${MODEL_NAME} STREQUAL "zip_model")
|
||||
|
|
|
@ -22,7 +22,9 @@ Result<void> NCNNNet::Init(const Value& args) {
|
|||
auto& context = args["context"];
|
||||
device_ = context["device"].get<Device>();
|
||||
stream_ = context["stream"].get<Stream>();
|
||||
|
||||
if (args.contains("use_vulkan")) {
|
||||
net_.opt.use_vulkan_compute = args["use_vulkan"].get<bool>();
|
||||
}
|
||||
if (!device_.is_host()) {
|
||||
return Status(eNotSupported);
|
||||
}
|
||||
|
@ -30,10 +32,29 @@ Result<void> NCNNNet::Init(const Value& args) {
|
|||
auto name = args["name"].get<std::string>();
|
||||
auto model = context["model"].get<Model>();
|
||||
OUTCOME_TRY(auto config, model.GetModelConfig(name));
|
||||
|
||||
auto precision = config.precision;
|
||||
if (precision == "FP16") {
|
||||
net_.opt.use_fp16_packed = true;
|
||||
net_.opt.use_fp16_storage = true;
|
||||
net_.opt.use_fp16_arithmetic = true;
|
||||
} else if (precision == "INT8") {
|
||||
// in android platform, ncnn will automatically start FP16 accelerate.
|
||||
// In INT8 case, we set fp16 as false explicitly.
|
||||
net_.opt.use_int8_packed = true;
|
||||
net_.opt.use_int8_storage = true;
|
||||
net_.opt.use_int8_arithmetic = true;
|
||||
net_.opt.use_fp16_packed = false;
|
||||
net_.opt.use_fp16_storage = false;
|
||||
net_.opt.use_fp16_arithmetic = false;
|
||||
} else {
|
||||
// in android platform, ncnn will automatically start FP16 accelerate.
|
||||
// In FP32 case, we set fp16 as false explicitly.
|
||||
net_.opt.use_fp16_packed = false;
|
||||
net_.opt.use_fp16_storage = false;
|
||||
net_.opt.use_fp16_arithmetic = false;
|
||||
}
|
||||
OUTCOME_TRY(params_, model.ReadFile(config.net));
|
||||
OUTCOME_TRY(weights_, model.ReadFile(config.weights));
|
||||
|
||||
register_mmdeploy_custom_layers(net_);
|
||||
|
||||
OUTCOME_TRY(ncnn_status(net_.load_param_mem(params_.c_str())));
|
||||
|
@ -57,7 +78,6 @@ Result<void> NCNNNet::Init(const Value& args) {
|
|||
x,
|
||||
});
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
|
@ -91,10 +111,24 @@ Result<void> NCNNNet::Forward() {
|
|||
OUTCOME_TRY(ncnn_status(extractor.extract(output_indices_[i], outputs[i])));
|
||||
auto& tensor = output_tensors_[i];
|
||||
auto shape = outputs[i].shape();
|
||||
tensor.Reshape({1, shape.w, shape.h, shape.c});
|
||||
if (outputs[i].dims == 1) {
|
||||
tensor.Reshape({1, shape.w});
|
||||
} else if (outputs[i].dims == 2) {
|
||||
tensor.Reshape({1, shape.h, shape.w});
|
||||
} else if (outputs[i].dims == 3) {
|
||||
tensor.Reshape({1, shape.d, shape.h, shape.w});
|
||||
} else {
|
||||
// for dim==4 case and blank image.
|
||||
tensor.Reshape({1, shape.c, shape.d, shape.h, shape.w});
|
||||
}
|
||||
// tensor.Reshape({1, shape.c, shape.h, shape.w});
|
||||
// ncnn Mat may be padded, flatten to avoid that
|
||||
auto flattened = outputs[i].reshape(shape.w * shape.h * shape.c);
|
||||
OUTCOME_TRY(tensor.CopyFrom(flattened.data, stream_));
|
||||
auto flattened = outputs[i].reshape(shape.c * shape.h * shape.w);
|
||||
// if ((shape.c * shape.h * shape.w) > 0)
|
||||
if (outputs[i].dims > 0) {
|
||||
OUTCOME_TRY(tensor.CopyFrom(flattened.data, stream_));
|
||||
}
|
||||
OUTCOME_TRY(stream_.Wait());
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,17 @@ PadImpl::PadImpl(const Value& args) : TransformImpl(args) {
|
|||
}
|
||||
|
||||
arg_.size_divisor = args.value("size_divisor", 1);
|
||||
arg_.pad_val = args.value("pad_val", 0.0f);
|
||||
if (args.contains("pad_val")) {
|
||||
if (args["pad_val"].is_number()) {
|
||||
arg_.pad_val = args["pad_val"].get<float>();
|
||||
} else if (args["pad_val"].contains("img")) {
|
||||
arg_.pad_val = args["pad_val"]["img"][0].get<float>();
|
||||
} else {
|
||||
throw std::invalid_argument("args must be number or img dict");
|
||||
}
|
||||
} else {
|
||||
arg_.pad_val = 0.0f;
|
||||
}
|
||||
arg_.pad_to_square = args.value("pad_to_square", false);
|
||||
arg_.padding_mode = args.value("padding_mode", std::string("constant"));
|
||||
}
|
||||
|
@ -31,43 +41,39 @@ Result<Value> PadImpl::Process(const Value& input) {
|
|||
MMDEPLOY_DEBUG("input: {}", to_json(input).dump(2));
|
||||
Value output = input;
|
||||
auto img_fields = GetImageFields(input);
|
||||
|
||||
for (auto& key : img_fields) {
|
||||
Tensor output_tensor;
|
||||
auto tensor = input[key].get<Tensor>();
|
||||
|
||||
assert(tensor.desc().shape.size() == 4);
|
||||
assert(tensor.desc().shape[0] == 1);
|
||||
assert(tensor.desc().shape[3] == 3 || tensor.desc().shape[3] == 1);
|
||||
|
||||
int height = tensor.desc().shape[1];
|
||||
int width = tensor.desc().shape[2];
|
||||
|
||||
if (arg_.pad_to_square) {
|
||||
int max_size = std::max(tensor.desc().shape[1], tensor.desc().shape[2]);
|
||||
std::array padding{0, 0, max_size - width, max_size - height};
|
||||
|
||||
OUTCOME_TRY(output_tensor, PadImage(tensor, padding));
|
||||
|
||||
output["pad_fixed_size"].push_back(max_size);
|
||||
output["pad_fixed_size"].push_back(max_size);
|
||||
} else if (arg_.size[0] != 0 && arg_.size[1] != 0) {
|
||||
output_tensor = tensor;
|
||||
std::array padding{0, 0, arg_.size[1] - width, arg_.size[0] - height};
|
||||
OUTCOME_TRY(output_tensor, PadImage(tensor, padding));
|
||||
output["pad_fixed_size"].push_back(arg_.size[0]);
|
||||
output["pad_fixed_size"].push_back(arg_.size[1]);
|
||||
} else if (arg_.size_divisor != 1) {
|
||||
auto pad_h = (height + arg_.size_divisor - 1) / arg_.size_divisor * arg_.size_divisor;
|
||||
auto pad_w = (width + arg_.size_divisor - 1) / arg_.size_divisor * arg_.size_divisor;
|
||||
std::array padding{0, 0, pad_w - width, pad_h - height};
|
||||
|
||||
OUTCOME_TRY(output_tensor, PadImage(tensor, padding));
|
||||
|
||||
output["pad_size_divisor"] = arg_.size_divisor;
|
||||
output["pad_fixed_size"].push_back(pad_h);
|
||||
output["pad_fixed_size"].push_back(pad_w);
|
||||
} else {
|
||||
std::array padding{0, 0, arg_.size[1] - width, arg_.size[0] - height};
|
||||
|
||||
OUTCOME_TRY(output_tensor, PadImage(tensor, padding));
|
||||
|
||||
output["pad_fixed_size"].push_back(arg_.size[0]);
|
||||
output["pad_fixed_size"].push_back(arg_.size[1]);
|
||||
output_tensor = tensor;
|
||||
output["pad_fixed_size"].push_back(height);
|
||||
output["pad_fixed_size"].push_back(width);
|
||||
}
|
||||
output[key] = output_tensor;
|
||||
for (auto& v : output_tensor.desc().shape) {
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
# Build for Android
|
||||
|
||||
- [Build for Android](#build-for-android)
|
||||
- [Build From Source](#build-from-source)
|
||||
- [Install Toolchains](#install-toolchains)
|
||||
- [Install Dependencies](#install-dependencies)
|
||||
- [Install Dependencies for SDK](#install-dependencies-for-sdk)
|
||||
- [Build MMDeploy](#build-mmdeploy)
|
||||
- [Build Options Spec](#build-options-spec)
|
||||
- [Build SDK](#build-sdk)
|
||||
- [Build Demo](#build-demo)
|
||||
|
||||
---
|
||||
MMDeploy provides cross compile for android platform.
|
||||
|
||||
Model converter is executed on linux platform, and SDK is executed on android platform.
|
||||
|
||||
Here are two steps for android build.
|
||||
|
||||
1. Build model converter on linux, please refer to [How to build linux](./linux.md)
|
||||
|
||||
2. Build SDK using android toolchain on linux.
|
||||
|
||||
This doc is only for how to build SDK using android toolchain on linux.
|
||||
|
||||
## Build From Source
|
||||
|
||||
### Install Toolchains
|
||||
|
||||
- cmake
|
||||
|
||||
**Make sure cmake version >= 3.14.0**. If not, you can follow instructions below to install cmake 3.20.0. For more versions of cmake, please refer to [cmake website](https://cmake.org/install).
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y libssl-dev
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.20.0/cmake-3.20.0.tar.gz
|
||||
tar -zxvf cmake-3.20.0.tar.gz
|
||||
cd cmake-3.20.0
|
||||
./bootstrap
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
- ANDROID NDK 19+
|
||||
|
||||
**Make sure android ndk version >= 19.0**. If not, you can follow instructions below to install android ndk r23b. For more versions of android ndk, please refer to [android ndk website](https://developer.android.com/ndk/downloads).
|
||||
|
||||
```bash
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
cd android-ndk-r23b
|
||||
export NDK_PATH=${PWD}
|
||||
```
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
#### Install Dependencies for SDK
|
||||
|
||||
You can skip this chapter if only interested in model converter.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>NAME </th>
|
||||
<th>INSTALLATION </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>spdlog </td>
|
||||
<td>
|
||||
<pre><code>
|
||||
git clone -b v1.9.2 https://github.com/gabime/spdlog.git
|
||||
cd spdlog
|
||||
export SPDLOG_DIR=${PWD}
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${SPDLOG_DIR} -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-30 ..
|
||||
make install
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OpenCV<br>(>=3.0) </td>
|
||||
<td>
|
||||
<pre><code>
|
||||
export OPENCV_VERSION=4.5.4
|
||||
wget https://github.com/opencv/opencv/releases/download/${OPENCV_VERSION}/opencv-${OPENCV_VERSION}-android-sdk.zip
|
||||
unzip opencv-${OPENCV_VERSION}-android-sdk.zip
|
||||
export OPENCV_ANDROID_SDK_DIR=${PWD}/OpenCV-android-sdk
|
||||
</code></pre>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ncnn </td>
|
||||
<td>A high-performance neural network inference computing framework supporting for android.</br>
|
||||
<b> Now, MMDeploy supports v20211208 and has to use <code>git clone</code> to download it.</b><br>
|
||||
<pre><code>
|
||||
git clone -b 20211208 https://github.com/Tencent/ncnn.git
|
||||
cd ncnn
|
||||
git submodule update --init
|
||||
export NCNN_DIR=${PWD}
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-30 -DNCNN_VULKAN=ON -DNCNN_DISABLE_EXCEPTION=OFF -DNCNN_DISABLE_RTTI=OFF ..
|
||||
make install
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Build MMDeploy
|
||||
#### Build Options Spec
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>NAME</th>
|
||||
<th>VALUE</th>
|
||||
<th>DEFAULT</th>
|
||||
<th>REMARK</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>MMDEPLOY_BUILD_SDK</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>OFF</td>
|
||||
<td>Switch to build MMDeploy SDK</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_BUILD_SDK_PYTHON_API</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>OFF</td>
|
||||
<td>switch to build MMDeploy SDK python package</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_BUILD_TEST</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>OFF</td>
|
||||
<td>Switch to build MMDeploy SDK unittest cases</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_TARGET_DEVICES</td>
|
||||
<td>{"cpu"}</td>
|
||||
<td>cpu</td>
|
||||
<td>Enable target device. <br>If you want use ncnn vulkan accelerate, you still fill <code>{"cpu"}</code> here. Because, vulkan accelerate is only for ncnn net. The other part of inference is still using cpu.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_TARGET_BACKENDS</td>
|
||||
<td>{"ncnn"}</td>
|
||||
<td>N/A</td>
|
||||
<td>Enabling inference engine. <br><b>By default, no target inference engine is set, since it highly depends on the use case.</b><br> Only ncnn backend is supported for android platform now.<br>
|
||||
After specifying the inference engine, it's package path has to be passed to cmake as follows, <br>
|
||||
1. <b>ncnn</b>: ncnn. <code>ncnn_DIR</code> is needed.
|
||||
<pre><code>-Dncnn_DIR=${NCNN_DIR}/build/install/lib/cmake/ncnn</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_CODEBASES</td>
|
||||
<td>{"mmcls", "mmdet", "mmseg", "mmedit", "mmocr", "all"}</td>
|
||||
<td>N/A</td>
|
||||
<td>Enable codebase's postprocess modules. It MUST be set by a semicolon separated list of codebase names. The currently supported codebases are 'mmcls', 'mmdet', 'mmedit', 'mmseg', 'mmocr'. Instead of listing them one by one, you can also pass <code>all</code> to enable them all, i.e., <code>-DMMDEPLOY_CODEBASES=all</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BUILD_SHARED_LIBS</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>ON</td>
|
||||
<td>Switch to build shared library or static library of MMDeploy SDK. Now you should build static library for android. Bug will be fixed soon.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
#### Build SDK
|
||||
MMDeploy provides a recipe as shown below for building SDK with ncnn as inference engine for android.
|
||||
|
||||
- cpu + ncnn
|
||||
```Bash
|
||||
cd ${MMDEPLOY_DIR}
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-DMMDEPLOY_BUILD_SDK=ON \
|
||||
-DOpenCV_DIR=${OPENCV_ANDROID_SDK_DIR}/sdk/native/jni/abi-arm64-v8a \
|
||||
-Dspdlog_DIR=${SPDLOG_DIR}/lib/cmake/spdlog \
|
||||
-Dncnn_DIR=${NCNN_DIR}/build/install/lib/cmake/ncnn \
|
||||
-DMMDEPLOY_TARGET_BACKENDS=ncnn \
|
||||
-DMMDEPLOY_CODEBASES=all \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-30 \
|
||||
-DANDROID_CPP_FEATURES="rtti exceptions"
|
||||
|
||||
make -j$(nproc) && make install
|
||||
```
|
||||
|
||||
#### Build Demo
|
||||
|
||||
```Bash
|
||||
cd ${MMDEPLOY_DIR}/build/install/example
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-DOpenCV_DIR=${OPENCV_ANDROID_SDK_DIR}/sdk/native/jni/abi-arm64-v8a \
|
||||
-Dspdlog_DIR=${SPDLOG_DIR}/lib/cmake/spdlog \
|
||||
-DMMDeploy_DIR=${MMDEPLOY_DIR}/build/install/lib/cmake/MMDeploy \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-30
|
||||
cmake --build . -- -j$(nproc)
|
||||
```
|
|
@ -0,0 +1,205 @@
|
|||
# Android 下构建方式
|
||||
|
||||
- [Android 下构建方式](#Android 下构建方式)
|
||||
- [源码安装](#源码安装)
|
||||
- [安装构建和编译工具链](#安装构建和编译工具链)
|
||||
- [安装依赖包](#安装依赖包)
|
||||
- [安装 MMDeploy SDK 依赖](#安装-MMDeploy-SDK-依赖)
|
||||
- [编译 MMDeploy](#编译-mmdeploy)
|
||||
- [编译选项说明](#编译选项说明)
|
||||
- [编译 SDK](#编译-sdk)
|
||||
- [编译 Demo](#编译-demo)
|
||||
|
||||
---
|
||||
MMDeploy 为 android 平台提供交叉编译的构建方式.
|
||||
|
||||
MMDeploy converter 部分在 linux 平台上执行,SDK 部分在 android 平台上执行.
|
||||
|
||||
MMDeploy 的交叉编译分为两步:
|
||||
|
||||
1. 在 linux 平台上构建 MMDeploy converter. 请根据 [How to build linux](./linux.md) 进行构建.
|
||||
|
||||
2. 使用 android 工具链构建 MMDeploy SDK.
|
||||
|
||||
本文档仅提供在 linux 平台上使用 android 工具链进行交叉编译构建 MMDeploy SDK 的方法.
|
||||
|
||||
## 源码安装
|
||||
|
||||
### 安装构建和编译工具链
|
||||
|
||||
- cmake
|
||||
|
||||
**保证 cmake的版本 >= 3.14.0**. 如果不是,可以参考以下命令安装 3.20.0 版本. 如要获取其他版本,请参考 [这里](https://cmake.org/install)
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y libssl-dev
|
||||
wget https://github.com/Kitware/CMake/releases/download/v3.20.0/cmake-3.20.0.tar.gz
|
||||
tar -zxvf cmake-3.20.0.tar.gz
|
||||
cd cmake-3.20.0
|
||||
./bootstrap
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
- ANDROID NDK 19+
|
||||
|
||||
**保证 android ndk 的版本 >= 19.0**. 如果不是,可以参考以下命令安装 r23b 版本. 如要获取其他版本,请参考 [这里](https://developer.android.com/ndk/downloads)
|
||||
|
||||
```bash
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
cd android-ndk-r23b
|
||||
export NDK_PATH=${PWD}
|
||||
```
|
||||
|
||||
### 安装依赖包
|
||||
|
||||
#### 安装 MMDeploy SDK 依赖
|
||||
|
||||
如果您只对模型转换感兴趣,那么可以跳过本章节.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称 </th>
|
||||
<th>安装方式 </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>spdlog </td>
|
||||
<td>
|
||||
<pre><code>
|
||||
git clone -b v1.9.2 https://github.com/gabime/spdlog.git
|
||||
cd spdlog
|
||||
export SPDLOG_DIR=${PWD}
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${SPDLOG_DIR} -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-30 ..
|
||||
make install
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OpenCV<br>(>=3.0) </td>
|
||||
<td>
|
||||
<pre><code>
|
||||
export OPENCV_VERSION=4.5.4
|
||||
wget https://github.com/opencv/opencv/releases/download/${OPENCV_VERSION}/opencv-${OPENCV_VERSION}-android-sdk.zip
|
||||
unzip opencv-${OPENCV_VERSION}-android-sdk.zip
|
||||
export OPENCV_ANDROID_SDK_DIR=${PWD}/OpenCV-android-sdk
|
||||
</code></pre>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ncnn </td>
|
||||
<td>ncnn 是支持 android 平台的高效神经网络推理计算框架</br>
|
||||
<b> 目前, MMDeploy 支持 ncnn 的 20211208 版本, 且必须使用<code>git clone</code> 下载源码的方式安装</b><br>
|
||||
<pre><code>
|
||||
git clone -b 20211208 https://github.com/Tencent/ncnn.git
|
||||
cd ncnn
|
||||
git submodule update --init
|
||||
export NCNN_DIR=${PWD}
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-30 -DNCNN_VULKAN=ON -DNCNN_DISABLE_EXCEPTION=OFF -DNCNN_DISABLE_RTTI=OFF ..
|
||||
make install
|
||||
</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### 编译 MMDeploy
|
||||
#### 编译选项说明
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编译选项</th>
|
||||
<th>取值范围</th>
|
||||
<th>缺省值</th>
|
||||
<th>说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>MMDEPLOY_BUILD_SDK</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>OFF</td>
|
||||
<td>MMDeploy SDK 编译开关</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_BUILD_TEST</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>OFF</td>
|
||||
<td>MMDeploy SDK 的单元测试程序编译开关</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_TARGET_DEVICES</td>
|
||||
<td>{"cpu"}</td>
|
||||
<td>cpu</td>
|
||||
<td>设置目标设备. <br>如果您想使用 ncnn 的 vulkan 加速功能, 您仍旧需要在这里填写<code>{"cpu"}</code>参数. 这是因为 vulkan 加速仅用于 ncnn 网络计算内部,推理过程的其他部分仍旧使用 cpu 计算.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_TARGET_BACKENDS</td>
|
||||
<td>{"ncnn"}</td>
|
||||
<td>N/A</td>
|
||||
<td>设置推理后端. <br><b>默认情况下,SDK不设置任何后端, 因为它与应用场景高度相关.</b><br> Android 端目前只支持ncnn一个后端 <br>
|
||||
构建时,几乎每个后端,都需传入一些路径变量,用来查找依赖包. <br>
|
||||
1. <b>ncnn</b>: 表示 ncnn. 需要设置<code>ncnn_DIR</code>.
|
||||
<pre><code>-Dncnn_DIR=${NCNN_DIR}/build/install/lib/cmake/ncnn</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MMDEPLOY_CODEBASES</td>
|
||||
<td>{"mmcls", "mmdet", "mmseg", "mmedit", "mmocr", "all"}</td>
|
||||
<td>N/A</td>
|
||||
<td>用来设置 SDK 后处理组件,加载 OpenMMLab 算法仓库的后处理功能. 已支持的算法仓库有'mmcls','mmdet','mmedit','mmseg'和'mmocr'. 如果选择多个codebase,中间使用分号隔开. 比如, 'mmcls', 'mmdet', 'mmedit', 'mmseg', 'mmocr'. 也可以通过 <code>all</code> 的方式, 加载所有codebase, 即 <code>-DMMDEPLOY_CODEBASES=all.</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BUILD_SHARED_LIBS</td>
|
||||
<td>{ON, OFF}</td>
|
||||
<td>ON</td>
|
||||
<td>MMDeploy SDK 的动态库的编译开关.设置 OFF 时, 编译静态库. 目前 android 端 SDK 仅支持静态库加载, 后续会进行对动态库加载的支持.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
#### 编译 SDK
|
||||
|
||||
下文展示构建SDK的样例,用 ncnn 作为推理引擎。
|
||||
|
||||
- cpu + ncnn
|
||||
```Bash
|
||||
cd ${MMDEPLOY_DIR}
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-DMMDEPLOY_BUILD_SDK=ON \
|
||||
-DOpenCV_DIR=${OPENCV_ANDROID_SDK_DIR}/sdk/native/jni/abi-arm64-v8a \
|
||||
-Dspdlog_DIR=${SPDLOG_DIR}/lib/cmake/spdlog \
|
||||
-Dncnn_DIR=${NCNN_DIR}/build/install/lib/cmake/ncnn \
|
||||
-DMMDEPLOY_TARGET_BACKENDS=ncnn \
|
||||
-DMMDEPLOY_CODEBASES=all \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-30 \
|
||||
-DANDROID_CPP_FEATURES="rtti exceptions"
|
||||
|
||||
make -j$(nproc) && make install
|
||||
```
|
||||
|
||||
#### 编译 Demo
|
||||
|
||||
```Bash
|
||||
cd ${MMDEPLOY_DIR}/build/install/example
|
||||
mkdir -p build && cd build
|
||||
cmake .. \
|
||||
-DOpenCV_DIR=${OPENCV_ANDROID_SDK_DIR}/sdk/native/jni/abi-arm64-v8a \
|
||||
-Dspdlog_DIR=${SPDLOG_DIR}/lib/cmake/spdlog \
|
||||
-DMMDeploy_DIR=${MMDEPLOY_DIR}/build/install/lib/cmake/MMDeploy \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-30
|
||||
cmake --build . -- -j$(nproc)
|
||||
```
|
|
@ -112,6 +112,8 @@ def get_models(deploy_cfg: Union[str, mmcv.Config],
|
|||
elif backend == Backend.NCNN:
|
||||
net = onnx_name.replace('.onnx', '.param')
|
||||
weights = onnx_name.replace('.onnx', '.bin')
|
||||
if 'precision' in deploy_cfg['backend_config']:
|
||||
precision = deploy_cfg['backend_config']['precision']
|
||||
elif backend == Backend.ONNXRUNTIME:
|
||||
pass
|
||||
else:
|
||||
|
@ -153,13 +155,16 @@ def get_inference_info(deploy_cfg: mmcv.Config, model_cfg: mmcv.Config,
|
|||
input_names = onnx_config.get('input_names', None)
|
||||
input_name = input_names[0] if input_names else 'input'
|
||||
input_map = dict(img=input_name)
|
||||
return dict(
|
||||
return_dict = dict(
|
||||
name=name,
|
||||
type=type,
|
||||
module=module,
|
||||
input=input,
|
||||
output=output,
|
||||
input_map=input_map)
|
||||
if 'use_vulkan' in deploy_cfg['backend_config']:
|
||||
return_dict['use_vulkan'] = deploy_cfg['backend_config']['use_vulkan']
|
||||
return return_dict
|
||||
|
||||
|
||||
def get_preprocess(deploy_cfg: mmcv.Config, model_cfg: mmcv.Config):
|
||||
|
|
Loading…
Reference in New Issue