From 210359dd57410a1f8eb2321bf594ec28bcd2c283 Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 10 Aug 2022 19:45:40 +0800 Subject: [PATCH 01/28] add ppl.nn riscv engine --- csrc/mmdeploy/net/ppl/CMakeLists.txt | 3 +++ csrc/mmdeploy/net/ppl/ppl_net.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/csrc/mmdeploy/net/ppl/CMakeLists.txt b/csrc/mmdeploy/net/ppl/CMakeLists.txt index a65c64d4de..c92b80ba72 100644 --- a/csrc/mmdeploy/net/ppl/CMakeLists.txt +++ b/csrc/mmdeploy/net/ppl/CMakeLists.txt @@ -18,4 +18,7 @@ if (PPLNN_USE_CUDA AND ("cuda" IN_LIST MMDEPLOY_TARGET_DEVICES)) endif () target_link_libraries(${PROJECT_NAME} PRIVATE ${PPLNN_LIBRARIES}) +if (PPLNN_USE_RISCV AND ("cpu" IN_LIST MMDEPLOY_TARGET_DEVICES)) + target_compile_definitions(${PROJECT_NAME} PRIVATE -DPPL_NN_HAS_RISCV=1) +endif () add_library(mmdeploy::pplnn_net ALIAS ${PROJECT_NAME}) diff --git a/csrc/mmdeploy/net/ppl/ppl_net.cpp b/csrc/mmdeploy/net/ppl/ppl_net.cpp index 3f404983d8..666090eab6 100644 --- a/csrc/mmdeploy/net/ppl/ppl_net.cpp +++ b/csrc/mmdeploy/net/ppl/ppl_net.cpp @@ -18,6 +18,11 @@ #include "ppl/nn/engines/cuda/ops.h" #define PPL_CUDA_IMPORT_FROM_BUFFER 1 #endif +#if PPL_NN_HAS_RISCV +#include "ppl/nn/engines/riscv/engine_factory.h" +#include "ppl/nn/engines/riscv/engine_options.h" +#include "ppl/nn/engines/riscv/ops.h" +#endif namespace mmdeploy { @@ -92,6 +97,12 @@ Result PPLNet::Init(const Value& args) { engines_.emplace_back(ppl::nn::x86::EngineFactory::Create({})); } #endif +#if PPL_NN_HAS_RISCV + if (device_.is_host()) { + ppl::nn::riscv::RegisterBuiltinOpImpls(); + engines_.emplace_back(ppl::nn::riscv::EngineFactory::Create({})); + } +#endif std::vector engines; for (const auto& engine : engines_) { From 55268fec88013a9469e6c17635e977f9ad8b5063 Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 11 Aug 2022 16:06:54 +0800 Subject: [PATCH 02/28] update ppl.nn riscv engine --- csrc/mmdeploy/net/ppl/ppl_net.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/csrc/mmdeploy/net/ppl/ppl_net.cpp b/csrc/mmdeploy/net/ppl/ppl_net.cpp index 666090eab6..43d0f22c2d 100644 --- a/csrc/mmdeploy/net/ppl/ppl_net.cpp +++ b/csrc/mmdeploy/net/ppl/ppl_net.cpp @@ -100,7 +100,13 @@ Result PPLNet::Init(const Value& args) { #if PPL_NN_HAS_RISCV if (device_.is_host()) { ppl::nn::riscv::RegisterBuiltinOpImpls(); - engines_.emplace_back(ppl::nn::riscv::EngineFactory::Create({})); + ppl::nn::riscv::EngineOptions options{}; + // TODO: + // FP16 -> postprocess + options.forward_precision = ppl::common::DATATYPE_FLOAT32; + options.dynamic_tuning_level = 0; + options.winograd_level = 1; + engines_.emplace_back(ppl::nn::riscv::EngineFactory::Create(options)); } #endif From ec2eed8bdd221aee5e4fd266654a3a995cc9ab84 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 16 Aug 2022 16:20:21 +0800 Subject: [PATCH 03/28] udpate riscv service (ncnn backend) --- CMakeLists.txt | 6 + cmake/toolchains/riscv64-linux-gnu.cmake | 22 ++ csrc/mmdeploy/backend_ops/ncnn/CMakeLists.txt | 2 +- mmdeploy/backend/ncnn/client/inference_pb2.py | 42 ++++ .../backend/ncnn/client/inference_pb2_grpc.py | 173 ++++++++++++++ mmdeploy/backend/ncnn/wrapper.py | 218 ++++++++++++++---- mmdeploy/utils/retry_interceptor.py | 81 +++++++ service/riscv/CMakeLists.txt | 57 +++++ service/riscv/backend.cpp | 94 ++++++++ service/riscv/backend.h | 41 ++++ service/riscv/common.cmake | 123 ++++++++++ service/riscv/inference.proto | 89 +++++++ service/riscv/inference_server.cpp | 90 ++++++++ service/riscv/server_impl.cpp | 38 +++ service/riscv/server_impl.h | 42 ++++ 15 files changed, 1071 insertions(+), 47 deletions(-) create mode 100644 cmake/toolchains/riscv64-linux-gnu.cmake create mode 100644 mmdeploy/backend/ncnn/client/inference_pb2.py create mode 100644 mmdeploy/backend/ncnn/client/inference_pb2_grpc.py create mode 100644 mmdeploy/utils/retry_interceptor.py create mode 100644 service/riscv/CMakeLists.txt create mode 100644 service/riscv/backend.cpp create mode 100644 service/riscv/backend.h create mode 100644 service/riscv/common.cmake create mode 100644 service/riscv/inference.proto create mode 100644 service/riscv/inference_server.cpp create mode 100644 service/riscv/server_impl.cpp create mode 100644 service/riscv/server_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cfde11ec04..52ae2c4074 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(MMDEPLOY_BUILD_EXAMPLES "build examples" OFF) option(MMDEPLOY_SPDLOG_EXTERNAL "use external spdlog" OFF) option(MMDEPLOY_ZIP_MODEL "support SDK model in zip format" OFF) option(MMDEPLOY_COVERAGE "build SDK for coverage" OFF) +option(MMDEPLOY_BUILD_RISCV_SERVER "build riscv server" OFF) set(MMDEPLOY_TARGET_DEVICES "cpu" CACHE STRING "target devices to support") set(MMDEPLOY_TARGET_BACKENDS "" CACHE STRING "target inference engines to support") @@ -97,6 +98,11 @@ if (MMDEPLOY_BUILD_SDK) MMDeployLibs EXPORT MMDeployTargets) + if (MMDEPLOY_BUILD_RISCV_SERVER) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + add_subdirectory(service/riscv/server) + endif () + if (MMDEPLOY_BUILD_TEST) add_subdirectory(tests/test_csrc) endif () diff --git a/cmake/toolchains/riscv64-linux-gnu.cmake b/cmake/toolchains/riscv64-linux-gnu.cmake new file mode 100644 index 0000000000..0117ce98e3 --- /dev/null +++ b/cmake/toolchains/riscv64-linux-gnu.cmake @@ -0,0 +1,22 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv) + +if(DEFINED ENV{RISCV_ROOT_PATH}) + file(TO_CMAKE_PATH $ENV{RISCV_ROOT_PATH} RISCV_ROOT_PATH) +else() + message(FATAL_ERROR "RISCV_ROOT_PATH env must be defined") +endif() + +set(CMAKE_C_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-g++) + +set(CMAKE_SYSROOT "${RISCV_ROOT_PATH}/sysroot" CACHE PATH "riscv sysroot") +set(CMAKE_FIND_ROOT_PATH ${RISCV_ROOT_PATH}/riscv64-unknown-linux-gnu) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +set(CMAKE_C_FLAGS "-march=rv64gc -mabi=lp64d -mtune=c906") +set(CMAKE_CXX_FLAGS "-march=rv64gc -mabi=lp64d -mtune=c906") diff --git a/csrc/mmdeploy/backend_ops/ncnn/CMakeLists.txt b/csrc/mmdeploy/backend_ops/ncnn/CMakeLists.txt index 42901f77f9..4df9ad1233 100755 --- a/csrc/mmdeploy/backend_ops/ncnn/CMakeLists.txt +++ b/csrc/mmdeploy/backend_ops/ncnn/CMakeLists.txt @@ -10,7 +10,7 @@ else () endif () -if (NOT ANDROID AND NOT IOS) +if (NOT ANDROID AND NOT IOS AND NOT CMAKE_CROSSCOMPILING) add_subdirectory(ops) add_subdirectory(onnx2ncnn) add_subdirectory(pyncnn_ext) diff --git a/mmdeploy/backend/ncnn/client/inference_pb2.py b/mmdeploy/backend/ncnn/client/inference_pb2.py new file mode 100644 index 0000000000..91657aad12 --- /dev/null +++ b/mmdeploy/backend/ncnn/client/inference_pb2.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: inference.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0finference.proto\x12\x08mmdeploy\"7\n\x08PPLModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07weights\x18\x02 \x01(\x0c\x42\x07\n\x05_name\"H\n\tNCNNModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0e\n\x06params\x18\x02 \x01(\x0c\x12\x0f\n\x07weights\x18\x03 \x01(\x0c\x42\x07\n\x05_name\"\x89\x01\n\x05Model\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.mmdeploy.ModelType\x12&\n\x04ncnn\x18\x02 \x01(\x0b\x32\x13.mmdeploy.NCNNModelH\x00\x88\x01\x01\x12$\n\x03ppl\x18\x03 \x01(\x0b\x32\x12.mmdeploy.PPLModelH\x01\x88\x01\x01\x42\x07\n\x05_ncnnB\x06\n\x04_ppl\"\x07\n\x05\x45mpty\"Q\n\x06Tensor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\x05\x64type\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\r\n\x05shape\x18\x04 \x03(\x05\x42\x08\n\x06_dtype\",\n\nTensorList\x12\x1e\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x10.mmdeploy.Tensor\"E\n\x05Reply\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0c\n\x04info\x18\x02 \x01(\t\x12\x1e\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\x10.mmdeploy.Tensor\"\x16\n\x05Names\x12\r\n\x05names\x18\x01 \x03(\t*,\n\tModelType\x12\n\n\x06UNKOWN\x10\x00\x12\x08\n\x04NCNN\x10\x01\x12\t\n\x05PPLNN\x10\x02\x32\xcf\x01\n\tInference\x12*\n\x04Init\x12\x0f.mmdeploy.Model\x1a\x0f.mmdeploy.Reply\"\x00\x12\x31\n\x0bOutputNames\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Names\"\x00\x12\x34\n\tInference\x12\x14.mmdeploy.TensorList\x1a\x0f.mmdeploy.Reply\"\x00\x12-\n\x07\x44\x65stroy\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Reply\"\x00\x42(\n\x0emmdeploy.riscvB\x0cRISCVWrapperP\x01\xa2\x02\x05RISCVb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'inference_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + DESCRIPTOR._serialized_options = b'\n\016mmdeploy.riscvB\014RISCVWrapperP\001\242\002\005RISCV' + _MODELTYPE._serialized_start = 533 + _MODELTYPE._serialized_end = 577 + _PPLMODEL._serialized_start = 29 + _PPLMODEL._serialized_end = 84 + _NCNNMODEL._serialized_start = 86 + _NCNNMODEL._serialized_end = 158 + _MODEL._serialized_start = 161 + _MODEL._serialized_end = 298 + _EMPTY._serialized_start = 300 + _EMPTY._serialized_end = 307 + _TENSOR._serialized_start = 309 + _TENSOR._serialized_end = 390 + _TENSORLIST._serialized_start = 392 + _TENSORLIST._serialized_end = 436 + _REPLY._serialized_start = 438 + _REPLY._serialized_end = 507 + _NAMES._serialized_start = 509 + _NAMES._serialized_end = 531 + _INFERENCE._serialized_start = 580 + _INFERENCE._serialized_end = 787 +# @@protoc_insertion_point(module_scope) diff --git a/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py b/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py new file mode 100644 index 0000000000..1983b07e52 --- /dev/null +++ b/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py @@ -0,0 +1,173 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from . import inference_pb2 as inference__pb2 + + +class InferenceStub(object): + """The inference service definition. + """ + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.Init = channel.unary_unary( + '/mmdeploy.Inference/Init', + request_serializer=inference__pb2.Model.SerializeToString, + response_deserializer=inference__pb2.Reply.FromString, + ) + self.OutputNames = channel.unary_unary( + '/mmdeploy.Inference/OutputNames', + request_serializer=inference__pb2.Empty.SerializeToString, + response_deserializer=inference__pb2.Names.FromString, + ) + self.Inference = channel.unary_unary( + '/mmdeploy.Inference/Inference', + request_serializer=inference__pb2.TensorList.SerializeToString, + response_deserializer=inference__pb2.Reply.FromString, + ) + self.Destroy = channel.unary_unary( + '/mmdeploy.Inference/Destroy', + request_serializer=inference__pb2.Empty.SerializeToString, + response_deserializer=inference__pb2.Reply.FromString, + ) + + +class InferenceServicer(object): + """The inference service definition. + """ + + def Init(self, request, context): + """Init Model with model file + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def OutputNames(self, request, context): + """Get output names + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Inference(self, request, context): + """Inference with inputs + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def Destroy(self, request, context): + """Destroy handle + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_InferenceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'Init': grpc.unary_unary_rpc_method_handler( + servicer.Init, + request_deserializer=inference__pb2.Model.FromString, + response_serializer=inference__pb2.Reply.SerializeToString, + ), + 'OutputNames': grpc.unary_unary_rpc_method_handler( + servicer.OutputNames, + request_deserializer=inference__pb2.Empty.FromString, + response_serializer=inference__pb2.Names.SerializeToString, + ), + 'Inference': grpc.unary_unary_rpc_method_handler( + servicer.Inference, + request_deserializer=inference__pb2.TensorList.FromString, + response_serializer=inference__pb2.Reply.SerializeToString, + ), + 'Destroy': grpc.unary_unary_rpc_method_handler( + servicer.Destroy, + request_deserializer=inference__pb2.Empty.FromString, + response_serializer=inference__pb2.Reply.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'mmdeploy.Inference', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + # This class is part of an EXPERIMENTAL API. + + +class Inference(object): + """The inference service definition. + """ + + @staticmethod + def Init(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Init', + inference__pb2.Model.SerializeToString, + inference__pb2.Reply.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def OutputNames(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/OutputNames', + inference__pb2.Empty.SerializeToString, + inference__pb2.Names.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Inference(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Inference', + inference__pb2.TensorList.SerializeToString, + inference__pb2.Reply.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def Destroy(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Destroy', + inference__pb2.Empty.SerializeToString, + inference__pb2.Reply.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/mmdeploy/backend/ncnn/wrapper.py b/mmdeploy/backend/ncnn/wrapper.py index adc9dccdf0..cf91778108 100644 --- a/mmdeploy/backend/ncnn/wrapper.py +++ b/mmdeploy/backend/ncnn/wrapper.py @@ -11,6 +11,170 @@ from ..base import BACKEND_WRAPPER, BaseWrapper +class NCNNLocal: + """ncnn local wrapper class for inference + + Args: + param_file (str): Path of a parameter file. + bin_file (str): Path of a binary file. + output_names (Sequence[str] | None): Names of model outputs in order. + Defaults to `None` and the wrapper will load the output names from + ncnn model. + """ + + def __init__(self, + param_file: str, + bin_file: str, + output_names: Optional[Sequence[str]] = None, + use_vulkan: bool = False, + **kwargs): + + net = ncnn.Net() + if importlib.util.find_spec('mmdeploy.backend.ncnn.ncnn_ext'): + from mmdeploy.backend.ncnn import ncnn_ext + ncnn_ext.register_mmdeploy_custom_layers(net) + net.opt.use_vulkan_compute = use_vulkan + net.load_param(param_file) + net.load_model(bin_file) + + self._net = net + if output_names is None: + assert hasattr(self._net, 'output_names') + output_names = self._net.output_names() + self.output_names = output_names + + def forward(self, + inputs: Dict[str, torch.Tensor], + batch_id: int): + + # create extractor + ex = self._net.create_extractor() + + # set inputs + for name, input_tensor in inputs.items(): + data = input_tensor[batch_id].contiguous() + data = data.detach().cpu().numpy() + input_mat = ncnn.Mat(data) + ex.input(name, input_mat) + + # get outputs + result = self.__ncnn_execute( + extractor=ex, output_names=self.output_names) + + return result + + @TimeCounter.count_time(Backend.NCNN.value) + def __ncnn_execute(self, extractor: ncnn.Extractor, + output_names: Sequence[str]) -> Dict[str, ncnn.Mat]: + """Run inference with ncnn. + + Args: + extractor (ncnn.Extractor): ncnn extractor to extract output. + output_names (Iterable[str]): A list of string specifying + output names. + + Returns: + dict[str, ncnn.Mat]: Inference results of ncnn model. + """ + result = {} + for name in output_names: + out_ret, out = extractor.extract(name) + assert out_ret == 0, f'Failed to extract output : {out}.' + result[name] = out + return result + + +class NCNNRemote: + """ncnn remote wrapper class for inference + + Args: + param_file (str): Path of a parameter file. + bin_file (str): Path of a binary file. + output_names (Sequence[str] | None): Names of model outputs in order. + Defaults to `None` and the wrapper will load the output names from + ncnn model. + uri (str): uri for the server. + """ + + def __init__(self, + param_file: str, + bin_file: str, + output_names: Optional[Sequence[str]] = None, + uri=None, + **kwargs): + from mmdeploy.utils.retry_interceptor import RetryOnRpcErrorClientInterceptor, ExponentialBackoff + import grpc + from .client import inference_pb2_grpc + from .client import inference_pb2 + + self._Tensor = inference_pb2.Tensor + self._TensorList = inference_pb2.TensorList + + logger = get_root_logger() + + if uri is None: + logger.error('URI not set') + + interceptors = (RetryOnRpcErrorClientInterceptor( + max_attempts=4, + sleeping_policy=ExponentialBackoff( + init_backoff_ms=100, max_backoff_ms=1600, multiplier=2), + status_for_retry=(grpc.StatusCode.UNAVAILABLE, ), + ), ) + self.stub = inference_pb2_grpc.InferenceStub( + grpc.intercept_channel(grpc.insecure_channel(uri), *interceptors)) + + with open(param_file, 'rb') as f: + params = f.read() + with open(bin_file, 'rb') as f: + weights = f.read() + + ncnn_model = inference_pb2.NCNNModel(params=params, weights=weights) + model = inference_pb2.Model(type=inference_pb2.NCNN, ncnn=ncnn_model) + resp = self.stub.Init(model) + + if resp.status != 0: + logger.error(f'init NCNN model failed {resp.info}') + return + + output = self.stub.OutputNames(inference_pb2.Empty()) + output_names = output.names + self.output_names = output_names + + def forward(self, + inputs: Dict[str, torch.Tensor], + batch_id: int): + ncnn_inputs = [] + for name, input_tensor in inputs.items(): + data = input_tensor[batch_id].contiguous() + data = data.detach().cpu().numpy() + data = data.astype(dtype=np.float32) + tensor = self._Tensor( + data=data.tobytes(), + name=name, + dtype='float32', + shape=list(data.shape)) + ncnn_inputs.append(tensor) + + tensorList = self._TensorList(data=ncnn_inputs) + return self.__ncnn_execute(tensorList) + + def __ncnn_execute(self, + tensorList): + resp = self.stub.Inference(tensorList) + result = dict() + if resp.status == 0: + for tensor in resp.data: + ndarray = np.frombuffer(tensor.data, dtype=np.float32) + ndarray = ndarray.reshape(tuple(tensor.shape)) + result[tensor.name] = ncnn.Mat(ndarray) + else: + logger = get_root_logger() + logger.error(f'onnx inference failed {resp.info}') + + return result + + @BACKEND_WRAPPER.register_module(Backend.NCNN.value) class NCNNWrapper(BaseWrapper): """ncnn wrapper class for inference. @@ -39,21 +203,15 @@ def __init__(self, bin_file: str, output_names: Optional[Sequence[str]] = None, use_vulkan: bool = False, + uri=None, **kwargs): + if uri is None: + self._net = NCNNLocal( + param_file, bin_file, output_names, use_vulkan) + else: + self._net = NCNNRemote(param_file, bin_file, output_names, uri) - net = ncnn.Net() - if importlib.util.find_spec('mmdeploy.backend.ncnn.ncnn_ext'): - from mmdeploy.backend.ncnn import ncnn_ext - ncnn_ext.register_mmdeploy_custom_layers(net) - net.opt.use_vulkan_compute = use_vulkan - net.load_param(param_file) - net.load_model(bin_file) - - self._net = net - if output_names is None: - assert hasattr(self._net, 'output_names') - output_names = self._net.output_names() - + output_names = self._net.output_names super().__init__(output_names) @staticmethod @@ -94,19 +252,7 @@ def forward(self, inputs: Dict[str, outputs = dict([name, [None] * batch_size] for name in output_names) # run inference for batch_id in range(batch_size): - # create extractor - ex = self._net.create_extractor() - - # set inputs - for name, input_tensor in inputs.items(): - data = input_tensor[batch_id].contiguous() - data = data.detach().cpu().numpy() - input_mat = ncnn.Mat(data) - ex.input(name, input_mat) - - # get outputs - result = self.__ncnn_execute( - extractor=ex, output_names=output_names) + result = self._net.forward(inputs, batch_id) for name in output_names: mat = result[name] # deal with special case @@ -124,23 +270,3 @@ def forward(self, inputs: Dict[str, outputs[name] = torch.stack(output_tensor) return outputs - - @TimeCounter.count_time(Backend.NCNN.value) - def __ncnn_execute(self, extractor: ncnn.Extractor, - output_names: Sequence[str]) -> Dict[str, ncnn.Mat]: - """Run inference with ncnn. - - Args: - extractor (ncnn.Extractor): ncnn extractor to extract output. - output_names (Iterable[str]): A list of string specifying - output names. - - Returns: - dict[str, ncnn.Mat]: Inference results of ncnn model. - """ - result = {} - for name in output_names: - out_ret, out = extractor.extract(name) - assert out_ret == 0, f'Failed to extract output : {out}.' - result[name] = out - return result diff --git a/mmdeploy/utils/retry_interceptor.py b/mmdeploy/utils/retry_interceptor.py new file mode 100644 index 0000000000..bec6b42154 --- /dev/null +++ b/mmdeploy/utils/retry_interceptor.py @@ -0,0 +1,81 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +import abc +from random import randint +import grpc +import time +from mmdeploy.utils import get_root_logger +from typing import Optional, Tuple + + +class SleepingPolicy(abc.ABC): + + @abc.abstractmethod + def sleep(self, try_i: int): + """How long to sleep in milliseconds. + + :param try_i: the number of retry (starting from zero) + """ + assert try_i >= 0 + + +class ExponentialBackoff(SleepingPolicy): + + def __init__(self, *, init_backoff_ms: int, max_backoff_ms: int, + multiplier: int): + self.init_backoff = randint(0, init_backoff_ms) + self.max_backoff = max_backoff_ms + self.multiplier = multiplier + + def sleep(self, try_i: int): + sleep_range = min(self.init_backoff * self.multiplier**try_i, + self.max_backoff) + sleep_ms = randint(0, sleep_range) + logger = get_root_logger() + logger.debug(f'Sleeping for {sleep_ms}') + time.sleep(sleep_ms / 1000) + + +class RetryOnRpcErrorClientInterceptor(grpc.UnaryUnaryClientInterceptor, + grpc.StreamUnaryClientInterceptor): + + def __init__( + self, + *, + max_attempts: int, + sleeping_policy: SleepingPolicy, + status_for_retry: Optional[Tuple[grpc.StatusCode]] = None, + ): + self.max_attempts = max_attempts + self.sleeping_policy = sleeping_policy + self.status_for_retry = status_for_retry + + def _intercept_call(self, continuation, client_call_details, + request_or_iterator): + + for try_i in range(self.max_attempts): + response = continuation(client_call_details, request_or_iterator) + + if isinstance(response, grpc.RpcError): + + # Return if it was last attempt + if try_i == (self.max_attempts - 1): + return response + + # If status code is not in retryable status codes + if (self.status_for_retry + and response.code() not in self.status_for_retry): + return response + + self.sleeping_policy.sleep(try_i) + else: + return response + + def intercept_unary_unary(self, continuation, client_call_details, + request): + return self._intercept_call(continuation, client_call_details, request) + + def intercept_stream_unary(self, continuation, client_call_details, + request_iterator): + return self._intercept_call(continuation, client_call_details, + request_iterator) diff --git a/service/riscv/CMakeLists.txt b/service/riscv/CMakeLists.txt new file mode 100644 index 0000000000..32443dc410 --- /dev/null +++ b/service/riscv/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.14) +project(RISCVServer C CXX) +include(./common.cmake) +include(../../cmake/MMDeploy.cmake) + +# Proto file +get_filename_component(rv_proto "inference.proto" ABSOLUTE) +get_filename_component(rv_proto_path "${rv_proto}" PATH) + +# Generated sources +set(rv_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/inference.pb.cc") +set(rv_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/inference.pb.h") +set(rv_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/inference.grpc.pb.cc") +set(rv_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/inference.grpc.pb.h") + +add_custom_command( + OUTPUT "${rv_proto_srcs}" "${rv_proto_hdrs}" "${rv_grpc_srcs}" "${rv_grpc_hdrs}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${rv_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" + "${rv_proto}" + DEPENDS "${rv_proto}") + +find_package(ncnn REQUIRED) +# find_package(pplnn REQUIRED) + +# Include generated *.pb.h files +include_directories("${CMAKE_CURRENT_BINARY_DIR}") + +add_executable(inference_server + server_impl.cpp + inference_server.cpp + backend.cpp + ${rv_proto_srcs} + ${rv_grpc_srcs}) + +target_link_libraries(inference_server + PRIVATE + mmdeploy_ncnn_ops_obj + mmdeploy::core + ncnn + ${PPLNN_LIBRARIES} + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF} + -static) + +set_target_properties(inference_server + PROPERTIES RUNTIME_OUTPUT_DIRECTORY + ${CMAKE_BINARY_DIR}/riscv-server) + +# generate pb file +# GRPC_BIN_PATH=/opt/grpc/build/install/bin +# ${GRPC_BIN_PATH}/protoc -I . --python_out client --grpc_out client inference.proto --plugin=protoc-gen-grpc=${GRPC_BIN_PATH}/grpc_python_plugin + diff --git a/service/riscv/backend.cpp b/service/riscv/backend.cpp new file mode 100644 index 0000000000..004a1695bf --- /dev/null +++ b/service/riscv/backend.cpp @@ -0,0 +1,94 @@ +#include "backend.h" + +#include +#include +#include + +#include "mmdeploy/core/logger.h" +#include "ncnn_ops_register.h" + +Status NCNNNet::Init(ServerContext* context, const Model* request, Reply* response) { + MMDEPLOY_INFO("Init ncnn net ..."); + net_.opt.use_fp16_packed = true; + net_.opt.use_fp16_storage = true; + net_.opt.use_fp16_arithmetic = true; + register_mmdeploy_custom_layers(net_); + // copy params & weights + params_ = request->ncnn().params(); + weights_ = request->ncnn().weights(); + net_.load_param_mem(params_.c_str()); + net_.load_model(reinterpret_cast(weights_.data())); + + response->set_status(0); + return Status::OK; +} + +Status NCNNNet::OutputNames(ServerContext* context, const Empty* request, Names* response) { + for (const auto& name : net_.output_names()) { + response->add_names(name); + } + return Status::OK; +} + +Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Reply* response) { + auto extractor = net_.create_extractor(); + + const std::vector& input_names = net_.input_names(); + std::vector inputs(input_names.size()); + if (input_names.size() != request->data_size()) { + MMDEPLOY_ERROR("Inference: input names count not match !"); + response->set_status(-1); + response->set_info("Inference: input names count not match !"); + return Status::OK; + } + + // input + for (size_t i = 0; i < input_names.size(); ++i) { + auto tensor = request->data(i); + auto shape = tensor.shape(); + inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)tensor.data().c_str()); + extractor.input(input_names[i], inputs[i]); + } + + // output + auto ts = std::chrono::high_resolution_clock::now(); + const std::vector& output_names = net_.output_names(); + std::vector outputs(output_names.size()); + for (size_t i = 0; i < output_names.size(); i++) { + extractor.extract(output_names[i], outputs[i]); + } + auto te = std::chrono::high_resolution_clock::now(); + auto dur = std::chrono::duration_cast(te - ts).count(); + MMDEPLOY_INFO("inference time: {} ms", dur); + + // response + for (size_t i = 0; i < output_names.size(); i++) { + Tensor* pdata = response->add_data(); + pdata->set_name(output_names[i]); + pdata->set_dtype("float32"); + + std::vector tshape; + auto shape = outputs[i].shape(); + if (shape.dims == 1) { + tshape = {shape.w}; + } else if (shape.dims == 2) { + tshape = {shape.h, shape.w}; + } else if (shape.dims == 3) { + tshape = {shape.c, shape.h, shape.w}; + } else if (shape.dims == 4) { + tshape = {shape.c, shape.d, shape.h, shape.w}; + } + for (auto d : tshape) { + pdata->add_shape(d); + } + size_t total = shape.c * shape.d * shape.h * shape.w; + auto flattened = outputs[i].reshape(total); + std::string tdata; + tdata.resize(total * sizeof(float)); + memcpy(tdata.data(), flattened.data, total * sizeof(float)); + pdata->set_data(tdata); + } + + response->set_status(0); + return Status::OK; +} \ No newline at end of file diff --git a/service/riscv/backend.h b/service/riscv/backend.h new file mode 100644 index 0000000000..19bb4546e9 --- /dev/null +++ b/service/riscv/backend.h @@ -0,0 +1,41 @@ +#ifndef SERVER_RISCV_BACKEND_H +#define SERVER_RISCV_BACKEND_H + +#include "inference.grpc.pb.h" +// It's ncnn's net.h +#include "net.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; + +using mmdeploy::Empty; +using mmdeploy::Inference; +using mmdeploy::Model; +using mmdeploy::ModelType; +using mmdeploy::Names; +using mmdeploy::Reply; +using mmdeploy::Tensor; +using mmdeploy::TensorList; + +class Net { + public: + virtual Status Init(ServerContext* context, const Model* request, Reply* response) = 0; + virtual Status OutputNames(ServerContext* context, const Empty* request, Names* response) = 0; + virtual Status Inference(ServerContext* context, const TensorList* request, Reply* response) = 0; +}; + +class NCNNNet : public Net { + public: + Status Init(ServerContext* context, const Model* request, Reply* response) override; + Status OutputNames(ServerContext* context, const Empty* request, Names* response) override; + Status Inference(ServerContext* context, const TensorList* request, Reply* response) override; + + private: + ncnn::Net net_; + std::string params_; + std::string weights_; +}; + +#endif \ No newline at end of file diff --git a/service/riscv/common.cmake b/service/riscv/common.cmake new file mode 100644 index 0000000000..20d2f0c01e --- /dev/null +++ b/service/riscv/common.cmake @@ -0,0 +1,123 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# cmake build file for C++ route_guide example. +# Assumes protobuf and gRPC have been installed using cmake. +# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build +# that automatically builds all the dependencies before building route_guide. + +cmake_minimum_required(VERSION 3.5.1) + +set (CMAKE_CXX_STANDARD 17) + +if(MSVC) + add_definitions(-D_WIN32_WINNT=0x600) +endif() + +find_package(Threads REQUIRED) + +if(GRPC_AS_SUBMODULE) + # One way to build a projects that uses gRPC is to just include the + # entire gRPC project tree via "add_subdirectory". + # This approach is very simple to use, but the are some potential + # disadvantages: + # * it includes gRPC's CMakeLists.txt directly into your build script + # without and that can make gRPC's internal setting interfere with your + # own build. + # * depending on what's installed on your system, the contents of submodules + # in gRPC's third_party/* might need to be available (and there might be + # additional prerequisites required to build them). Consider using + # the gRPC_*_PROVIDER options to fine-tune the expected behavior. + # + # A more robust approach to add dependency on gRPC is using + # cmake's ExternalProject_Add (see cmake_externalproject/CMakeLists.txt). + + # Include the gRPC's cmake build (normally grpc source code would live + # in a git submodule called "third_party/grpc", but this example lives in + # the same repository as gRPC sources, so we just look a few directories up) + add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL) + message(STATUS "Using gRPC via add_subdirectory.") + + # After using add_subdirectory, we can now use the grpc targets directly from + # this build. + set(_PROTOBUF_LIBPROTOBUF libprotobuf) + set(_REFLECTION grpc++_reflection) + if(CMAKE_CROSSCOMPILING) + find_program(_PROTOBUF_PROTOC protoc) + else() + set(_PROTOBUF_PROTOC $) + endif() + set(_GRPC_GRPCPP grpc++) + if(CMAKE_CROSSCOMPILING) + find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) + else() + set(_GRPC_CPP_PLUGIN_EXECUTABLE $) + endif() +elseif(GRPC_FETCHCONTENT) + # Another way is to use CMake's FetchContent module to clone gRPC at + # configure time. This makes gRPC's source code available to your project, + # similar to a git submodule. + message(STATUS "Using gRPC via add_subdirectory (FetchContent).") + include(FetchContent) + FetchContent_Declare( + grpc + GIT_REPOSITORY https://github.com/grpc/grpc.git + # when using gRPC, you will actually set this to an existing tag, such as + # v1.25.0, v1.26.0 etc.. + # For the purpose of testing, we override the tag used to the commit + # that's currently under test. + GIT_TAG vGRPC_TAG_VERSION_OF_YOUR_CHOICE) + FetchContent_MakeAvailable(grpc) + + # Since FetchContent uses add_subdirectory under the hood, we can use + # the grpc targets directly from this build. + set(_PROTOBUF_LIBPROTOBUF libprotobuf) + set(_REFLECTION grpc++_reflection) + set(_PROTOBUF_PROTOC $) + set(_GRPC_GRPCPP grpc++) + if(CMAKE_CROSSCOMPILING) + find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) + else() + set(_GRPC_CPP_PLUGIN_EXECUTABLE $) + endif() +else() + # This branch assumes that gRPC and all its dependencies are already installed + # on this system, so they can be located by find_package(). + + # Find Protobuf installation + # Looks for protobuf-config.cmake file installed by Protobuf's cmake installation. + set(protobuf_MODULE_COMPATIBLE TRUE) + find_package(Protobuf CONFIG REQUIRED) + message(STATUS "Using protobuf ${Protobuf_VERSION}") + + set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) + set(_REFLECTION gRPC::grpc++_reflection) + if(CMAKE_CROSSCOMPILING) + find_program(_PROTOBUF_PROTOC protoc) + else() + set(_PROTOBUF_PROTOC $) + endif() + + # Find gRPC installation + # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. + find_package(gRPC CONFIG REQUIRED) + message(STATUS "Using gRPC ${gRPC_VERSION}") + + set(_GRPC_GRPCPP gRPC::grpc++) + if(CMAKE_CROSSCOMPILING) + find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) + else() + set(_GRPC_CPP_PLUGIN_EXECUTABLE $) + endif() +endif() diff --git a/service/riscv/inference.proto b/service/riscv/inference.proto new file mode 100644 index 0000000000..6fd77a05a7 --- /dev/null +++ b/service/riscv/inference.proto @@ -0,0 +1,89 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "mmdeploy.riscv"; +option java_outer_classname = "RISCVWrapper"; +option objc_class_prefix = "RISCV"; + +package mmdeploy; + +// The inference service definition. +service Inference { + + // Init Model with model file + rpc Init(Model) returns (Reply) {} + + // Get output names + rpc OutputNames(Empty) returns (Names) {} + + // Inference with inputs + rpc Inference(TensorList) returns (Reply) {} + + // Destroy handle + rpc Destroy(Empty) returns (Reply) {} +} + +message PPLModel { + // name + optional string name = 1; + + // weights + bytes weights = 2; +} + +message NCNNModel { + // name + optional string name = 1; + + // params + bytes params = 2; + + // weights + bytes weights = 3; +} + +enum ModelType { + UNKOWN = 0; + NCNN = 1; + PPLNN = 2; +} + +message Model { + + ModelType type = 1; + + optional NCNNModel ncnn = 2; + + optional PPLModel ppl = 3; +} + +// https://stackoverflow.com/questions/31768665/can-i-define-a-grpc-call-with-a-null-request-or-response +message Empty {} + +message Tensor { + // name + string name = 1; + + // datatype + optional string dtype = 2; + + // data + bytes data = 3; + + // shape + repeated int32 shape = 4; +} + +message TensorList { + repeated Tensor data = 1; +} + +message Reply { + int32 status = 1; + string info = 2; + repeated Tensor data = 3; +} + +message Names { + repeated string names = 1; +} diff --git a/service/riscv/inference_server.cpp b/service/riscv/inference_server.cpp new file mode 100644 index 0000000000..29c3a45c28 --- /dev/null +++ b/service/riscv/inference_server.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../snpe/server/text_table.h" +#include "server_impl.h" + +void PrintIP() { + struct ifaddrs* ifAddrStruct = NULL; + void* tmpAddrPtr = NULL; + + int retval = getifaddrs(&ifAddrStruct); + if (retval == -1) { + return; + } + + helper::TextTable table("Device"); + table.padding(1); + table.add("port").add("ip").eor(); + while (ifAddrStruct != nullptr) { + if (ifAddrStruct->ifa_addr == nullptr) { + break; + } + + if (ifAddrStruct->ifa_addr->sa_family == AF_INET) { + tmpAddrPtr = &((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + table.add(std::string(ifAddrStruct->ifa_name)).add(std::string(addressBuffer)).eor(); + } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { + tmpAddrPtr = &((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr; + char addressBuffer[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); + table.add(std::string(ifAddrStruct->ifa_name)).add(std::string(addressBuffer)).eor(); + } + ifAddrStruct = ifAddrStruct->ifa_next; + } + std::cout << table << std::endl << std::endl; +} + +void RunServer(int port = 60000) { + // listen IPv4 and IPv6 + char server_address[64] = {0}; + sprintf(server_address, "[::]:%d", port); + InferenceServiceImpl service; + + grpc::EnableDefaultHealthCheckService(true); + grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + ServerBuilder builder; + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + + // Max 128MB + builder.SetMaxMessageSize(2 << 29); + builder.SetMaxSendMessageSize(2 << 29); + + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr server(builder.BuildAndStart()); + fprintf(stdout, "Server listening on %s\n", server_address); + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +int main(int argc, char** argv) { + int port = 60000; + if (argc > 1) { + port = std::stoi(argv[1]); + } + + if (port <= 9999) { + fprintf(stdout, "Usage: %s [port]\n", argv[0]); + return 0; + } + PrintIP(); + RunServer(port); + + return 0; +} diff --git a/service/riscv/server_impl.cpp b/service/riscv/server_impl.cpp new file mode 100644 index 0000000000..ccfc759970 --- /dev/null +++ b/service/riscv/server_impl.cpp @@ -0,0 +1,38 @@ +// Copyright (c) OpenMMLab. All rights reserved. + +#include "server_impl.h" + +Status InferenceServiceImpl::Init(ServerContext* context, const Model* request, Reply* response) { + if (net_ != nullptr) { + net_.reset(); + } + + if (request->type() == ModelType::NCNN) { + net_ = std::make_unique(); + return net_->Init(context, request, response); + } else if (request->type() == ModelType::PPLNN) { + response->set_info("not implemented"); + response->set_status(-1); + } else { + response->set_info("unsupported model type"); + response->set_status(-1); + } + + return Status::OK; +} + +Status InferenceServiceImpl::OutputNames(ServerContext* context, const Empty* request, + Names* response) { + return net_->OutputNames(context, request, response); +} + +Status InferenceServiceImpl::Inference(ServerContext* context, const TensorList* request, + Reply* response) { + return net_->Inference(context, request, response); +} +Status InferenceServiceImpl::Destroy(ServerContext* context, const Empty* request, + Reply* response) { + net_.reset(); + response->set_status(0); + return Status::OK; +} \ No newline at end of file diff --git a/service/riscv/server_impl.h b/service/riscv/server_impl.h new file mode 100644 index 0000000000..c61c3f0d9d --- /dev/null +++ b/service/riscv/server_impl.h @@ -0,0 +1,42 @@ +// Copyright (c) OpenMMLab. All rights reserved. + +#ifndef SERVICE_RISCV_IMPL_H +#define SERVICE_RISCV_IMPL_H + +#include +#include +#include + +#include + +#include "backend.h" +#include "inference.grpc.pb.h" + +// using grpc::Server; +// using grpc::ServerBuilder; +// using grpc::ServerContext; +// using grpc::Status; + +// using mmdeploy::Empty; +// using mmdeploy::Inference; +// using mmdeploy::Model; +// using mmdeploy::ModelType; +// using mmdeploy::Reply; +// using mmdeploy::Tensor; +// using mmdeploy::TensorList; + +class InferenceServiceImpl final : public Inference::Service { + // Init Model with model file + Status Init(ServerContext* context, const Model* request, Reply* response) override; + // Get output names + Status OutputNames(ServerContext* context, const Empty* request, Names* response) override; + // Inference with inputs + Status Inference(ServerContext* context, const TensorList* request, Reply* response) override; + // Destroy handle + Status Destroy(ServerContext* context, const Empty* request, Reply* response) override; + + private: + std::unique_ptr net_; +}; + +#endif \ No newline at end of file From 062746d31b48064b1ccfb0f50d218c5ef38c2788 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 16 Aug 2022 16:24:03 +0800 Subject: [PATCH 04/28] update _build_wrapper for ncnn --- mmdeploy/codebase/base/backend_model.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mmdeploy/codebase/base/backend_model.py b/mmdeploy/codebase/base/backend_model.py index 3a3ae3fafc..c4459d05a2 100644 --- a/mmdeploy/codebase/base/backend_model.py +++ b/mmdeploy/codebase/base/backend_model.py @@ -82,11 +82,15 @@ def _build_wrapper(backend: Backend, use_vulkan = backend_config.get('use_vulkan', False) else: use_vulkan = False + uri = None + if 'uri' in kwargs: + uri = kwargs['uri'] return NCNNWrapper( param_file=backend_files[0], bin_file=backend_files[1], output_names=output_names, - use_vulkan=use_vulkan) + use_vulkan=use_vulkan, + uri=uri) elif backend == Backend.OPENVINO: from mmdeploy.backend.openvino import OpenVINOWrapper return OpenVINOWrapper( From 7b96794b0d7c7e335f1c59b488cbf5a29ed339f7 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 16 Aug 2022 16:24:31 +0800 Subject: [PATCH 05/28] fix build --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52ae2c4074..b1028ca0c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ if (MMDEPLOY_BUILD_SDK) if (MMDEPLOY_BUILD_RISCV_SERVER) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - add_subdirectory(service/riscv/server) + add_subdirectory(service/riscv) endif () if (MMDEPLOY_BUILD_TEST) From 8b5435b85b4657dcc801558ba666dbca2882956b Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 16 Aug 2022 16:37:40 +0800 Subject: [PATCH 06/28] fix lint --- mmdeploy/backend/ncnn/client/inference_pb2.py | 10 ++- .../backend/ncnn/client/inference_pb2_grpc.py | 83 ++++++++++--------- mmdeploy/backend/ncnn/wrapper.py | 26 +++--- mmdeploy/utils/retry_interceptor.py | 6 +- service/riscv/CMakeLists.txt | 7 +- service/riscv/backend.cpp | 8 +- service/riscv/backend.h | 2 +- service/riscv/inference.proto | 2 +- service/riscv/server_impl.cpp | 2 +- service/riscv/server_impl.h | 2 +- 10 files changed, 75 insertions(+), 73 deletions(-) diff --git a/mmdeploy/backend/ncnn/client/inference_pb2.py b/mmdeploy/backend/ncnn/client/inference_pb2.py index 91657aad12..a9f0716a0c 100644 --- a/mmdeploy/backend/ncnn/client/inference_pb2.py +++ b/mmdeploy/backend/ncnn/client/inference_pb2.py @@ -1,17 +1,19 @@ -# -*- coding: utf-8 -*- +# Copyright (c) OpenMMLab. All rights reserved. # Generated by the protocol buffer compiler. DO NOT EDIT! # source: inference.proto """Generated protocol buffer code.""" -from google.protobuf.internal import builder as _builder from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder + # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0finference.proto\x12\x08mmdeploy\"7\n\x08PPLModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07weights\x18\x02 \x01(\x0c\x42\x07\n\x05_name\"H\n\tNCNNModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0e\n\x06params\x18\x02 \x01(\x0c\x12\x0f\n\x07weights\x18\x03 \x01(\x0c\x42\x07\n\x05_name\"\x89\x01\n\x05Model\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.mmdeploy.ModelType\x12&\n\x04ncnn\x18\x02 \x01(\x0b\x32\x13.mmdeploy.NCNNModelH\x00\x88\x01\x01\x12$\n\x03ppl\x18\x03 \x01(\x0b\x32\x12.mmdeploy.PPLModelH\x01\x88\x01\x01\x42\x07\n\x05_ncnnB\x06\n\x04_ppl\"\x07\n\x05\x45mpty\"Q\n\x06Tensor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\x05\x64type\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\r\n\x05shape\x18\x04 \x03(\x05\x42\x08\n\x06_dtype\",\n\nTensorList\x12\x1e\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x10.mmdeploy.Tensor\"E\n\x05Reply\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0c\n\x04info\x18\x02 \x01(\t\x12\x1e\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\x10.mmdeploy.Tensor\"\x16\n\x05Names\x12\r\n\x05names\x18\x01 \x03(\t*,\n\tModelType\x12\n\n\x06UNKOWN\x10\x00\x12\x08\n\x04NCNN\x10\x01\x12\t\n\x05PPLNN\x10\x02\x32\xcf\x01\n\tInference\x12*\n\x04Init\x12\x0f.mmdeploy.Model\x1a\x0f.mmdeploy.Reply\"\x00\x12\x31\n\x0bOutputNames\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Names\"\x00\x12\x34\n\tInference\x12\x14.mmdeploy.TensorList\x1a\x0f.mmdeploy.Reply\"\x00\x12-\n\x07\x44\x65stroy\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Reply\"\x00\x42(\n\x0emmdeploy.riscvB\x0cRISCVWrapperP\x01\xa2\x02\x05RISCVb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( + b'\n\x0finference.proto\x12\x08mmdeploy\"7\n\x08PPLModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07weights\x18\x02 \x01(\x0c\x42\x07\n\x05_name\"H\n\tNCNNModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0e\n\x06params\x18\x02 \x01(\x0c\x12\x0f\n\x07weights\x18\x03 \x01(\x0c\x42\x07\n\x05_name\"\x89\x01\n\x05Model\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.mmdeploy.ModelType\x12&\n\x04ncnn\x18\x02 \x01(\x0b\x32\x13.mmdeploy.NCNNModelH\x00\x88\x01\x01\x12$\n\x03ppl\x18\x03 \x01(\x0b\x32\x12.mmdeploy.PPLModelH\x01\x88\x01\x01\x42\x07\n\x05_ncnnB\x06\n\x04_ppl\"\x07\n\x05\x45mpty\"Q\n\x06Tensor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\x05\x64type\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\r\n\x05shape\x18\x04 \x03(\x05\x42\x08\n\x06_dtype\",\n\nTensorList\x12\x1e\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x10.mmdeploy.Tensor\"E\n\x05Reply\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0c\n\x04info\x18\x02 \x01(\t\x12\x1e\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\x10.mmdeploy.Tensor\"\x16\n\x05Names\x12\r\n\x05names\x18\x01 \x03(\t*,\n\tModelType\x12\n\n\x06UNKOWN\x10\x00\x12\x08\n\x04NCNN\x10\x01\x12\t\n\x05PPLNN\x10\x02\x32\xcf\x01\n\tInference\x12*\n\x04Init\x12\x0f.mmdeploy.Model\x1a\x0f.mmdeploy.Reply\"\x00\x12\x31\n\x0bOutputNames\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Names\"\x00\x12\x34\n\tInference\x12\x14.mmdeploy.TensorList\x1a\x0f.mmdeploy.Reply\"\x00\x12-\n\x07\x44\x65stroy\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Reply\"\x00\x42(\n\x0emmdeploy.riscvB\x0cRISCVWrapperP\x01\xa2\x02\x05RISCVb\x06proto3' +) _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'inference_pb2', globals()) diff --git a/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py b/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py index 1983b07e52..e396f85bf5 100644 --- a/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py +++ b/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py @@ -1,3 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc @@ -6,8 +7,7 @@ class InferenceStub(object): - """The inference service definition. - """ + """The inference service definition.""" def __init__(self, channel): """Constructor. @@ -38,33 +38,28 @@ def __init__(self, channel): class InferenceServicer(object): - """The inference service definition. - """ + """The inference service definition.""" def Init(self, request, context): - """Init Model with model file - """ + """Init Model with model file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def OutputNames(self, request, context): - """Get output names - """ + """Get output names.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Inference(self, request, context): - """Inference with inputs - """ + """Inference with inputs.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def Destroy(self, request, context): - """Destroy handle - """ + """Destroy handle.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') @@ -72,22 +67,26 @@ def Destroy(self, request, context): def add_InferenceServicer_to_server(servicer, server): rpc_method_handlers = { - 'Init': grpc.unary_unary_rpc_method_handler( + 'Init': + grpc.unary_unary_rpc_method_handler( servicer.Init, request_deserializer=inference__pb2.Model.FromString, response_serializer=inference__pb2.Reply.SerializeToString, ), - 'OutputNames': grpc.unary_unary_rpc_method_handler( + 'OutputNames': + grpc.unary_unary_rpc_method_handler( servicer.OutputNames, request_deserializer=inference__pb2.Empty.FromString, response_serializer=inference__pb2.Names.SerializeToString, ), - 'Inference': grpc.unary_unary_rpc_method_handler( + 'Inference': + grpc.unary_unary_rpc_method_handler( servicer.Inference, request_deserializer=inference__pb2.TensorList.FromString, response_serializer=inference__pb2.Reply.SerializeToString, ), - 'Destroy': grpc.unary_unary_rpc_method_handler( + 'Destroy': + grpc.unary_unary_rpc_method_handler( servicer.Destroy, request_deserializer=inference__pb2.Empty.FromString, response_serializer=inference__pb2.Reply.SerializeToString, @@ -95,14 +94,14 @@ def add_InferenceServicer_to_server(servicer, server): } generic_handler = grpc.method_handlers_generic_handler( 'mmdeploy.Inference', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) + server.add_generic_rpc_handlers((generic_handler, )) + - # This class is part of an EXPERIMENTAL API. +# This class is part of an EXPERIMENTAL API. class Inference(object): - """The inference service definition. - """ + """The inference service definition.""" @staticmethod def Init(request, @@ -115,11 +114,12 @@ def Init(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Init', - inference__pb2.Model.SerializeToString, - inference__pb2.Reply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + return grpc.experimental.unary_unary( + request, target, '/mmdeploy.Inference/Init', + inference__pb2.Model.SerializeToString, + inference__pb2.Reply.FromString, options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, + metadata) @staticmethod def OutputNames(request, @@ -132,11 +132,12 @@ def OutputNames(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/OutputNames', - inference__pb2.Empty.SerializeToString, - inference__pb2.Names.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + return grpc.experimental.unary_unary( + request, target, '/mmdeploy.Inference/OutputNames', + inference__pb2.Empty.SerializeToString, + inference__pb2.Names.FromString, options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, + metadata) @staticmethod def Inference(request, @@ -149,11 +150,12 @@ def Inference(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Inference', - inference__pb2.TensorList.SerializeToString, - inference__pb2.Reply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + return grpc.experimental.unary_unary( + request, target, '/mmdeploy.Inference/Inference', + inference__pb2.TensorList.SerializeToString, + inference__pb2.Reply.FromString, options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, + metadata) @staticmethod def Destroy(request, @@ -166,8 +168,9 @@ def Destroy(request, wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/mmdeploy.Inference/Destroy', - inference__pb2.Empty.SerializeToString, - inference__pb2.Reply.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + return grpc.experimental.unary_unary( + request, target, '/mmdeploy.Inference/Destroy', + inference__pb2.Empty.SerializeToString, + inference__pb2.Reply.FromString, options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, + metadata) diff --git a/mmdeploy/backend/ncnn/wrapper.py b/mmdeploy/backend/ncnn/wrapper.py index cf91778108..ecbb6b4d2d 100644 --- a/mmdeploy/backend/ncnn/wrapper.py +++ b/mmdeploy/backend/ncnn/wrapper.py @@ -12,7 +12,7 @@ class NCNNLocal: - """ncnn local wrapper class for inference + """ncnn local wrapper class for inference. Args: param_file (str): Path of a parameter file. @@ -43,9 +43,7 @@ def __init__(self, output_names = self._net.output_names() self.output_names = output_names - def forward(self, - inputs: Dict[str, torch.Tensor], - batch_id: int): + def forward(self, inputs: Dict[str, torch.Tensor], batch_id: int): # create extractor ex = self._net.create_extractor() @@ -85,7 +83,7 @@ def __ncnn_execute(self, extractor: ncnn.Extractor, class NCNNRemote: - """ncnn remote wrapper class for inference + """ncnn remote wrapper class for inference. Args: param_file (str): Path of a parameter file. @@ -102,10 +100,11 @@ def __init__(self, output_names: Optional[Sequence[str]] = None, uri=None, **kwargs): - from mmdeploy.utils.retry_interceptor import RetryOnRpcErrorClientInterceptor, ExponentialBackoff import grpc - from .client import inference_pb2_grpc - from .client import inference_pb2 + + from mmdeploy.utils.retry_interceptor import ( + ExponentialBackoff, RetryOnRpcErrorClientInterceptor) + from .client import inference_pb2, inference_pb2_grpc self._Tensor = inference_pb2.Tensor self._TensorList = inference_pb2.TensorList @@ -141,9 +140,7 @@ def __init__(self, output_names = output.names self.output_names = output_names - def forward(self, - inputs: Dict[str, torch.Tensor], - batch_id: int): + def forward(self, inputs: Dict[str, torch.Tensor], batch_id: int): ncnn_inputs = [] for name, input_tensor in inputs.items(): data = input_tensor[batch_id].contiguous() @@ -159,8 +156,7 @@ def forward(self, tensorList = self._TensorList(data=ncnn_inputs) return self.__ncnn_execute(tensorList) - def __ncnn_execute(self, - tensorList): + def __ncnn_execute(self, tensorList): resp = self.stub.Inference(tensorList) result = dict() if resp.status == 0: @@ -206,8 +202,8 @@ def __init__(self, uri=None, **kwargs): if uri is None: - self._net = NCNNLocal( - param_file, bin_file, output_names, use_vulkan) + self._net = NCNNLocal(param_file, bin_file, output_names, + use_vulkan) else: self._net = NCNNRemote(param_file, bin_file, output_names, uri) diff --git a/mmdeploy/utils/retry_interceptor.py b/mmdeploy/utils/retry_interceptor.py index bec6b42154..79d56213ba 100644 --- a/mmdeploy/utils/retry_interceptor.py +++ b/mmdeploy/utils/retry_interceptor.py @@ -1,11 +1,13 @@ # Copyright (c) OpenMMLab. All rights reserved. import abc +import time from random import randint +from typing import Optional, Tuple + import grpc -import time + from mmdeploy.utils import get_root_logger -from typing import Optional, Tuple class SleepingPolicy(abc.ABC): diff --git a/service/riscv/CMakeLists.txt b/service/riscv/CMakeLists.txt index 32443dc410..f10f25ef71 100644 --- a/service/riscv/CMakeLists.txt +++ b/service/riscv/CMakeLists.txt @@ -29,7 +29,7 @@ find_package(ncnn REQUIRED) # Include generated *.pb.h files include_directories("${CMAKE_CURRENT_BINARY_DIR}") -add_executable(inference_server +add_executable(inference_server server_impl.cpp inference_server.cpp backend.cpp @@ -47,11 +47,10 @@ target_link_libraries(inference_server ${_PROTOBUF_LIBPROTOBUF} -static) -set_target_properties(inference_server - PROPERTIES RUNTIME_OUTPUT_DIRECTORY +set_target_properties(inference_server + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/riscv-server) # generate pb file # GRPC_BIN_PATH=/opt/grpc/build/install/bin # ${GRPC_BIN_PATH}/protoc -I . --python_out client --grpc_out client inference.proto --plugin=protoc-gen-grpc=${GRPC_BIN_PATH}/grpc_python_plugin - diff --git a/service/riscv/backend.cpp b/service/riscv/backend.cpp index 004a1695bf..0f10bca46a 100644 --- a/service/riscv/backend.cpp +++ b/service/riscv/backend.cpp @@ -51,14 +51,14 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep } // output - auto ts = std::chrono::high_resolution_clock::now(); + auto t0 = std::chrono::high_resolution_clock::now(); const std::vector& output_names = net_.output_names(); std::vector outputs(output_names.size()); for (size_t i = 0; i < output_names.size(); i++) { extractor.extract(output_names[i], outputs[i]); } - auto te = std::chrono::high_resolution_clock::now(); - auto dur = std::chrono::duration_cast(te - ts).count(); + auto t1 = std::chrono::high_resolution_clock::now(); + auto dur = std::chrono::duration_cast(t1 - t0).count(); MMDEPLOY_INFO("inference time: {} ms", dur); // response @@ -91,4 +91,4 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep response->set_status(0); return Status::OK; -} \ No newline at end of file +} diff --git a/service/riscv/backend.h b/service/riscv/backend.h index 19bb4546e9..f4b8408225 100644 --- a/service/riscv/backend.h +++ b/service/riscv/backend.h @@ -38,4 +38,4 @@ class NCNNNet : public Net { std::string weights_; }; -#endif \ No newline at end of file +#endif diff --git a/service/riscv/inference.proto b/service/riscv/inference.proto index 6fd77a05a7..b5d75b00c9 100644 --- a/service/riscv/inference.proto +++ b/service/riscv/inference.proto @@ -34,7 +34,7 @@ message PPLModel { message NCNNModel { // name optional string name = 1; - + // params bytes params = 2; diff --git a/service/riscv/server_impl.cpp b/service/riscv/server_impl.cpp index ccfc759970..4c3aeecbb7 100644 --- a/service/riscv/server_impl.cpp +++ b/service/riscv/server_impl.cpp @@ -35,4 +35,4 @@ Status InferenceServiceImpl::Destroy(ServerContext* context, const Empty* reques net_.reset(); response->set_status(0); return Status::OK; -} \ No newline at end of file +} diff --git a/service/riscv/server_impl.h b/service/riscv/server_impl.h index c61c3f0d9d..5ae10f73f4 100644 --- a/service/riscv/server_impl.h +++ b/service/riscv/server_impl.h @@ -39,4 +39,4 @@ class InferenceServiceImpl final : public Inference::Service { std::unique_ptr net_; }; -#endif \ No newline at end of file +#endif From 0046e6a4374af0ed72cf7a49aa926431ade0abc3 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 16 Aug 2022 18:50:39 +0800 Subject: [PATCH 07/28] update default uri --- tools/test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/test.py b/tools/test.py index d3957a19d4..07783eaaeb 100644 --- a/tools/test.py +++ b/tools/test.py @@ -81,8 +81,6 @@ def parse_args(): 'in data config.') parser.add_argument( '--uri', - action='store_true', - default='192.168.1.1:60000', help='Remote ipv4:port or ipv6:port for inference on edge device.') args = parser.parse_args() From 40ce5dbc411eb3b4276f54af68bd7dcc6a4293dc Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 17 Aug 2022 15:43:00 +0800 Subject: [PATCH 08/28] update file structure & add cn doc --- CMakeLists.txt | 2 +- docs/zh_cn/01-how-to-build/riscv.md | 113 ++++++++++++++++++ mmdeploy/backend/ncnn/wrapper.py | 3 +- .../riscv}/client/inference_pb2.py | 0 .../riscv}/client/inference_pb2_grpc.py | 3 +- service/riscv/{ => server}/CMakeLists.txt | 4 +- service/riscv/{ => server}/backend.cpp | 13 +- service/riscv/{ => server}/backend.h | 0 service/riscv/{ => server}/common.cmake | 0 .../riscv/{ => server}/inference_server.cpp | 2 +- service/riscv/{ => server}/server_impl.cpp | 0 service/riscv/{ => server}/server_impl.h | 14 --- tools/deploy.py | 2 +- 13 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 docs/zh_cn/01-how-to-build/riscv.md rename {mmdeploy/backend/ncnn => service/riscv}/client/inference_pb2.py (100%) rename {mmdeploy/backend/ncnn => service/riscv}/client/inference_pb2_grpc.py (99%) rename service/riscv/{ => server}/CMakeLists.txt (94%) rename service/riscv/{ => server}/backend.cpp (86%) rename service/riscv/{ => server}/backend.h (100%) rename service/riscv/{ => server}/common.cmake (100%) rename service/riscv/{ => server}/inference_server.cpp (98%) rename service/riscv/{ => server}/server_impl.cpp (100%) rename service/riscv/{ => server}/server_impl.h (72%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1028ca0c6..52ae2c4074 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ if (MMDEPLOY_BUILD_SDK) if (MMDEPLOY_BUILD_RISCV_SERVER) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - add_subdirectory(service/riscv) + add_subdirectory(service/riscv/server) endif () if (MMDEPLOY_BUILD_TEST) diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md new file mode 100644 index 0000000000..fa8c8ca623 --- /dev/null +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -0,0 +1,113 @@ +# 支持 RISCV + +## 一、运行推理服务 + +下载预编译 riscv 推理服务包 + +```bash +root@RVBoards:~$ wget https://github.com/irexyc/mmdeploy-riscv-server/raw/main/riscv-ncnn_20220729-inference_server.tar.gz + +# 解压运行 +root@RVBoards:~$ tar xf riscv-ncnn_20220729-inference_server.tar.gz +root@RVBoards:~$ cd riscv-server +root@RVBoards:~$ ./inference_server 60000 +... + Server listening on [::]:60000 +``` + +此时推理服务应打印设备所有 ipv6 和 ipv4 地址,并监听端口。 + +## 二、安装 mmdeploy + +这里需要使用 mmdeploy_onnx2ncnn 进行模型转换,故需要安装 ncnn 推理引擎,可参考[BUILD 文档](./linux-x86_64.md) 进行安装, + +## 三、测试模型 + +以 Resnet-18 为例。先参照[文档](https://github.com/open-mmlab/mmclassification)安装 mmcls,然后使用 `tools/deploy.py` 转换模型。 + +```bash +$ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py +$ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + +export PYTHONPATH=${PWD}/service/riscv/client:${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} +export PATH=${pwd}/build/bin:${PATH} + +# 模型转换 +$ cd /path/to/mmdeploy +$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --uri 192.168.1.1:60000 --dump-info + +# 精度测试 +$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall --uri 192.168.1.1:60000 +``` + +注意需要 `--uri` 指明 riscv 推理服务的 ip 和端口号,可以使用 ipv4 和 ipv6 地址。 + +## 四、编译 SDK + +### 1. 下载交叉编译工具链,设置环境变量 + +```bash +# 下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0-20220715.tar.gz +# https://occ.t-head.cn/community/download?id=4073475960903634944 +$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0-20220715.tar.gz +$ export RISCV_ROOT_DIR=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` +``` + +### 2. 编译 ncnn & opencv + +```bash +# ncnn +# 可参考 https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-allwinner-d1 + +# opencv +$ git clone https://github.com/opencv/opencv.git +$ mkdir build && cd build +$ cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_INSTALL_PREFIX=install \ + -DBUILD_PERF_TESTS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_TESTS=OFF \ + -DCMAKE_BUILD_TYPE=Release +$ make -j && make install +``` + +### 3. 编译 mmdeploy SDK & demo + +```bash +$ cd /path/to/mmdeploy +$ mkdir build && cd build +$ cmake .. \ + -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DMMDEPLOY_BUILD_SDK=ON \ + -DMMDEPLOY_SHARED_LIBS=OFF \ + -DMMDEPLOY_BUILD_EXAMPLES=ON \ + -DMMDEPLOY_TARGET_DEVICES="cpu" \ + -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ + -Dncnn_DIR=/home/cx/ws/ncnn/build-c906/install/lib/cmake/ncnn/ \ + -DMMDEPLOY_CODEBASES=all \ + -DOpenCV_DIR=/home/cx/ws/opencv-4.6.0/build/install/lib/cmake/opencv4 + +$ make && make install +$ tree -L 1 bin/ +. +├── image_classification +├── image_restorer +├── image_segmentation +├── object_detection +├── ocr +├── pose_detection +└── rotated_object_detection +``` + +### 4. 运行 demo + +先确认测试模型用了 `--dump-info`,这样 `resnet18` 目录才有 `pipeline.json` 等 SDK 所需文件。 + +把 dump 好的模型目录、可执行文件拷贝到设备中 + +```bash +./image_classification cpu ./resnet18 tiger.jpeg +``` diff --git a/mmdeploy/backend/ncnn/wrapper.py b/mmdeploy/backend/ncnn/wrapper.py index ecbb6b4d2d..1dba4ef181 100644 --- a/mmdeploy/backend/ncnn/wrapper.py +++ b/mmdeploy/backend/ncnn/wrapper.py @@ -101,10 +101,11 @@ def __init__(self, uri=None, **kwargs): import grpc + import inference_pb2 + import inference_pb2_grpc from mmdeploy.utils.retry_interceptor import ( ExponentialBackoff, RetryOnRpcErrorClientInterceptor) - from .client import inference_pb2, inference_pb2_grpc self._Tensor = inference_pb2.Tensor self._TensorList = inference_pb2.TensorList diff --git a/mmdeploy/backend/ncnn/client/inference_pb2.py b/service/riscv/client/inference_pb2.py similarity index 100% rename from mmdeploy/backend/ncnn/client/inference_pb2.py rename to service/riscv/client/inference_pb2.py diff --git a/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py b/service/riscv/client/inference_pb2_grpc.py similarity index 99% rename from mmdeploy/backend/ncnn/client/inference_pb2_grpc.py rename to service/riscv/client/inference_pb2_grpc.py index e396f85bf5..9c810fec02 100644 --- a/mmdeploy/backend/ncnn/client/inference_pb2_grpc.py +++ b/service/riscv/client/inference_pb2_grpc.py @@ -2,8 +2,7 @@ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! """Client and server classes corresponding to protobuf-defined services.""" import grpc - -from . import inference_pb2 as inference__pb2 +import inference_pb2 as inference__pb2 class InferenceStub(object): diff --git a/service/riscv/CMakeLists.txt b/service/riscv/server/CMakeLists.txt similarity index 94% rename from service/riscv/CMakeLists.txt rename to service/riscv/server/CMakeLists.txt index f10f25ef71..b079e5105f 100644 --- a/service/riscv/CMakeLists.txt +++ b/service/riscv/server/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.14) project(RISCVServer C CXX) include(./common.cmake) -include(../../cmake/MMDeploy.cmake) +include(../../../cmake/MMDeploy.cmake) # Proto file -get_filename_component(rv_proto "inference.proto" ABSOLUTE) +get_filename_component(rv_proto "../inference.proto" ABSOLUTE) get_filename_component(rv_proto_path "${rv_proto}" PATH) # Generated sources diff --git a/service/riscv/backend.cpp b/service/riscv/server/backend.cpp similarity index 86% rename from service/riscv/backend.cpp rename to service/riscv/server/backend.cpp index 0f10bca46a..3561928c93 100644 --- a/service/riscv/backend.cpp +++ b/service/riscv/server/backend.cpp @@ -9,9 +9,9 @@ Status NCNNNet::Init(ServerContext* context, const Model* request, Reply* response) { MMDEPLOY_INFO("Init ncnn net ..."); - net_.opt.use_fp16_packed = true; - net_.opt.use_fp16_storage = true; - net_.opt.use_fp16_arithmetic = true; + net_.opt.use_fp16_packed = false; + net_.opt.use_fp16_storage = false; + net_.opt.use_fp16_arithmetic = false; register_mmdeploy_custom_layers(net_); // copy params & weights params_ = request->ncnn().params(); @@ -34,6 +34,7 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep auto extractor = net_.create_extractor(); const std::vector& input_names = net_.input_names(); + std::vector> input_data(input_names.size()); std::vector inputs(input_names.size()); if (input_names.size() != request->data_size()) { MMDEPLOY_ERROR("Inference: input names count not match !"); @@ -46,7 +47,11 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep for (size_t i = 0; i < input_names.size(); ++i) { auto tensor = request->data(i); auto shape = tensor.shape(); - inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)tensor.data().c_str()); + size_t total = shape[2] * shape[1] * shape[0]; + std::vector tmp(total); + memcpy(tmp.data(), tensor.data().data(), sizeof(float) * total); + input_data[i] = std::move(tmp); + inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)input_data[i].data()); extractor.input(input_names[i], inputs[i]); } diff --git a/service/riscv/backend.h b/service/riscv/server/backend.h similarity index 100% rename from service/riscv/backend.h rename to service/riscv/server/backend.h diff --git a/service/riscv/common.cmake b/service/riscv/server/common.cmake similarity index 100% rename from service/riscv/common.cmake rename to service/riscv/server/common.cmake diff --git a/service/riscv/inference_server.cpp b/service/riscv/server/inference_server.cpp similarity index 98% rename from service/riscv/inference_server.cpp rename to service/riscv/server/inference_server.cpp index 29c3a45c28..fd146dd21a 100644 --- a/service/riscv/inference_server.cpp +++ b/service/riscv/server/inference_server.cpp @@ -8,7 +8,7 @@ #include #include -#include "../snpe/server/text_table.h" +#include "../../snpe/server/text_table.h" #include "server_impl.h" void PrintIP() { diff --git a/service/riscv/server_impl.cpp b/service/riscv/server/server_impl.cpp similarity index 100% rename from service/riscv/server_impl.cpp rename to service/riscv/server/server_impl.cpp diff --git a/service/riscv/server_impl.h b/service/riscv/server/server_impl.h similarity index 72% rename from service/riscv/server_impl.h rename to service/riscv/server/server_impl.h index 5ae10f73f4..fce12d9c88 100644 --- a/service/riscv/server_impl.h +++ b/service/riscv/server/server_impl.h @@ -10,20 +10,6 @@ #include #include "backend.h" -#include "inference.grpc.pb.h" - -// using grpc::Server; -// using grpc::ServerBuilder; -// using grpc::ServerContext; -// using grpc::Status; - -// using mmdeploy::Empty; -// using mmdeploy::Inference; -// using mmdeploy::Model; -// using mmdeploy::ModelType; -// using mmdeploy::Reply; -// using mmdeploy::Tensor; -// using mmdeploy::TensorList; class InferenceServiceImpl final : public Inference::Service { // Init Model with model file diff --git a/tools/deploy.py b/tools/deploy.py index 73135a6e3c..9cfa6cc54e 100644 --- a/tools/deploy.py +++ b/tools/deploy.py @@ -363,7 +363,7 @@ def main(): backend=backend, output_file=osp.join(args.work_dir, f'output_{backend.value}.jpg'), show_result=args.show) - if backend == Backend.SNPE: + if backend in [Backend.SNPE, Backend.NCNN]: extra['uri'] = args.uri create_process( From b0f3694200dbac37c1fa689b35d082c3337a4201 Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 17 Aug 2022 20:04:12 +0800 Subject: [PATCH 09/28] remove copy input data --- service/riscv/server/backend.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/service/riscv/server/backend.cpp b/service/riscv/server/backend.cpp index 3561928c93..6402823f4b 100644 --- a/service/riscv/server/backend.cpp +++ b/service/riscv/server/backend.cpp @@ -34,7 +34,6 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep auto extractor = net_.create_extractor(); const std::vector& input_names = net_.input_names(); - std::vector> input_data(input_names.size()); std::vector inputs(input_names.size()); if (input_names.size() != request->data_size()) { MMDEPLOY_ERROR("Inference: input names count not match !"); @@ -45,13 +44,10 @@ Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Rep // input for (size_t i = 0; i < input_names.size(); ++i) { - auto tensor = request->data(i); - auto shape = tensor.shape(); + auto& tensor = request->data(i); + auto& shape = tensor.shape(); size_t total = shape[2] * shape[1] * shape[0]; - std::vector tmp(total); - memcpy(tmp.data(), tensor.data().data(), sizeof(float) * total); - input_data[i] = std::move(tmp); - inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)input_data[i].data()); + inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)tensor.data().data()); extractor.input(input_names[i], inputs[i]); } From 4d2fea8a66e3ea9d628e7f7157459fe08b8a7aa0 Mon Sep 17 00:00:00 2001 From: irexyc Date: Mon, 22 Aug 2022 18:35:24 +0800 Subject: [PATCH 10/28] update docs --- docs/en/01-how-to-build/riscv.md | 94 +++++++++++++++++++++++++++++ docs/zh_cn/01-how-to-build/riscv.md | 43 ++++--------- 2 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 docs/en/01-how-to-build/riscv.md diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md new file mode 100644 index 0000000000..49334e2366 --- /dev/null +++ b/docs/en/01-how-to-build/riscv.md @@ -0,0 +1,94 @@ +# Build for RISCV + +## 一、Install MMDeploy + +We need `mmdeploy_onnx2ncnn` program to convert a ncnn model,so we have to install ncnn engine. You can refer to this [doc](./linux-x86_64.md) for installation. + +## 二、Test the model + +Take Resnet-18 as an example. First refer to [documentation to install mmcls](https://github.com/open-mmlab/mmclassification) to install mmcls. Then use `tools/deploy.py` to convert a model. + +```bash +$ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py +$ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + +export PYTHONPATH=${PWD}/service/riscv/client:${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} +export PATH=${pwd}/build/bin:${PATH} + +# Convert the model +$ cd /path/to/mmdeploy +$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --dump-info + +# accuracy test +$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall +``` + +## 三、Build SDK + +### 1. Download the compiler toolchain and set environment + +```bash +# download Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +# https://occ.t-head.cn/community/download?id=4046947553902661632 +$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +$ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` +``` + +### 2. Compile ncnn & opencv + +```bash +# ncnn +# refer to https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-allwinner-d1 + +# opencv +$ git clone https://github.com/opencv/opencv.git +$ mkdir build && cd build +$ cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_INSTALL_PREFIX=install \ + -DBUILD_PERF_TESTS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_TESTS=OFF \ + -DCMAKE_BUILD_TYPE=Release +$ make -j$(nproc) && make install +``` + +### 3. Compile mmdeploy SDK & demo + +```bash +$ cd /path/to/mmdeploy +$ mkdir build && cd build +$ cmake .. \ + -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DMMDEPLOY_BUILD_SDK=ON \ + -DMMDEPLOY_SHARED_LIBS=OFF \ + -DMMDEPLOY_BUILD_EXAMPLES=ON \ + -DMMDEPLOY_TARGET_DEVICES="cpu" \ + -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ + -Dncnn_DIR=/home/cx/ws/ncnn/build-c906/install/lib/cmake/ncnn/ \ + -DMMDEPLOY_CODEBASES=all \ + -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 + +$ make -j$(nproc) && make install +$ tree -L 1 bin/ +. +├── image_classification +├── image_restorer +├── image_segmentation +├── object_detection +├── ocr +├── pose_detection +└── rotated_object_detection +``` + +### 4. Run the demo + +First make sure that`--dump-info`is used during convert model, so that the `resnet18` directory has the files required by the SDK such as `pipeline.json`. + +Copy the model folder and executable file to the device. + +```bash +./image_classification cpu ./resnet18 tiger.jpeg +``` diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index fa8c8ca623..e7b29f5ea9 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -1,27 +1,10 @@ # 支持 RISCV -## 一、运行推理服务 - -下载预编译 riscv 推理服务包 - -```bash -root@RVBoards:~$ wget https://github.com/irexyc/mmdeploy-riscv-server/raw/main/riscv-ncnn_20220729-inference_server.tar.gz - -# 解压运行 -root@RVBoards:~$ tar xf riscv-ncnn_20220729-inference_server.tar.gz -root@RVBoards:~$ cd riscv-server -root@RVBoards:~$ ./inference_server 60000 -... - Server listening on [::]:60000 -``` - -此时推理服务应打印设备所有 ipv6 和 ipv4 地址,并监听端口。 - -## 二、安装 mmdeploy +## 一、安装 mmdeploy 这里需要使用 mmdeploy_onnx2ncnn 进行模型转换,故需要安装 ncnn 推理引擎,可参考[BUILD 文档](./linux-x86_64.md) 进行安装, -## 三、测试模型 +## 二、测试模型 以 Resnet-18 为例。先参照[文档](https://github.com/open-mmlab/mmclassification)安装 mmcls,然后使用 `tools/deploy.py` 转换模型。 @@ -34,23 +17,21 @@ export PATH=${pwd}/build/bin:${PATH} # 模型转换 $ cd /path/to/mmdeploy -$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --uri 192.168.1.1:60000 --dump-info +$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --dump-info # 精度测试 -$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall --uri 192.168.1.1:60000 +$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall ``` -注意需要 `--uri` 指明 riscv 推理服务的 ip 和端口号,可以使用 ipv4 和 ipv6 地址。 - -## 四、编译 SDK +## 三、编译 SDK ### 1. 下载交叉编译工具链,设置环境变量 ```bash -# 下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0-20220715.tar.gz -# https://occ.t-head.cn/community/download?id=4073475960903634944 -$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0-20220715.tar.gz -$ export RISCV_ROOT_DIR=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` +# 下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +# https://occ.t-head.cn/community/download?id=4046947553902661632 +$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +$ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` ``` ### 2. 编译 ncnn & opencv @@ -69,7 +50,7 @@ $ cmake .. \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_TESTS=OFF \ -DCMAKE_BUILD_TYPE=Release -$ make -j && make install +$ make -j$(nproc) && make install ``` ### 3. 编译 mmdeploy SDK & demo @@ -88,9 +69,9 @@ $ cmake .. \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ -Dncnn_DIR=/home/cx/ws/ncnn/build-c906/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ - -DOpenCV_DIR=/home/cx/ws/opencv-4.6.0/build/install/lib/cmake/opencv4 + -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 -$ make && make install +$ make -j$(nproc) && make install $ tree -L 1 bin/ . ├── image_classification From e233d7bddf1a292edf2f1467f25173ba3a52a332 Mon Sep 17 00:00:00 2001 From: irexyc Date: Mon, 22 Aug 2022 18:41:44 +0800 Subject: [PATCH 11/28] remove ncnn server --- CMakeLists.txt | 6 - mmdeploy/backend/ncnn/wrapper.py | 215 +++++---------------- mmdeploy/codebase/base/backend_model.py | 6 +- mmdeploy/utils/retry_interceptor.py | 83 -------- service/riscv/client/inference_pb2.py | 44 ----- service/riscv/client/inference_pb2_grpc.py | 175 ----------------- service/riscv/inference.proto | 89 --------- service/riscv/server/CMakeLists.txt | 56 ------ service/riscv/server/backend.cpp | 95 --------- service/riscv/server/backend.h | 41 ---- service/riscv/server/common.cmake | 123 ------------ service/riscv/server/inference_server.cpp | 90 --------- service/riscv/server/server_impl.cpp | 38 ---- service/riscv/server/server_impl.h | 28 --- tools/deploy.py | 2 +- 15 files changed, 48 insertions(+), 1043 deletions(-) delete mode 100644 mmdeploy/utils/retry_interceptor.py delete mode 100644 service/riscv/client/inference_pb2.py delete mode 100644 service/riscv/client/inference_pb2_grpc.py delete mode 100644 service/riscv/inference.proto delete mode 100644 service/riscv/server/CMakeLists.txt delete mode 100644 service/riscv/server/backend.cpp delete mode 100644 service/riscv/server/backend.h delete mode 100644 service/riscv/server/common.cmake delete mode 100644 service/riscv/server/inference_server.cpp delete mode 100644 service/riscv/server/server_impl.cpp delete mode 100644 service/riscv/server/server_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 52ae2c4074..cfde11ec04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,6 @@ option(MMDEPLOY_BUILD_EXAMPLES "build examples" OFF) option(MMDEPLOY_SPDLOG_EXTERNAL "use external spdlog" OFF) option(MMDEPLOY_ZIP_MODEL "support SDK model in zip format" OFF) option(MMDEPLOY_COVERAGE "build SDK for coverage" OFF) -option(MMDEPLOY_BUILD_RISCV_SERVER "build riscv server" OFF) set(MMDEPLOY_TARGET_DEVICES "cpu" CACHE STRING "target devices to support") set(MMDEPLOY_TARGET_BACKENDS "" CACHE STRING "target inference engines to support") @@ -98,11 +97,6 @@ if (MMDEPLOY_BUILD_SDK) MMDeployLibs EXPORT MMDeployTargets) - if (MMDEPLOY_BUILD_RISCV_SERVER) - set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - add_subdirectory(service/riscv/server) - endif () - if (MMDEPLOY_BUILD_TEST) add_subdirectory(tests/test_csrc) endif () diff --git a/mmdeploy/backend/ncnn/wrapper.py b/mmdeploy/backend/ncnn/wrapper.py index 1dba4ef181..adc9dccdf0 100644 --- a/mmdeploy/backend/ncnn/wrapper.py +++ b/mmdeploy/backend/ncnn/wrapper.py @@ -11,167 +11,6 @@ from ..base import BACKEND_WRAPPER, BaseWrapper -class NCNNLocal: - """ncnn local wrapper class for inference. - - Args: - param_file (str): Path of a parameter file. - bin_file (str): Path of a binary file. - output_names (Sequence[str] | None): Names of model outputs in order. - Defaults to `None` and the wrapper will load the output names from - ncnn model. - """ - - def __init__(self, - param_file: str, - bin_file: str, - output_names: Optional[Sequence[str]] = None, - use_vulkan: bool = False, - **kwargs): - - net = ncnn.Net() - if importlib.util.find_spec('mmdeploy.backend.ncnn.ncnn_ext'): - from mmdeploy.backend.ncnn import ncnn_ext - ncnn_ext.register_mmdeploy_custom_layers(net) - net.opt.use_vulkan_compute = use_vulkan - net.load_param(param_file) - net.load_model(bin_file) - - self._net = net - if output_names is None: - assert hasattr(self._net, 'output_names') - output_names = self._net.output_names() - self.output_names = output_names - - def forward(self, inputs: Dict[str, torch.Tensor], batch_id: int): - - # create extractor - ex = self._net.create_extractor() - - # set inputs - for name, input_tensor in inputs.items(): - data = input_tensor[batch_id].contiguous() - data = data.detach().cpu().numpy() - input_mat = ncnn.Mat(data) - ex.input(name, input_mat) - - # get outputs - result = self.__ncnn_execute( - extractor=ex, output_names=self.output_names) - - return result - - @TimeCounter.count_time(Backend.NCNN.value) - def __ncnn_execute(self, extractor: ncnn.Extractor, - output_names: Sequence[str]) -> Dict[str, ncnn.Mat]: - """Run inference with ncnn. - - Args: - extractor (ncnn.Extractor): ncnn extractor to extract output. - output_names (Iterable[str]): A list of string specifying - output names. - - Returns: - dict[str, ncnn.Mat]: Inference results of ncnn model. - """ - result = {} - for name in output_names: - out_ret, out = extractor.extract(name) - assert out_ret == 0, f'Failed to extract output : {out}.' - result[name] = out - return result - - -class NCNNRemote: - """ncnn remote wrapper class for inference. - - Args: - param_file (str): Path of a parameter file. - bin_file (str): Path of a binary file. - output_names (Sequence[str] | None): Names of model outputs in order. - Defaults to `None` and the wrapper will load the output names from - ncnn model. - uri (str): uri for the server. - """ - - def __init__(self, - param_file: str, - bin_file: str, - output_names: Optional[Sequence[str]] = None, - uri=None, - **kwargs): - import grpc - import inference_pb2 - import inference_pb2_grpc - - from mmdeploy.utils.retry_interceptor import ( - ExponentialBackoff, RetryOnRpcErrorClientInterceptor) - - self._Tensor = inference_pb2.Tensor - self._TensorList = inference_pb2.TensorList - - logger = get_root_logger() - - if uri is None: - logger.error('URI not set') - - interceptors = (RetryOnRpcErrorClientInterceptor( - max_attempts=4, - sleeping_policy=ExponentialBackoff( - init_backoff_ms=100, max_backoff_ms=1600, multiplier=2), - status_for_retry=(grpc.StatusCode.UNAVAILABLE, ), - ), ) - self.stub = inference_pb2_grpc.InferenceStub( - grpc.intercept_channel(grpc.insecure_channel(uri), *interceptors)) - - with open(param_file, 'rb') as f: - params = f.read() - with open(bin_file, 'rb') as f: - weights = f.read() - - ncnn_model = inference_pb2.NCNNModel(params=params, weights=weights) - model = inference_pb2.Model(type=inference_pb2.NCNN, ncnn=ncnn_model) - resp = self.stub.Init(model) - - if resp.status != 0: - logger.error(f'init NCNN model failed {resp.info}') - return - - output = self.stub.OutputNames(inference_pb2.Empty()) - output_names = output.names - self.output_names = output_names - - def forward(self, inputs: Dict[str, torch.Tensor], batch_id: int): - ncnn_inputs = [] - for name, input_tensor in inputs.items(): - data = input_tensor[batch_id].contiguous() - data = data.detach().cpu().numpy() - data = data.astype(dtype=np.float32) - tensor = self._Tensor( - data=data.tobytes(), - name=name, - dtype='float32', - shape=list(data.shape)) - ncnn_inputs.append(tensor) - - tensorList = self._TensorList(data=ncnn_inputs) - return self.__ncnn_execute(tensorList) - - def __ncnn_execute(self, tensorList): - resp = self.stub.Inference(tensorList) - result = dict() - if resp.status == 0: - for tensor in resp.data: - ndarray = np.frombuffer(tensor.data, dtype=np.float32) - ndarray = ndarray.reshape(tuple(tensor.shape)) - result[tensor.name] = ncnn.Mat(ndarray) - else: - logger = get_root_logger() - logger.error(f'onnx inference failed {resp.info}') - - return result - - @BACKEND_WRAPPER.register_module(Backend.NCNN.value) class NCNNWrapper(BaseWrapper): """ncnn wrapper class for inference. @@ -200,15 +39,21 @@ def __init__(self, bin_file: str, output_names: Optional[Sequence[str]] = None, use_vulkan: bool = False, - uri=None, **kwargs): - if uri is None: - self._net = NCNNLocal(param_file, bin_file, output_names, - use_vulkan) - else: - self._net = NCNNRemote(param_file, bin_file, output_names, uri) - output_names = self._net.output_names + net = ncnn.Net() + if importlib.util.find_spec('mmdeploy.backend.ncnn.ncnn_ext'): + from mmdeploy.backend.ncnn import ncnn_ext + ncnn_ext.register_mmdeploy_custom_layers(net) + net.opt.use_vulkan_compute = use_vulkan + net.load_param(param_file) + net.load_model(bin_file) + + self._net = net + if output_names is None: + assert hasattr(self._net, 'output_names') + output_names = self._net.output_names() + super().__init__(output_names) @staticmethod @@ -249,7 +94,19 @@ def forward(self, inputs: Dict[str, outputs = dict([name, [None] * batch_size] for name in output_names) # run inference for batch_id in range(batch_size): - result = self._net.forward(inputs, batch_id) + # create extractor + ex = self._net.create_extractor() + + # set inputs + for name, input_tensor in inputs.items(): + data = input_tensor[batch_id].contiguous() + data = data.detach().cpu().numpy() + input_mat = ncnn.Mat(data) + ex.input(name, input_mat) + + # get outputs + result = self.__ncnn_execute( + extractor=ex, output_names=output_names) for name in output_names: mat = result[name] # deal with special case @@ -267,3 +124,23 @@ def forward(self, inputs: Dict[str, outputs[name] = torch.stack(output_tensor) return outputs + + @TimeCounter.count_time(Backend.NCNN.value) + def __ncnn_execute(self, extractor: ncnn.Extractor, + output_names: Sequence[str]) -> Dict[str, ncnn.Mat]: + """Run inference with ncnn. + + Args: + extractor (ncnn.Extractor): ncnn extractor to extract output. + output_names (Iterable[str]): A list of string specifying + output names. + + Returns: + dict[str, ncnn.Mat]: Inference results of ncnn model. + """ + result = {} + for name in output_names: + out_ret, out = extractor.extract(name) + assert out_ret == 0, f'Failed to extract output : {out}.' + result[name] = out + return result diff --git a/mmdeploy/codebase/base/backend_model.py b/mmdeploy/codebase/base/backend_model.py index c4459d05a2..3a3ae3fafc 100644 --- a/mmdeploy/codebase/base/backend_model.py +++ b/mmdeploy/codebase/base/backend_model.py @@ -82,15 +82,11 @@ def _build_wrapper(backend: Backend, use_vulkan = backend_config.get('use_vulkan', False) else: use_vulkan = False - uri = None - if 'uri' in kwargs: - uri = kwargs['uri'] return NCNNWrapper( param_file=backend_files[0], bin_file=backend_files[1], output_names=output_names, - use_vulkan=use_vulkan, - uri=uri) + use_vulkan=use_vulkan) elif backend == Backend.OPENVINO: from mmdeploy.backend.openvino import OpenVINOWrapper return OpenVINOWrapper( diff --git a/mmdeploy/utils/retry_interceptor.py b/mmdeploy/utils/retry_interceptor.py deleted file mode 100644 index 79d56213ba..0000000000 --- a/mmdeploy/utils/retry_interceptor.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. - -import abc -import time -from random import randint -from typing import Optional, Tuple - -import grpc - -from mmdeploy.utils import get_root_logger - - -class SleepingPolicy(abc.ABC): - - @abc.abstractmethod - def sleep(self, try_i: int): - """How long to sleep in milliseconds. - - :param try_i: the number of retry (starting from zero) - """ - assert try_i >= 0 - - -class ExponentialBackoff(SleepingPolicy): - - def __init__(self, *, init_backoff_ms: int, max_backoff_ms: int, - multiplier: int): - self.init_backoff = randint(0, init_backoff_ms) - self.max_backoff = max_backoff_ms - self.multiplier = multiplier - - def sleep(self, try_i: int): - sleep_range = min(self.init_backoff * self.multiplier**try_i, - self.max_backoff) - sleep_ms = randint(0, sleep_range) - logger = get_root_logger() - logger.debug(f'Sleeping for {sleep_ms}') - time.sleep(sleep_ms / 1000) - - -class RetryOnRpcErrorClientInterceptor(grpc.UnaryUnaryClientInterceptor, - grpc.StreamUnaryClientInterceptor): - - def __init__( - self, - *, - max_attempts: int, - sleeping_policy: SleepingPolicy, - status_for_retry: Optional[Tuple[grpc.StatusCode]] = None, - ): - self.max_attempts = max_attempts - self.sleeping_policy = sleeping_policy - self.status_for_retry = status_for_retry - - def _intercept_call(self, continuation, client_call_details, - request_or_iterator): - - for try_i in range(self.max_attempts): - response = continuation(client_call_details, request_or_iterator) - - if isinstance(response, grpc.RpcError): - - # Return if it was last attempt - if try_i == (self.max_attempts - 1): - return response - - # If status code is not in retryable status codes - if (self.status_for_retry - and response.code() not in self.status_for_retry): - return response - - self.sleeping_policy.sleep(try_i) - else: - return response - - def intercept_unary_unary(self, continuation, client_call_details, - request): - return self._intercept_call(continuation, client_call_details, request) - - def intercept_stream_unary(self, continuation, client_call_details, - request_iterator): - return self._intercept_call(continuation, client_call_details, - request_iterator) diff --git a/service/riscv/client/inference_pb2.py b/service/riscv/client/inference_pb2.py deleted file mode 100644 index a9f0716a0c..0000000000 --- a/service/riscv/client/inference_pb2.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: inference.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder - -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n\x0finference.proto\x12\x08mmdeploy\"7\n\x08PPLModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07weights\x18\x02 \x01(\x0c\x42\x07\n\x05_name\"H\n\tNCNNModel\x12\x11\n\x04name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x0e\n\x06params\x18\x02 \x01(\x0c\x12\x0f\n\x07weights\x18\x03 \x01(\x0c\x42\x07\n\x05_name\"\x89\x01\n\x05Model\x12!\n\x04type\x18\x01 \x01(\x0e\x32\x13.mmdeploy.ModelType\x12&\n\x04ncnn\x18\x02 \x01(\x0b\x32\x13.mmdeploy.NCNNModelH\x00\x88\x01\x01\x12$\n\x03ppl\x18\x03 \x01(\x0b\x32\x12.mmdeploy.PPLModelH\x01\x88\x01\x01\x42\x07\n\x05_ncnnB\x06\n\x04_ppl\"\x07\n\x05\x45mpty\"Q\n\x06Tensor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\x05\x64type\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\r\n\x05shape\x18\x04 \x03(\x05\x42\x08\n\x06_dtype\",\n\nTensorList\x12\x1e\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x10.mmdeploy.Tensor\"E\n\x05Reply\x12\x0e\n\x06status\x18\x01 \x01(\x05\x12\x0c\n\x04info\x18\x02 \x01(\t\x12\x1e\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\x10.mmdeploy.Tensor\"\x16\n\x05Names\x12\r\n\x05names\x18\x01 \x03(\t*,\n\tModelType\x12\n\n\x06UNKOWN\x10\x00\x12\x08\n\x04NCNN\x10\x01\x12\t\n\x05PPLNN\x10\x02\x32\xcf\x01\n\tInference\x12*\n\x04Init\x12\x0f.mmdeploy.Model\x1a\x0f.mmdeploy.Reply\"\x00\x12\x31\n\x0bOutputNames\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Names\"\x00\x12\x34\n\tInference\x12\x14.mmdeploy.TensorList\x1a\x0f.mmdeploy.Reply\"\x00\x12-\n\x07\x44\x65stroy\x12\x0f.mmdeploy.Empty\x1a\x0f.mmdeploy.Reply\"\x00\x42(\n\x0emmdeploy.riscvB\x0cRISCVWrapperP\x01\xa2\x02\x05RISCVb\x06proto3' -) - -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'inference_pb2', globals()) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'\n\016mmdeploy.riscvB\014RISCVWrapperP\001\242\002\005RISCV' - _MODELTYPE._serialized_start = 533 - _MODELTYPE._serialized_end = 577 - _PPLMODEL._serialized_start = 29 - _PPLMODEL._serialized_end = 84 - _NCNNMODEL._serialized_start = 86 - _NCNNMODEL._serialized_end = 158 - _MODEL._serialized_start = 161 - _MODEL._serialized_end = 298 - _EMPTY._serialized_start = 300 - _EMPTY._serialized_end = 307 - _TENSOR._serialized_start = 309 - _TENSOR._serialized_end = 390 - _TENSORLIST._serialized_start = 392 - _TENSORLIST._serialized_end = 436 - _REPLY._serialized_start = 438 - _REPLY._serialized_end = 507 - _NAMES._serialized_start = 509 - _NAMES._serialized_end = 531 - _INFERENCE._serialized_start = 580 - _INFERENCE._serialized_end = 787 -# @@protoc_insertion_point(module_scope) diff --git a/service/riscv/client/inference_pb2_grpc.py b/service/riscv/client/inference_pb2_grpc.py deleted file mode 100644 index 9c810fec02..0000000000 --- a/service/riscv/client/inference_pb2_grpc.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc -import inference_pb2 as inference__pb2 - - -class InferenceStub(object): - """The inference service definition.""" - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.Init = channel.unary_unary( - '/mmdeploy.Inference/Init', - request_serializer=inference__pb2.Model.SerializeToString, - response_deserializer=inference__pb2.Reply.FromString, - ) - self.OutputNames = channel.unary_unary( - '/mmdeploy.Inference/OutputNames', - request_serializer=inference__pb2.Empty.SerializeToString, - response_deserializer=inference__pb2.Names.FromString, - ) - self.Inference = channel.unary_unary( - '/mmdeploy.Inference/Inference', - request_serializer=inference__pb2.TensorList.SerializeToString, - response_deserializer=inference__pb2.Reply.FromString, - ) - self.Destroy = channel.unary_unary( - '/mmdeploy.Inference/Destroy', - request_serializer=inference__pb2.Empty.SerializeToString, - response_deserializer=inference__pb2.Reply.FromString, - ) - - -class InferenceServicer(object): - """The inference service definition.""" - - def Init(self, request, context): - """Init Model with model file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def OutputNames(self, request, context): - """Get output names.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def Inference(self, request, context): - """Inference with inputs.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def Destroy(self, request, context): - """Destroy handle.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_InferenceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'Init': - grpc.unary_unary_rpc_method_handler( - servicer.Init, - request_deserializer=inference__pb2.Model.FromString, - response_serializer=inference__pb2.Reply.SerializeToString, - ), - 'OutputNames': - grpc.unary_unary_rpc_method_handler( - servicer.OutputNames, - request_deserializer=inference__pb2.Empty.FromString, - response_serializer=inference__pb2.Names.SerializeToString, - ), - 'Inference': - grpc.unary_unary_rpc_method_handler( - servicer.Inference, - request_deserializer=inference__pb2.TensorList.FromString, - response_serializer=inference__pb2.Reply.SerializeToString, - ), - 'Destroy': - grpc.unary_unary_rpc_method_handler( - servicer.Destroy, - request_deserializer=inference__pb2.Empty.FromString, - response_serializer=inference__pb2.Reply.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'mmdeploy.Inference', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler, )) - - -# This class is part of an EXPERIMENTAL API. - - -class Inference(object): - """The inference service definition.""" - - @staticmethod - def Init(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary( - request, target, '/mmdeploy.Inference/Init', - inference__pb2.Model.SerializeToString, - inference__pb2.Reply.FromString, options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, - metadata) - - @staticmethod - def OutputNames(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary( - request, target, '/mmdeploy.Inference/OutputNames', - inference__pb2.Empty.SerializeToString, - inference__pb2.Names.FromString, options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, - metadata) - - @staticmethod - def Inference(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary( - request, target, '/mmdeploy.Inference/Inference', - inference__pb2.TensorList.SerializeToString, - inference__pb2.Reply.FromString, options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, - metadata) - - @staticmethod - def Destroy(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary( - request, target, '/mmdeploy.Inference/Destroy', - inference__pb2.Empty.SerializeToString, - inference__pb2.Reply.FromString, options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, - metadata) diff --git a/service/riscv/inference.proto b/service/riscv/inference.proto deleted file mode 100644 index b5d75b00c9..0000000000 --- a/service/riscv/inference.proto +++ /dev/null @@ -1,89 +0,0 @@ -syntax = "proto3"; - -option java_multiple_files = true; -option java_package = "mmdeploy.riscv"; -option java_outer_classname = "RISCVWrapper"; -option objc_class_prefix = "RISCV"; - -package mmdeploy; - -// The inference service definition. -service Inference { - - // Init Model with model file - rpc Init(Model) returns (Reply) {} - - // Get output names - rpc OutputNames(Empty) returns (Names) {} - - // Inference with inputs - rpc Inference(TensorList) returns (Reply) {} - - // Destroy handle - rpc Destroy(Empty) returns (Reply) {} -} - -message PPLModel { - // name - optional string name = 1; - - // weights - bytes weights = 2; -} - -message NCNNModel { - // name - optional string name = 1; - - // params - bytes params = 2; - - // weights - bytes weights = 3; -} - -enum ModelType { - UNKOWN = 0; - NCNN = 1; - PPLNN = 2; -} - -message Model { - - ModelType type = 1; - - optional NCNNModel ncnn = 2; - - optional PPLModel ppl = 3; -} - -// https://stackoverflow.com/questions/31768665/can-i-define-a-grpc-call-with-a-null-request-or-response -message Empty {} - -message Tensor { - // name - string name = 1; - - // datatype - optional string dtype = 2; - - // data - bytes data = 3; - - // shape - repeated int32 shape = 4; -} - -message TensorList { - repeated Tensor data = 1; -} - -message Reply { - int32 status = 1; - string info = 2; - repeated Tensor data = 3; -} - -message Names { - repeated string names = 1; -} diff --git a/service/riscv/server/CMakeLists.txt b/service/riscv/server/CMakeLists.txt deleted file mode 100644 index b079e5105f..0000000000 --- a/service/riscv/server/CMakeLists.txt +++ /dev/null @@ -1,56 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(RISCVServer C CXX) -include(./common.cmake) -include(../../../cmake/MMDeploy.cmake) - -# Proto file -get_filename_component(rv_proto "../inference.proto" ABSOLUTE) -get_filename_component(rv_proto_path "${rv_proto}" PATH) - -# Generated sources -set(rv_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/inference.pb.cc") -set(rv_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/inference.pb.h") -set(rv_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/inference.grpc.pb.cc") -set(rv_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/inference.grpc.pb.h") - -add_custom_command( - OUTPUT "${rv_proto_srcs}" "${rv_proto_hdrs}" "${rv_grpc_srcs}" "${rv_grpc_hdrs}" - COMMAND ${_PROTOBUF_PROTOC} - ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" - --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" - -I "${rv_proto_path}" - --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" - "${rv_proto}" - DEPENDS "${rv_proto}") - -find_package(ncnn REQUIRED) -# find_package(pplnn REQUIRED) - -# Include generated *.pb.h files -include_directories("${CMAKE_CURRENT_BINARY_DIR}") - -add_executable(inference_server - server_impl.cpp - inference_server.cpp - backend.cpp - ${rv_proto_srcs} - ${rv_grpc_srcs}) - -target_link_libraries(inference_server - PRIVATE - mmdeploy_ncnn_ops_obj - mmdeploy::core - ncnn - ${PPLNN_LIBRARIES} - ${_REFLECTION} - ${_GRPC_GRPCPP} - ${_PROTOBUF_LIBPROTOBUF} - -static) - -set_target_properties(inference_server - PROPERTIES RUNTIME_OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/riscv-server) - -# generate pb file -# GRPC_BIN_PATH=/opt/grpc/build/install/bin -# ${GRPC_BIN_PATH}/protoc -I . --python_out client --grpc_out client inference.proto --plugin=protoc-gen-grpc=${GRPC_BIN_PATH}/grpc_python_plugin diff --git a/service/riscv/server/backend.cpp b/service/riscv/server/backend.cpp deleted file mode 100644 index 6402823f4b..0000000000 --- a/service/riscv/server/backend.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "backend.h" - -#include -#include -#include - -#include "mmdeploy/core/logger.h" -#include "ncnn_ops_register.h" - -Status NCNNNet::Init(ServerContext* context, const Model* request, Reply* response) { - MMDEPLOY_INFO("Init ncnn net ..."); - net_.opt.use_fp16_packed = false; - net_.opt.use_fp16_storage = false; - net_.opt.use_fp16_arithmetic = false; - register_mmdeploy_custom_layers(net_); - // copy params & weights - params_ = request->ncnn().params(); - weights_ = request->ncnn().weights(); - net_.load_param_mem(params_.c_str()); - net_.load_model(reinterpret_cast(weights_.data())); - - response->set_status(0); - return Status::OK; -} - -Status NCNNNet::OutputNames(ServerContext* context, const Empty* request, Names* response) { - for (const auto& name : net_.output_names()) { - response->add_names(name); - } - return Status::OK; -} - -Status NCNNNet::Inference(ServerContext* context, const TensorList* request, Reply* response) { - auto extractor = net_.create_extractor(); - - const std::vector& input_names = net_.input_names(); - std::vector inputs(input_names.size()); - if (input_names.size() != request->data_size()) { - MMDEPLOY_ERROR("Inference: input names count not match !"); - response->set_status(-1); - response->set_info("Inference: input names count not match !"); - return Status::OK; - } - - // input - for (size_t i = 0; i < input_names.size(); ++i) { - auto& tensor = request->data(i); - auto& shape = tensor.shape(); - size_t total = shape[2] * shape[1] * shape[0]; - inputs[i] = ncnn::Mat(shape[2], shape[1], shape[0], (void*)tensor.data().data()); - extractor.input(input_names[i], inputs[i]); - } - - // output - auto t0 = std::chrono::high_resolution_clock::now(); - const std::vector& output_names = net_.output_names(); - std::vector outputs(output_names.size()); - for (size_t i = 0; i < output_names.size(); i++) { - extractor.extract(output_names[i], outputs[i]); - } - auto t1 = std::chrono::high_resolution_clock::now(); - auto dur = std::chrono::duration_cast(t1 - t0).count(); - MMDEPLOY_INFO("inference time: {} ms", dur); - - // response - for (size_t i = 0; i < output_names.size(); i++) { - Tensor* pdata = response->add_data(); - pdata->set_name(output_names[i]); - pdata->set_dtype("float32"); - - std::vector tshape; - auto shape = outputs[i].shape(); - if (shape.dims == 1) { - tshape = {shape.w}; - } else if (shape.dims == 2) { - tshape = {shape.h, shape.w}; - } else if (shape.dims == 3) { - tshape = {shape.c, shape.h, shape.w}; - } else if (shape.dims == 4) { - tshape = {shape.c, shape.d, shape.h, shape.w}; - } - for (auto d : tshape) { - pdata->add_shape(d); - } - size_t total = shape.c * shape.d * shape.h * shape.w; - auto flattened = outputs[i].reshape(total); - std::string tdata; - tdata.resize(total * sizeof(float)); - memcpy(tdata.data(), flattened.data, total * sizeof(float)); - pdata->set_data(tdata); - } - - response->set_status(0); - return Status::OK; -} diff --git a/service/riscv/server/backend.h b/service/riscv/server/backend.h deleted file mode 100644 index f4b8408225..0000000000 --- a/service/riscv/server/backend.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef SERVER_RISCV_BACKEND_H -#define SERVER_RISCV_BACKEND_H - -#include "inference.grpc.pb.h" -// It's ncnn's net.h -#include "net.h" - -using grpc::Server; -using grpc::ServerBuilder; -using grpc::ServerContext; -using grpc::Status; - -using mmdeploy::Empty; -using mmdeploy::Inference; -using mmdeploy::Model; -using mmdeploy::ModelType; -using mmdeploy::Names; -using mmdeploy::Reply; -using mmdeploy::Tensor; -using mmdeploy::TensorList; - -class Net { - public: - virtual Status Init(ServerContext* context, const Model* request, Reply* response) = 0; - virtual Status OutputNames(ServerContext* context, const Empty* request, Names* response) = 0; - virtual Status Inference(ServerContext* context, const TensorList* request, Reply* response) = 0; -}; - -class NCNNNet : public Net { - public: - Status Init(ServerContext* context, const Model* request, Reply* response) override; - Status OutputNames(ServerContext* context, const Empty* request, Names* response) override; - Status Inference(ServerContext* context, const TensorList* request, Reply* response) override; - - private: - ncnn::Net net_; - std::string params_; - std::string weights_; -}; - -#endif diff --git a/service/riscv/server/common.cmake b/service/riscv/server/common.cmake deleted file mode 100644 index 20d2f0c01e..0000000000 --- a/service/riscv/server/common.cmake +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# cmake build file for C++ route_guide example. -# Assumes protobuf and gRPC have been installed using cmake. -# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build -# that automatically builds all the dependencies before building route_guide. - -cmake_minimum_required(VERSION 3.5.1) - -set (CMAKE_CXX_STANDARD 17) - -if(MSVC) - add_definitions(-D_WIN32_WINNT=0x600) -endif() - -find_package(Threads REQUIRED) - -if(GRPC_AS_SUBMODULE) - # One way to build a projects that uses gRPC is to just include the - # entire gRPC project tree via "add_subdirectory". - # This approach is very simple to use, but the are some potential - # disadvantages: - # * it includes gRPC's CMakeLists.txt directly into your build script - # without and that can make gRPC's internal setting interfere with your - # own build. - # * depending on what's installed on your system, the contents of submodules - # in gRPC's third_party/* might need to be available (and there might be - # additional prerequisites required to build them). Consider using - # the gRPC_*_PROVIDER options to fine-tune the expected behavior. - # - # A more robust approach to add dependency on gRPC is using - # cmake's ExternalProject_Add (see cmake_externalproject/CMakeLists.txt). - - # Include the gRPC's cmake build (normally grpc source code would live - # in a git submodule called "third_party/grpc", but this example lives in - # the same repository as gRPC sources, so we just look a few directories up) - add_subdirectory(../../.. ${CMAKE_CURRENT_BINARY_DIR}/grpc EXCLUDE_FROM_ALL) - message(STATUS "Using gRPC via add_subdirectory.") - - # After using add_subdirectory, we can now use the grpc targets directly from - # this build. - set(_PROTOBUF_LIBPROTOBUF libprotobuf) - set(_REFLECTION grpc++_reflection) - if(CMAKE_CROSSCOMPILING) - find_program(_PROTOBUF_PROTOC protoc) - else() - set(_PROTOBUF_PROTOC $) - endif() - set(_GRPC_GRPCPP grpc++) - if(CMAKE_CROSSCOMPILING) - find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) - else() - set(_GRPC_CPP_PLUGIN_EXECUTABLE $) - endif() -elseif(GRPC_FETCHCONTENT) - # Another way is to use CMake's FetchContent module to clone gRPC at - # configure time. This makes gRPC's source code available to your project, - # similar to a git submodule. - message(STATUS "Using gRPC via add_subdirectory (FetchContent).") - include(FetchContent) - FetchContent_Declare( - grpc - GIT_REPOSITORY https://github.com/grpc/grpc.git - # when using gRPC, you will actually set this to an existing tag, such as - # v1.25.0, v1.26.0 etc.. - # For the purpose of testing, we override the tag used to the commit - # that's currently under test. - GIT_TAG vGRPC_TAG_VERSION_OF_YOUR_CHOICE) - FetchContent_MakeAvailable(grpc) - - # Since FetchContent uses add_subdirectory under the hood, we can use - # the grpc targets directly from this build. - set(_PROTOBUF_LIBPROTOBUF libprotobuf) - set(_REFLECTION grpc++_reflection) - set(_PROTOBUF_PROTOC $) - set(_GRPC_GRPCPP grpc++) - if(CMAKE_CROSSCOMPILING) - find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) - else() - set(_GRPC_CPP_PLUGIN_EXECUTABLE $) - endif() -else() - # This branch assumes that gRPC and all its dependencies are already installed - # on this system, so they can be located by find_package(). - - # Find Protobuf installation - # Looks for protobuf-config.cmake file installed by Protobuf's cmake installation. - set(protobuf_MODULE_COMPATIBLE TRUE) - find_package(Protobuf CONFIG REQUIRED) - message(STATUS "Using protobuf ${Protobuf_VERSION}") - - set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) - set(_REFLECTION gRPC::grpc++_reflection) - if(CMAKE_CROSSCOMPILING) - find_program(_PROTOBUF_PROTOC protoc) - else() - set(_PROTOBUF_PROTOC $) - endif() - - # Find gRPC installation - # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. - find_package(gRPC CONFIG REQUIRED) - message(STATUS "Using gRPC ${gRPC_VERSION}") - - set(_GRPC_GRPCPP gRPC::grpc++) - if(CMAKE_CROSSCOMPILING) - find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) - else() - set(_GRPC_CPP_PLUGIN_EXECUTABLE $) - endif() -endif() diff --git a/service/riscv/server/inference_server.cpp b/service/riscv/server/inference_server.cpp deleted file mode 100644 index fd146dd21a..0000000000 --- a/service/riscv/server/inference_server.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../../snpe/server/text_table.h" -#include "server_impl.h" - -void PrintIP() { - struct ifaddrs* ifAddrStruct = NULL; - void* tmpAddrPtr = NULL; - - int retval = getifaddrs(&ifAddrStruct); - if (retval == -1) { - return; - } - - helper::TextTable table("Device"); - table.padding(1); - table.add("port").add("ip").eor(); - while (ifAddrStruct != nullptr) { - if (ifAddrStruct->ifa_addr == nullptr) { - break; - } - - if (ifAddrStruct->ifa_addr->sa_family == AF_INET) { - tmpAddrPtr = &((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr; - char addressBuffer[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); - table.add(std::string(ifAddrStruct->ifa_name)).add(std::string(addressBuffer)).eor(); - } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { - tmpAddrPtr = &((struct sockaddr_in*)ifAddrStruct->ifa_addr)->sin_addr; - char addressBuffer[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); - table.add(std::string(ifAddrStruct->ifa_name)).add(std::string(addressBuffer)).eor(); - } - ifAddrStruct = ifAddrStruct->ifa_next; - } - std::cout << table << std::endl << std::endl; -} - -void RunServer(int port = 60000) { - // listen IPv4 and IPv6 - char server_address[64] = {0}; - sprintf(server_address, "[::]:%d", port); - InferenceServiceImpl service; - - grpc::EnableDefaultHealthCheckService(true); - grpc::reflection::InitProtoReflectionServerBuilderPlugin(); - ServerBuilder builder; - // Listen on the given address without any authentication mechanism. - builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); - - // Max 128MB - builder.SetMaxMessageSize(2 << 29); - builder.SetMaxSendMessageSize(2 << 29); - - // Register "service" as the instance through which we'll communicate with - // clients. In this case it corresponds to an *synchronous* service. - - builder.RegisterService(&service); - // Finally assemble the server. - std::unique_ptr server(builder.BuildAndStart()); - fprintf(stdout, "Server listening on %s\n", server_address); - - // Wait for the server to shutdown. Note that some other thread must be - // responsible for shutting down the server for this call to ever return. - server->Wait(); -} - -int main(int argc, char** argv) { - int port = 60000; - if (argc > 1) { - port = std::stoi(argv[1]); - } - - if (port <= 9999) { - fprintf(stdout, "Usage: %s [port]\n", argv[0]); - return 0; - } - PrintIP(); - RunServer(port); - - return 0; -} diff --git a/service/riscv/server/server_impl.cpp b/service/riscv/server/server_impl.cpp deleted file mode 100644 index 4c3aeecbb7..0000000000 --- a/service/riscv/server/server_impl.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) OpenMMLab. All rights reserved. - -#include "server_impl.h" - -Status InferenceServiceImpl::Init(ServerContext* context, const Model* request, Reply* response) { - if (net_ != nullptr) { - net_.reset(); - } - - if (request->type() == ModelType::NCNN) { - net_ = std::make_unique(); - return net_->Init(context, request, response); - } else if (request->type() == ModelType::PPLNN) { - response->set_info("not implemented"); - response->set_status(-1); - } else { - response->set_info("unsupported model type"); - response->set_status(-1); - } - - return Status::OK; -} - -Status InferenceServiceImpl::OutputNames(ServerContext* context, const Empty* request, - Names* response) { - return net_->OutputNames(context, request, response); -} - -Status InferenceServiceImpl::Inference(ServerContext* context, const TensorList* request, - Reply* response) { - return net_->Inference(context, request, response); -} -Status InferenceServiceImpl::Destroy(ServerContext* context, const Empty* request, - Reply* response) { - net_.reset(); - response->set_status(0); - return Status::OK; -} diff --git a/service/riscv/server/server_impl.h b/service/riscv/server/server_impl.h deleted file mode 100644 index fce12d9c88..0000000000 --- a/service/riscv/server/server_impl.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) OpenMMLab. All rights reserved. - -#ifndef SERVICE_RISCV_IMPL_H -#define SERVICE_RISCV_IMPL_H - -#include -#include -#include - -#include - -#include "backend.h" - -class InferenceServiceImpl final : public Inference::Service { - // Init Model with model file - Status Init(ServerContext* context, const Model* request, Reply* response) override; - // Get output names - Status OutputNames(ServerContext* context, const Empty* request, Names* response) override; - // Inference with inputs - Status Inference(ServerContext* context, const TensorList* request, Reply* response) override; - // Destroy handle - Status Destroy(ServerContext* context, const Empty* request, Reply* response) override; - - private: - std::unique_ptr net_; -}; - -#endif diff --git a/tools/deploy.py b/tools/deploy.py index 9cfa6cc54e..73135a6e3c 100644 --- a/tools/deploy.py +++ b/tools/deploy.py @@ -363,7 +363,7 @@ def main(): backend=backend, output_file=osp.join(args.work_dir, f'output_{backend.value}.jpg'), show_result=args.show) - if backend in [Backend.SNPE, Backend.NCNN]: + if backend == Backend.SNPE: extra['uri'] = args.uri create_process( From 89f5ba27fd072ca918531138a39ea2c8a3ad87b3 Mon Sep 17 00:00:00 2001 From: irexyc Date: Mon, 22 Aug 2022 19:53:10 +0800 Subject: [PATCH 12/28] fix docs --- docs/en/01-how-to-build/riscv.md | 16 ++++++++-------- docs/zh_cn/01-how-to-build/riscv.md | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 49334e2366..4b7fb4f48c 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -1,10 +1,10 @@ -# Build for RISCV +# Build for RISC-V -## 一、Install MMDeploy +## 1. Install MMDeploy We need `mmdeploy_onnx2ncnn` program to convert a ncnn model,so we have to install ncnn engine. You can refer to this [doc](./linux-x86_64.md) for installation. -## 二、Test the model +## 2. Test the model Take Resnet-18 as an example. First refer to [documentation to install mmcls](https://github.com/open-mmlab/mmclassification) to install mmcls. Then use `tools/deploy.py` to convert a model. @@ -23,9 +23,9 @@ $ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CON $ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall ``` -## 三、Build SDK +## 3. Build SDK -### 1. Download the compiler toolchain and set environment +### 1) Download the compiler toolchain and set environment ```bash # download Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz @@ -34,7 +34,7 @@ $ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz $ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` ``` -### 2. Compile ncnn & opencv +### 2) Compile ncnn & opencv ```bash # ncnn @@ -53,7 +53,7 @@ $ cmake .. \ $ make -j$(nproc) && make install ``` -### 3. Compile mmdeploy SDK & demo +### 3) Compile mmdeploy SDK & demo ```bash $ cd /path/to/mmdeploy @@ -83,7 +83,7 @@ $ tree -L 1 bin/ └── rotated_object_detection ``` -### 4. Run the demo +### 4) Run the demo First make sure that`--dump-info`is used during convert model, so that the `resnet18` directory has the files required by the SDK such as `pipeline.json`. diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index e7b29f5ea9..75fc07d0b6 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -1,4 +1,4 @@ -# 支持 RISCV +# 支持 RISC-V ## 一、安装 mmdeploy From 4ed00a78c26a812238c236643e6fb53b91f78052 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 23 Aug 2022 15:44:39 +0800 Subject: [PATCH 13/28] update zh doc --- docs/zh_cn/01-how-to-build/riscv.md | 40 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 75fc07d0b6..2da44eb002 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -1,10 +1,14 @@ # 支持 RISC-V -## 一、安装 mmdeploy +MMDeploy 选择 ncnn 作为 RISC-V 平台下的推理后端,为了使模型运行在 RISC-V 平台,我们需要进行模型转换以及模型部署两个步骤,其中模型转换在 Host 端完成,需要在 Host 端编译 ncnn 以及 MMDeploy,模型部署在 device 端完成,需要对各模块进行交叉编译。 -这里需要使用 mmdeploy_onnx2ncnn 进行模型转换,故需要安装 ncnn 推理引擎,可参考[BUILD 文档](./linux-x86_64.md) 进行安装, +## 1. 模型转换 -## 二、测试模型 +a) 安装 MMDeploy + +可参考 [BUILD 文档](./linux-x86_64.md),安装 ncnn 推理引擎以及 MMDeploy。 + +b) 模型转换 以 Resnet-18 为例。先参照[文档](https://github.com/open-mmlab/mmclassification)安装 mmcls,然后使用 `tools/deploy.py` 转换模型。 @@ -12,20 +16,26 @@ $ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py $ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth -export PYTHONPATH=${PWD}/service/riscv/client:${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} -export PATH=${pwd}/build/bin:${PATH} +# let import ncnn works +export PYTHONPATH=${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} +# add mmdeploy_onnx2ncnn to PATH +export PATH=${MMDEPLOY_ROOT}/build/bin:${PATH} # 模型转换 $ cd /path/to/mmdeploy -$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --dump-info - -# 精度测试 -$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall +$ python tools/deploy.py \ + configs/mmcls/classification_ncnn_static.py \ + $MODEL_CONFIG \ + $MODEL_PATH \ + /path/to/test.png \ + --work-dir resnet18 \ + --device cpu \ + --dump-info ``` -## 三、编译 SDK +## 2. 模型部署 -### 1. 下载交叉编译工具链,设置环境变量 +a) 下载交叉编译工具链,设置环境变量 ```bash # 下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz @@ -34,7 +44,7 @@ $ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz $ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` ``` -### 2. 编译 ncnn & opencv +b) 编译 ncnn & opencv ```bash # ncnn @@ -53,7 +63,7 @@ $ cmake .. \ $ make -j$(nproc) && make install ``` -### 3. 编译 mmdeploy SDK & demo +c) 编译 mmdeploy SDK & demo ```bash $ cd /path/to/mmdeploy @@ -67,7 +77,7 @@ $ cmake .. \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ -DMMDEPLOY_TARGET_DEVICES="cpu" \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR=/home/cx/ws/ncnn/build-c906/install/lib/cmake/ncnn/ \ + -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 @@ -83,7 +93,7 @@ $ tree -L 1 bin/ └── rotated_object_detection ``` -### 4. 运行 demo +d) 运行 demo 先确认测试模型用了 `--dump-info`,这样 `resnet18` 目录才有 `pipeline.json` 等 SDK 所需文件。 From aebbd4a729460073d20c51236ac3a586bf82e661 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 23 Aug 2022 16:07:18 +0800 Subject: [PATCH 14/28] update toolchain --- cmake/toolchains/riscv64-linux-gnu.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/toolchains/riscv64-linux-gnu.cmake b/cmake/toolchains/riscv64-linux-gnu.cmake index 0117ce98e3..c24661f6e6 100644 --- a/cmake/toolchains/riscv64-linux-gnu.cmake +++ b/cmake/toolchains/riscv64-linux-gnu.cmake @@ -18,5 +18,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) -set(CMAKE_C_FLAGS "-march=rv64gc -mabi=lp64d -mtune=c906") -set(CMAKE_CXX_FLAGS "-march=rv64gc -mabi=lp64d -mtune=c906") +set(CMAKE_C_FLAGS "-march=rv64gc") +set(CMAKE_CXX_FLAGS "-march=rv64gc") + +# cache flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags") From 006a1f9a292f9b2b062c4fa89d3dbcb967de3f50 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 23 Aug 2022 16:28:40 +0800 Subject: [PATCH 15/28] remove unused --- docs/zh_cn/01-how-to-build/riscv.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 2da44eb002..88d5b82370 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -16,11 +16,6 @@ b) 模型转换 $ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py $ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth -# let import ncnn works -export PYTHONPATH=${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} -# add mmdeploy_onnx2ncnn to PATH -export PATH=${MMDEPLOY_ROOT}/build/bin:${PATH} - # 模型转换 $ cd /path/to/mmdeploy $ python tools/deploy.py \ From 8c2f131c57d7c6ee494d832c37b97e9cd6abd2b0 Mon Sep 17 00:00:00 2001 From: irexyc Date: Tue, 23 Aug 2022 17:36:03 +0800 Subject: [PATCH 16/28] update doc --- docs/en/01-how-to-build/riscv.md | 98 ++++++++++++++++------------- docs/zh_cn/01-how-to-build/riscv.md | 82 +++++++++++++----------- 2 files changed, 101 insertions(+), 79 deletions(-) diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 4b7fb4f48c..1219fc698f 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -1,78 +1,90 @@ # Build for RISC-V -## 1. Install MMDeploy +MMDeploy chooses ncnn as the inference backend on RISC-V platform. The deployment process consists of two steps: -We need `mmdeploy_onnx2ncnn` program to convert a ncnn model,so we have to install ncnn engine. You can refer to this [doc](./linux-x86_64.md) for installation. +Model conversion: Convert the PyTorch model to the ncnn model on the host side, and then upload the converted model to the device. -## 2. Test the model +Model deployment: Compile ncnn and MMDeploy in cross-compilation mode on the host side, and then upload the executable for inference. -Take Resnet-18 as an example. First refer to [documentation to install mmcls](https://github.com/open-mmlab/mmclassification) to install mmcls. Then use `tools/deploy.py` to convert a model. +## 1. Model conversion -```bash -$ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py -$ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth +a) Install MMDeploy -export PYTHONPATH=${PWD}/service/riscv/client:${NCNN_ROOT}/build/python/ncnn:${PYTHONPATH} -export PATH=${pwd}/build/bin:${PATH} +You can refer to [Build document](./linux-x86_64.md) to install ncnn inference engine and MMDeploy -# Convert the model -$ cd /path/to/mmdeploy -$ python3 tools/deploy.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG $MODEL_PATH /path/to/test.png --work-dir resnet18 --device cpu --dump-info +b) Convert model -# accuracy test -$ python3 tools/test.py configs/mmcls/classification_ncnn_static.py $MODEL_CONFIG --model reset18/end2end.param resnet18/end2end.bin --metrics accuracy precision f1_score recall +```bash +export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py +export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + +# Convert the model +cd /path/to/mmdeploy +python tools/deploy.py \ + configs/mmcls/classification_ncnn_static.py \ + $MODEL_CONFIG \ + $MODEL_PATH \ + tests/data/tiger.jpeg \ + --work-dir resnet18 \ + --device cpu \ + --dump-info ``` -## 3. Build SDK +## 2. Model deployment -### 1) Download the compiler toolchain and set environment +a) Download the compiler toolchain and set environment ```bash # download Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz # https://occ.t-head.cn/community/download?id=4046947553902661632 -$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz -$ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` +tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` ``` -### 2) Compile ncnn & opencv +b) Compile ncnn & opencv ```bash # ncnn # refer to https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-allwinner-d1 # opencv -$ git clone https://github.com/opencv/opencv.git -$ mkdir build && cd build -$ cmake .. \ +git clone https://github.com/opencv/opencv.git +mkdir build && cd build +cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_TESTS=OFF \ -DCMAKE_BUILD_TYPE=Release -$ make -j$(nproc) && make install +make -j$(nproc) && make install ``` -### 3) Compile mmdeploy SDK & demo +c) Compile mmdeploy SDK & demo ```bash -$ cd /path/to/mmdeploy -$ mkdir build && cd build -$ cmake .. \ - -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ - -DMMDEPLOY_BUILD_SDK=ON \ - -DMMDEPLOY_SHARED_LIBS=OFF \ - -DMMDEPLOY_BUILD_EXAMPLES=ON \ - -DMMDEPLOY_TARGET_DEVICES="cpu" \ - -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR=/home/cx/ws/ncnn/build-c906/install/lib/cmake/ncnn/ \ - -DMMDEPLOY_CODEBASES=all \ - -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 - -$ make -j$(nproc) && make install -$ tree -L 1 bin/ +cd /path/to/mmdeploy +mkdir build && cd build +cmake .. \ + -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DMMDEPLOY_BUILD_SDK=ON \ + -DMMDEPLOY_SHARED_LIBS=OFF \ + -DMMDEPLOY_BUILD_EXAMPLES=ON \ + -DMMDEPLOY_TARGET_DEVICES="cpu" \ + -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ + -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -DMMDEPLOY_CODEBASES=all \ + -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 + +make -j$(nproc) && make install +``` + +After `make install`, the examples will located in `install\bin` + +``` +tree -L 1 install/bin/ . ├── image_classification ├── image_restorer @@ -85,9 +97,9 @@ $ tree -L 1 bin/ ### 4) Run the demo -First make sure that`--dump-info`is used during convert model, so that the `resnet18` directory has the files required by the SDK such as `pipeline.json`. +First make sure that `--dump-info` is used during convert model, so that the `resnet18` directory has the files required by the SDK such as `pipeline.json`. -Copy the model folder and executable file to the device. +Copy the model folder(resnet18), executable(image_classification) file and test image(tests/data/tiger.jpeg) to the device. ```bash ./image_classification cpu ./resnet18 tiger.jpeg diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 88d5b82370..36fabc9ca5 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -1,6 +1,10 @@ # 支持 RISC-V -MMDeploy 选择 ncnn 作为 RISC-V 平台下的推理后端,为了使模型运行在 RISC-V 平台,我们需要进行模型转换以及模型部署两个步骤,其中模型转换在 Host 端完成,需要在 Host 端编译 ncnn 以及 MMDeploy,模型部署在 device 端完成,需要对各模块进行交叉编译。 +MMDeploy 选择 ncnn 作为 RISC-V 平台下的推理后端。完整的部署过程包含两个步骤: + +模型转换:在 Host 端将 PyTorch 模型转为 ncnn 模型。并将转换后的模型传到 device。 + +模型部署:在 Host 端以交叉编译方式编译 ncnn 和 MMDeploy。传到 Device 端进行推理。 ## 1. 模型转换 @@ -13,19 +17,19 @@ b) 模型转换 以 Resnet-18 为例。先参照[文档](https://github.com/open-mmlab/mmclassification)安装 mmcls,然后使用 `tools/deploy.py` 转换模型。 ```bash -$ export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py -$ export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth +export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py +export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth # 模型转换 -$ cd /path/to/mmdeploy -$ python tools/deploy.py \ - configs/mmcls/classification_ncnn_static.py \ - $MODEL_CONFIG \ - $MODEL_PATH \ - /path/to/test.png \ - --work-dir resnet18 \ - --device cpu \ - --dump-info +cd /path/to/mmdeploy +python tools/deploy.py \ + configs/mmcls/classification_ncnn_static.py \ + $MODEL_CONFIG \ + $MODEL_PATH \ + tests/data/tiger.jpeg \ + --work-dir resnet18 \ + --device cpu \ + --dump-info ``` ## 2. 模型部署 @@ -35,8 +39,8 @@ a) 下载交叉编译工具链,设置环境变量 ```bash # 下载 Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz # https://occ.t-head.cn/community/download?id=4046947553902661632 -$ tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz -$ export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` +tar xf Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6-20220516.tar.gz +export RISCV_ROOT_PATH=`realpath Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.6` ``` b) 编译 ncnn & opencv @@ -46,38 +50,44 @@ b) 编译 ncnn & opencv # 可参考 https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-allwinner-d1 # opencv -$ git clone https://github.com/opencv/opencv.git -$ mkdir build && cd build -$ cmake .. \ +git clone https://github.com/opencv/opencv.git +mkdir build && cd build +cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_TESTS=OFF \ -DCMAKE_BUILD_TYPE=Release -$ make -j$(nproc) && make install + +make -j$(nproc) && make install ``` c) 编译 mmdeploy SDK & demo ```bash -$ cd /path/to/mmdeploy -$ mkdir build && cd build -$ cmake .. \ - -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ - -DMMDEPLOY_BUILD_SDK=ON \ - -DMMDEPLOY_SHARED_LIBS=OFF \ - -DMMDEPLOY_BUILD_EXAMPLES=ON \ - -DMMDEPLOY_TARGET_DEVICES="cpu" \ - -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ - -DMMDEPLOY_CODEBASES=all \ - -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 - -$ make -j$(nproc) && make install -$ tree -L 1 bin/ +cd /path/to/mmdeploy +mkdir build && cd build +cmake .. \ + -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DMMDEPLOY_BUILD_SDK=ON \ + -DMMDEPLOY_SHARED_LIBS=OFF \ + -DMMDEPLOY_BUILD_EXAMPLES=ON \ + -DMMDEPLOY_TARGET_DEVICES="cpu" \ + -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ + -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -DMMDEPLOY_CODEBASES=all \ + -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 + +make -j$(nproc) && make install +``` + +执行 `make install` 之后, examples的可执行文件会保存在 `install/bin` + +``` +tree -L 1 install/bin/ . ├── image_classification ├── image_restorer @@ -92,7 +102,7 @@ d) 运行 demo 先确认测试模型用了 `--dump-info`,这样 `resnet18` 目录才有 `pipeline.json` 等 SDK 所需文件。 -把 dump 好的模型目录、可执行文件拷贝到设备中 +把 dump 好的模型目录(resnet18)、可执行文件(image_classification)、测试图片(tests/data/tiger.jpeg)拷贝到设备中 ```bash ./image_classification cpu ./resnet18 tiger.jpeg From 5b5884ae5b5d5c7476433c9d3db5f2672e46c87b Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 24 Aug 2022 11:09:18 +0800 Subject: [PATCH 17/28] update doc --- docs/en/01-how-to-build/riscv.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 1219fc698f..24010a2d9f 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -66,22 +66,20 @@ c) Compile mmdeploy SDK & demo cd /path/to/mmdeploy mkdir build && cd build cmake .. \ - -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ -DMMDEPLOY_SHARED_LIBS=OFF \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ -DMMDEPLOY_TARGET_DEVICES="cpu" \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -Dncnn_DIR=${ncnn_DIR}/build/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 make -j$(nproc) && make install ``` -After `make install`, the examples will located in `install\bin` +After `make install`, the examples will locate in `install\bin` ``` tree -L 1 install/bin/ From 63e7223d37a62c52bb8adb95922da21d7438c56c Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 24 Aug 2022 11:23:09 +0800 Subject: [PATCH 18/28] update doc --- docs/zh_cn/01-how-to-build/riscv.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 36fabc9ca5..088cfb813b 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -69,15 +69,13 @@ c) 编译 mmdeploy SDK & demo cd /path/to/mmdeploy mkdir build && cd build cmake .. \ - -DMMDEPLOY_BUILD_RISCV_SERVER=ON \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ -DMMDEPLOY_SHARED_LIBS=OFF \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ -DMMDEPLOY_TARGET_DEVICES="cpu" \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR={ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -Dncnn_DIR=${ncnn_DIR}/build/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 From 438925b839c2dbc5bfed6091bdf817c599c25781 Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 24 Aug 2022 15:11:16 +0800 Subject: [PATCH 19/28] rename cross build dirname --- docs/en/01-how-to-build/riscv.md | 8 ++++---- docs/zh_cn/01-how-to-build/riscv.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 24010a2d9f..0feda589c1 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -49,7 +49,7 @@ b) Compile ncnn & opencv # opencv git clone https://github.com/opencv/opencv.git -mkdir build && cd build +mkdir build_riscv && cd build_riscv cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ @@ -64,7 +64,7 @@ c) Compile mmdeploy SDK & demo ```bash cd /path/to/mmdeploy -mkdir build && cd build +mkdir build_riscv && cd build_riscv cmake .. \ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ @@ -72,9 +72,9 @@ cmake .. \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ -DMMDEPLOY_TARGET_DEVICES="cpu" \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR=${ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -Dncnn_DIR=${ncnn_DIR}/build-c906/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ - -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 + -DOpenCV_DIR=${OpenCV_DIR}/build_riscv/install/lib/cmake/opencv4 make -j$(nproc) && make install ``` diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 088cfb813b..c3540bc41d 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -51,7 +51,7 @@ b) 编译 ncnn & opencv # opencv git clone https://github.com/opencv/opencv.git -mkdir build && cd build +mkdir build_riscv && cd build_riscv cmake .. \ -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ @@ -67,7 +67,7 @@ c) 编译 mmdeploy SDK & demo ```bash cd /path/to/mmdeploy -mkdir build && cd build +mkdir build_riscv && cd build_riscv cmake .. \ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ @@ -75,9 +75,9 @@ cmake .. \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ -DMMDEPLOY_TARGET_DEVICES="cpu" \ -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ - -Dncnn_DIR=${ncnn_DIR}/build/install/lib/cmake/ncnn/ \ + -Dncnn_DIR=${ncnn_DIR}/build-c906/install/lib/cmake/ncnn/ \ -DMMDEPLOY_CODEBASES=all \ - -DOpenCV_DIR=${OpenCV_DIR}/build/install/lib/cmake/opencv4 + -DOpenCV_DIR=${OpenCV_DIR}/build_riscv/install/lib/cmake/opencv4 make -j$(nproc) && make install ``` From 2bda00a4b7397645de158777c168055b17442783 Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 24 Aug 2022 15:28:19 +0800 Subject: [PATCH 20/28] add riscv.md to build_from_source.md --- docs/en/01-how-to-build/build_from_source.md | 1 + docs/zh_cn/01-how-to-build/build_from_source.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/en/01-how-to-build/build_from_source.md b/docs/en/01-how-to-build/build_from_source.md index 2aa6ecc851..d05d9e27fa 100644 --- a/docs/en/01-how-to-build/build_from_source.md +++ b/docs/en/01-how-to-build/build_from_source.md @@ -38,3 +38,4 @@ Please visit the following links to find out how to build MMDeploy according to - [Android-aarch64](android.md) - [NVIDIA Jetson](jetsons.md) - [SNPE](snpe.md) +- [RISC-V](riscv.md) diff --git a/docs/zh_cn/01-how-to-build/build_from_source.md b/docs/zh_cn/01-how-to-build/build_from_source.md index d43d80a316..66f87c0158 100644 --- a/docs/zh_cn/01-how-to-build/build_from_source.md +++ b/docs/zh_cn/01-how-to-build/build_from_source.md @@ -41,3 +41,4 @@ git clone -b master git@github.com:open-mmlab/mmdeploy.git --recursive - [Android-aarch64](android.md) - [NVIDIA Jetson](jetsons.md) - [Qcom SNPE](snpe.md) +- [RISC-V](riscv.md) From 3abba9a10d5f3b2fcb6972b88380fa3daebe93cb Mon Sep 17 00:00:00 2001 From: irexyc Date: Wed, 24 Aug 2022 15:48:14 +0800 Subject: [PATCH 21/28] update cls model --- docs/en/01-how-to-build/riscv.md | 4 ++-- docs/zh_cn/01-how-to-build/riscv.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 0feda589c1..3e9e12ec3b 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -15,8 +15,8 @@ You can refer to [Build document](./linux-x86_64.md) to install ncnn inference e b) Convert model ```bash -export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py -export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth +export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb32_in1k.py +export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth # Convert the model cd /path/to/mmdeploy diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index c3540bc41d..49262b17f7 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -17,8 +17,8 @@ b) 模型转换 以 Resnet-18 为例。先参照[文档](https://github.com/open-mmlab/mmclassification)安装 mmcls,然后使用 `tools/deploy.py` 转换模型。 ```bash -export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb16_cifar10.py -export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth +export MODEL_CONFIG=/path/to/mmclassification/configs/resnet/resnet18_8xb32_in1k.py +export MODEL_PATH=https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth # 模型转换 cd /path/to/mmdeploy From 419e068c48f6e77acf7dd88130522df3a7cc0460 Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 15:21:17 +0800 Subject: [PATCH 22/28] test ci --- .github/workflows/linux-riscv64-gcc.yml | 74 +++++++++++++++++++ cmake/toolchains/riscv64-linux-gnu.cmake | 13 +--- .../riscv64-unknown-linux-gnu.cmake | 26 +++++++ docs/en/01-how-to-build/riscv.md | 4 +- docs/zh_cn/01-how-to-build/riscv.md | 4 +- 5 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/linux-riscv64-gcc.yml create mode 100644 cmake/toolchains/riscv64-unknown-linux-gnu.cmake diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml new file mode 100644 index 0000000000..9fc0edfed8 --- /dev/null +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -0,0 +1,74 @@ +name: build_riscv64_gcc + +on: + push: + paths: + - "csrc/**" + - "demo/csrc/**" + - "CMakeLists.txt" + + pull_request: + paths-ignore: + - "csrc/**" + - "demo/csrc/**" + - "CMakeLists.txt" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_riscv64_gcc: + runs-on: ubuntu-20.04 + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: riscv64-gnu-toolchain + run: | + sudo apt-get update + sudo apt-get install g++-riscv64-linux-gnu + - name: install opencv + run: | + git clone --depth 1 https://github.com/opencv/opencv.git + cd opencv + mkdir build_riscv && cd build_riscv + cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_INSTALL_PREFIX=install \ + -DBUILD_PERF_TESTS=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_TESTS=OFF \ + -DCMAKE_BUILD_TYPE=Release + make -j$(nproc) + make install + mkdir $GITHUB_WORKSPACE/opencv-install + cp -r install/* $GITHUB_WORKSPACE/opencv-install + - name: install ncnn + run: | + git clone --recursive --depth 1 https://github.com/Tencent/ncnn.git + mkdir build_riscv && cd build_riscv + cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/riscv64-linux-gnu.toolchain.cmake \ + -DNCNN_BUILD_TOOLS=OFF \ + -DNCNN_BUILD_EXAMPLES=OFF \ + -DNCNN_BUILD_TESTS=OFF .. + make -j$(nproc) + make install + mkdir $GITHUB_WORKSPACE/ncnn-install + cp -r install/* $GITHUB_WORKSPACE/ncnn-install + - name: build + run: | + mkdir build && cd build + cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DMMDEPLOY_BUILD_SDK=ON \ + -DMMDEPLOY_SHARED_LIBS=ON \ + -DMMDEPLOY_BUILD_EXAMPLES=ON \ + -DMMDEPLOY_TARGET_DEVICES="cpu" \ + -DMMDEPLOY_TARGET_BACKENDS="ncnn" \ + -Dncnn_DIR=$GITHUB_WORKSPACE/ncnn-install/lib/cmake/ncnn/ \ + -DMMDEPLOY_CODEBASES=all \ + -DOpenCV_DIR=$GITHUB_WORKSPACE/opencv-install/lib/cmake/opencv4 + make -j$(nproc) + make install diff --git a/cmake/toolchains/riscv64-linux-gnu.cmake b/cmake/toolchains/riscv64-linux-gnu.cmake index c24661f6e6..e3b3b2adbc 100644 --- a/cmake/toolchains/riscv64-linux-gnu.cmake +++ b/cmake/toolchains/riscv64-linux-gnu.cmake @@ -1,17 +1,8 @@ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR riscv) -if(DEFINED ENV{RISCV_ROOT_PATH}) - file(TO_CMAKE_PATH $ENV{RISCV_ROOT_PATH} RISCV_ROOT_PATH) -else() - message(FATAL_ERROR "RISCV_ROOT_PATH env must be defined") -endif() - -set(CMAKE_C_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-gcc) -set(CMAKE_CXX_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-g++) - -set(CMAKE_SYSROOT "${RISCV_ROOT_PATH}/sysroot" CACHE PATH "riscv sysroot") -set(CMAKE_FIND_ROOT_PATH ${RISCV_ROOT_PATH}/riscv64-unknown-linux-gnu) +set(CMAKE_C_COMPILER "riscv64-linux-gnu-gcc") +set(CMAKE_CXX_COMPILER "riscv64-linux-gnu-g++") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/cmake/toolchains/riscv64-unknown-linux-gnu.cmake b/cmake/toolchains/riscv64-unknown-linux-gnu.cmake new file mode 100644 index 0000000000..c24661f6e6 --- /dev/null +++ b/cmake/toolchains/riscv64-unknown-linux-gnu.cmake @@ -0,0 +1,26 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv) + +if(DEFINED ENV{RISCV_ROOT_PATH}) + file(TO_CMAKE_PATH $ENV{RISCV_ROOT_PATH} RISCV_ROOT_PATH) +else() + message(FATAL_ERROR "RISCV_ROOT_PATH env must be defined") +endif() + +set(CMAKE_C_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER ${RISCV_ROOT_PATH}/bin/riscv64-unknown-linux-gnu-g++) + +set(CMAKE_SYSROOT "${RISCV_ROOT_PATH}/sysroot" CACHE PATH "riscv sysroot") +set(CMAKE_FIND_ROOT_PATH ${RISCV_ROOT_PATH}/riscv64-unknown-linux-gnu) + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +set(CMAKE_C_FLAGS "-march=rv64gc") +set(CMAKE_CXX_FLAGS "-march=rv64gc") + +# cache flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags") diff --git a/docs/en/01-how-to-build/riscv.md b/docs/en/01-how-to-build/riscv.md index 3e9e12ec3b..28e78e57a5 100644 --- a/docs/en/01-how-to-build/riscv.md +++ b/docs/en/01-how-to-build/riscv.md @@ -51,7 +51,7 @@ b) Compile ncnn & opencv git clone https://github.com/opencv/opencv.git mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-unknown-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ @@ -66,7 +66,7 @@ c) Compile mmdeploy SDK & demo cd /path/to/mmdeploy mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-unknown-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ -DMMDEPLOY_SHARED_LIBS=OFF \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ diff --git a/docs/zh_cn/01-how-to-build/riscv.md b/docs/zh_cn/01-how-to-build/riscv.md index 49262b17f7..eb1baedf30 100644 --- a/docs/zh_cn/01-how-to-build/riscv.md +++ b/docs/zh_cn/01-how-to-build/riscv.md @@ -53,7 +53,7 @@ b) 编译 ncnn & opencv git clone https://github.com/opencv/opencv.git mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-unknown-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ @@ -69,7 +69,7 @@ c) 编译 mmdeploy SDK & demo cd /path/to/mmdeploy mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/riscv64-unknown-linux-gnu.cmake \ -DMMDEPLOY_BUILD_SDK=ON \ -DMMDEPLOY_SHARED_LIBS=OFF \ -DMMDEPLOY_BUILD_EXAMPLES=ON \ From 83a878830cbeb30ef5c3c143254ab3e18a95c4df Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 15:24:34 +0800 Subject: [PATCH 23/28] test ci --- .github/workflows/linux-riscv64-gcc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index 9fc0edfed8..83e3629d7c 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -35,7 +35,7 @@ jobs: cd opencv mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=/path/to/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ From 38ac29aa782289ab94135f106440a439768a19c2 Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 15:28:15 +0800 Subject: [PATCH 24/28] test ci --- .github/workflows/linux-riscv64-gcc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index 83e3629d7c..e748ca18c6 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -35,7 +35,7 @@ jobs: cd opencv mkdir build_riscv && cd build_riscv cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/mmdeploy/cmake/toolchains/riscv64-linux-gnu.cmake \ + -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/cmake/toolchains/riscv64-linux-gnu.cmake \ -DCMAKE_INSTALL_PREFIX=install \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_SHARED_LIBS=OFF \ From ca6aa79063e67c3793cb656756f7fe01a9f6f397 Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 15:44:18 +0800 Subject: [PATCH 25/28] test ci --- .github/workflows/linux-riscv64-gcc.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index e748ca18c6..61e07781ee 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -48,6 +48,7 @@ jobs: - name: install ncnn run: | git clone --recursive --depth 1 https://github.com/Tencent/ncnn.git + cd ncnn mkdir build_riscv && cd build_riscv cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/riscv64-linux-gnu.toolchain.cmake \ -DNCNN_BUILD_TOOLS=OFF \ From 41f149966b2ba2f271bee0bb9632965e5be065ef Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 17:18:07 +0800 Subject: [PATCH 26/28] test ci --- .github/workflows/linux-riscv64-gcc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index 61e07781ee..557c00e749 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -19,7 +19,7 @@ concurrency: jobs: build_riscv64_gcc: - runs-on: ubuntu-20.04 + runs-on: ubuntu-18.04 steps: - name: Checkout repository uses: actions/checkout@v3 From 99caaa9d2fb69826e1df2d3b474e7a8ea99f688b Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 18:56:09 +0800 Subject: [PATCH 27/28] update ci --- .github/workflows/linux-riscv64-gcc.yml | 27 ++++--------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index 557c00e749..21fc3dcd65 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -31,33 +31,14 @@ jobs: sudo apt-get install g++-riscv64-linux-gnu - name: install opencv run: | - git clone --depth 1 https://github.com/opencv/opencv.git - cd opencv - mkdir build_riscv && cd build_riscv - cmake .. \ - -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/cmake/toolchains/riscv64-linux-gnu.cmake \ - -DCMAKE_INSTALL_PREFIX=install \ - -DBUILD_PERF_TESTS=OFF \ - -DBUILD_SHARED_LIBS=OFF \ - -DBUILD_TESTS=OFF \ - -DCMAKE_BUILD_TYPE=Release - make -j$(nproc) - make install mkdir $GITHUB_WORKSPACE/opencv-install - cp -r install/* $GITHUB_WORKSPACE/opencv-install + wget https://github.com/irexyc/mmdeploy-ci-resource/raw/opencv/opencv_4.6.0_linux_riscv64.tar.gz + tar xf opencv_4.6.0_linux_riscv64.tar.gz -C $GITHUB_WORKSPACE/opencv-install - name: install ncnn run: | - git clone --recursive --depth 1 https://github.com/Tencent/ncnn.git - cd ncnn - mkdir build_riscv && cd build_riscv - cmake -DCMAKE_TOOLCHAIN_FILE=../toolchains/riscv64-linux-gnu.toolchain.cmake \ - -DNCNN_BUILD_TOOLS=OFF \ - -DNCNN_BUILD_EXAMPLES=OFF \ - -DNCNN_BUILD_TESTS=OFF .. - make -j$(nproc) - make install mkdir $GITHUB_WORKSPACE/ncnn-install - cp -r install/* $GITHUB_WORKSPACE/ncnn-install + wget https://github.com/irexyc/mmdeploy-ci-resource/raw/ncnn/ncnn_20220729_linux_riscv64.tar.gz + tar xf ncnn_20220729_linux_riscv64.tar.gz -C $GITHUB_WORKSPACE/ncnn-install - name: build run: | mkdir build && cd build From 70216341ddcb63c988692f3a6f6e9543f4747405 Mon Sep 17 00:00:00 2001 From: irexyc Date: Thu, 25 Aug 2022 19:11:19 +0800 Subject: [PATCH 28/28] update ci --- .github/workflows/linux-riscv64-gcc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux-riscv64-gcc.yml b/.github/workflows/linux-riscv64-gcc.yml index 21fc3dcd65..462a85296a 100644 --- a/.github/workflows/linux-riscv64-gcc.yml +++ b/.github/workflows/linux-riscv64-gcc.yml @@ -19,7 +19,7 @@ concurrency: jobs: build_riscv64_gcc: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - name: Checkout repository uses: actions/checkout@v3