From 7aa716278b46e803890c1dca2c6208c5a2f8eda3 Mon Sep 17 00:00:00 2001 From: MegEngine Date: Sat, 18 Sep 2021 15:47:30 +0800 Subject: [PATCH] ci(docker): add tuna source --- Dockerfile | 14 +- README.md | 3 +- doc_link_checker.py => ci/doc_link_checker.py | 8 +- ci/run_pylint_check.sh | 6 + docs/Makefile | 21 + docs/conf.py | 70 ++ .../01-single-classification-model.zh.md | 15 +- .../build-from-source.zh.md | 9 +- docs/index.rst | 36 ++ docs/make.bat | 35 + docs/requirements.txt | 4 + flow-python/examples/cat_finder/det.py | 19 +- .../examples/cat_finder/redis_proxy.py | 63 +- flow-python/examples/cat_finder/reid_image.py | 16 +- flow-python/examples/cat_finder/reid_video.py | 11 +- flow-python/examples/cat_finder/shaper.py | 13 +- flow-python/examples/cat_finder/track.py | 10 +- flow-python/examples/electric_bicycle/det.py | 17 +- .../examples/electric_bicycle/redis_proxy.py | 19 +- .../examples/electric_bicycle/shaper.py | 11 +- .../examples/electric_bicycle/track.py | 6 +- flow-python/examples/logical_test/__init__.py | 1 - flow-python/examples/logical_test/buffer.py | 1 + flow-python/examples/logical_test/printer.py | 8 +- flow-python/examples/logical_test/process.py | 7 +- flow-python/examples/logical_test/source.py | 2 +- .../simple_classification/__init__.py | 10 + .../simple_classification/classify.py | 13 +- .../examples/simple_classification/dump.py | 29 - .../examples/simple_classification/lite.py | 47 +- flow-python/examples/utils.py | 3 +- .../examples/warehouse/detection_memd/main.py | 23 +- .../warehouse/detection_memd/onnx_model.py | 22 +- .../warehouse/detection_yolox/__init__.py | 5 - .../warehouse/detection_yolox/build.py | 54 -- .../warehouse/detection_yolox/lite.py | 59 +- .../warehouse/detection_yolox/main.py | 202 ------ .../detection_yolox/models/__init__.py | 9 - .../detection_yolox/models/darknet.py | 154 ----- .../detection_yolox/models/network_blocks.py | 183 ------ .../detection_yolox/models/yolo_fpn.py | 78 --- .../detection_yolox/models/yolo_head.py | 192 ------ .../detection_yolox/models/yolo_pafpn.py | 111 ---- .../warehouse/detection_yolox/models/yolox.py | 34 - .../warehouse/detection_yolox/process.py | 16 +- .../detection_yolox/tools/convert_weights.py | 64 -- .../warehouse/detection_yolox/tools/dump.py | 51 -- .../warehouse/detection_yolox/visualize.py | 130 ++-- .../warehouse/quality_naive/__init__.py | 2 +- .../warehouse/quality_naive/quality.py | 4 +- .../warehouse/reid_alignedreid/dump.py | 12 +- .../warehouse/reid_alignedreid/lite.py | 24 +- .../warehouse/reid_alignedreid/main.py | 8 +- .../warehouse/reid_alignedreid/model.py | 51 +- .../warehouse/reid_alignedreid/process.py | 5 +- .../warehouse/reid_alignedreid/resnet.py | 268 ++++---- .../examples/warehouse/track_iou/__init__.py | 2 +- .../examples/warehouse/track_iou/track_iou.py | 20 +- flow-python/megflow/command_line.py | 1 - flow-python/megflow/registry.py | 4 - flow-python/setup.py | 3 +- pylintrc | 610 ++++++++++++++++++ 62 files changed, 1295 insertions(+), 1633 deletions(-) rename doc_link_checker.py => ci/doc_link_checker.py (89%) create mode 100755 ci/run_pylint_check.sh create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 flow-python/examples/simple_classification/__init__.py delete mode 100644 flow-python/examples/simple_classification/dump.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/build.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/main.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/__init__.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/darknet.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/network_blocks.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/yolo_fpn.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/yolo_head.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/yolo_pafpn.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/models/yolox.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/tools/convert_weights.py delete mode 100644 flow-python/examples/warehouse/detection_yolox/tools/dump.py create mode 100644 pylintrc diff --git a/Dockerfile b/Dockerfile index e1d19fc..6be865a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,18 +11,20 @@ RUN apt update \ && apt install -y git \ && apt install -y build-essential +ENV CARGO_HOME /cargo +ENV RUSTUP_HOME /rustup RUN curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -o run.sh \ - && chmod a+x run.sh \ - && ./run.sh -y \ - && export PATH=$HOME/.cargo/bin:${PATH} \ - && cargo --version + && chmod a+x run.sh \ + && ./run.sh -y && rm run.sh +ENV PATH $PATH:/cargo/bin +RUN chmod -R 777 /cargo /rustup +COPY ci/cargo-config /cargo/config RUN mkdir -p $HOME/megflow-runspace WORKDIR $HOME/megflow-runspace COPY . $HOME/megflow-runspace/ -RUN PATH=$HOME/.cargo/bin:${PATH} \ - && cargo build \ +RUN cargo build \ && cd flow-python \ && python3 setup.py install --user \ && cd examples \ diff --git a/README.md b/README.md index 47f81d4..7b78e06 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -## MegFlow +## MegFlow | [Documentation](https://megflow.readthedocs.io/zh_CN/latest/#) [![GitHub license](https://img.shields.io/badge/license-apache--2--Clause-brightgreen.svg)](./LICENSE) [![ubuntu](https://img.shields.io/github/workflow/status/MegEngine/MegFlow/ubuntu-x86-cpu?label=ubuntu)](https://github.com/MegEngine/MegFlow/actions/workflows/ubuntu-x86-cpu.yml?query=workflow%3A) [![macos](https://img.shields.io/github/workflow/status/MegEngine/MegFlow/ubuntu-x86-cpu?label=macos)](https://github.com/MegEngine/MegFlow/actions/workflows/macos-x86-cpu.yml?query=workflow%3A) @@ -57,7 +57,6 @@ MegFlow 提供快速视觉应用落地流程,最快 15 分钟搭建起视频 - Python 插件内置有栈协程,不依赖 asyncio - 基础测试工具,支持插件沙盒,用于单测插件 - ## Coming Soon - 进程级别的节点、子图支持 - 插件自动化测试部署 diff --git a/doc_link_checker.py b/ci/doc_link_checker.py similarity index 89% rename from doc_link_checker.py rename to ci/doc_link_checker.py index 493f95c..477bd8f 100644 --- a/doc_link_checker.py +++ b/ci/doc_link_checker.py @@ -1,5 +1,8 @@ +# /bin/python3 + import os import re +import sys pattern = re.compile(r'\[.*?\]\(.*?\)') def analyze_doc(home, path): @@ -13,19 +16,20 @@ def analyze_doc(home, path): start = item.find('(') end = item.find(')') ref = item[start+1: end] - if ref.startswith('http'): + if ref.startswith('http') or ref.startswith('#'): continue fullpath = os.path.join(home, ref) if not os.path.exists(fullpath): problem_list.append(ref) # print(f' {fullpath} in {path} not exist!') else: - continue + continue if len(problem_list) > 0: print(f'{path}:') for item in problem_list: print(f'\t {item}') print('\n') + sys.exit(1) def traverse(_dir): for home, dirs, files in os.walk(_dir): diff --git a/ci/run_pylint_check.sh b/ci/run_pylint_check.sh new file mode 100755 index 0000000..7434b65 --- /dev/null +++ b/ci/run_pylint_check.sh @@ -0,0 +1,6 @@ +python -m pip install pylint==2.5.2 +CHECK_DIR="flow-python/examples/simple_classification flow-python/examples/cat_finder flow-python/examples/electric_bicycle" +pylint $CHECK_DIR || pylint_ret=$? +if [ "$pylint_ret" ]; then + exit $pylint_ret +fi diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..b2e992e --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,21 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..24a804b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,70 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +#sys.path.insert(0, os.path.abspath('.')) + +import sphinx_rtd_theme +from recommonmark.parser import CommonMarkParser +from recommonmark.transform import AutoStructify + + +# -- Project information ----------------------------------------------------- + +project = 'MegFlow' +copyright = '2021, Megvii' +author = 'tpoisonooo' + +# The full version, including alpha/beta/rc tags +release = '' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['recommonmark', 'sphinx_markdown_tables'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'zh' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst', '.md'] diff --git a/docs/how-to-add-my-service/01-single-classification-model.zh.md b/docs/how-to-add-my-service/01-single-classification-model.zh.md index 46d1dbe..fc5bea6 100644 --- a/docs/how-to-add-my-service/01-single-classification-model.zh.md +++ b/docs/how-to-add-my-service/01-single-classification-model.zh.md @@ -4,9 +4,9 @@ ## 准备分类模型 -[MegEngine models]() 有现成的 imagenet 预训模型。这里把模型 dump 成 .mge。 +[MegEngine models](https://github.com/MegEngine/models) 有现成的 imagenet 预训模型。这里把模型 dump 成 .mge。 -新增 [dump.py](../../flow-python/examples/simple_classification/dump.py),按 [1, 3, 224, 224] 尺寸 trace 模型,打开推理优化选项,保存为 `model.mge`。 +新增 [dump.py](https://github.com/MegEngine/Models/blob/master/official/vision/classification/dump.py),按 [1, 3, 224, 224] 尺寸 trace 模型,打开推理优化选项,保存为 `model.mge`。 ```bash $ git clone https://github.com/MegEngine/models @@ -45,6 +45,8 @@ $ cat dump.py $ cat flow-python/examples/simple_classification/lite.py ... def inference(self, mat): + img = self.preprocess(mat, input_size=(224,224), scale_im = False, mean=[103.530, 116.280, 123.675], std=[57.375, 57.120, 58.395]) + # 设置输入 inp_data =self.net.get_io_tensor("data") inp_data.set_data_by_share(img) @@ -108,14 +110,7 @@ $ cat flow-python/examples/simple_classification/classify.py @register(inputs=['inp'], outputs=['out']) class Classify: def __init__(self, name, args): - logger.info("loading Resnet18 Classification...") - self.name = name - - # load model and warmup - self._model = PredictorLite(path=args['path'], device=args['device'], device_id=args['device_id']) - warmup_data = np.zeros((224, 224, 3), dtype=np.uint8) - self._model.inference(warmup_data) - logger.info("Resnet18 loaded.") + ... def exec(self): envelope = self.inp.recv() diff --git a/docs/how-to-build-and-run/build-from-source.zh.md b/docs/how-to-build-and-run/build-from-source.zh.md index 39a702f..2044f53 100644 --- a/docs/how-to-build-and-run/build-from-source.zh.md +++ b/docs/how-to-build-and-run/build-from-source.zh.md @@ -4,7 +4,7 @@ ### 安装 Rust ```bash -$ sudo apt install yasm git build-essential ffmpeg curl +$ sudo apt install curl $ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh ``` @@ -14,6 +14,11 @@ $ cargo --version cargo 1.53.0 (4369396ce 2021-04-27) ``` +如果不成功,提示`Command 'cargo' not found`,可以按照提示加载一下环境变量(重新连接或打开终端也可以): +``` +source $HOME/.cargo/env +``` + > `cargo` 是 Rust 的包管理器兼编译辅助工具。类似 Java maven/go pkg/C++ CMake 的角色,更易使用。 ### 安装 python3.x (推荐 conda) @@ -44,7 +49,7 @@ $ conda activate py38 MegFlow 需要编译 ffmpeg。考虑到 ffmpeg 依赖较多、本身又是常用工具,最简单的办法就是直接装 ffmpeg 把编译依赖装上 ```bash -$ sudo apt install ffmpeg +$ sudo apt install yasm git build-essential ffmpeg $ ffmpeg ffmpeg version 3.4.8... $ sudo apt install clang diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..a3a6131 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,36 @@ +.. MegFlow documentation master file, created by + sphinx-quickstart on Wed Mar 24 22:40:10 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. +Welcome to MegFlow's documentation! +=================================== + + +*Please select a specific version of the document in the lower left corner of the page.* + +.. toctree:: + :maxdepth: 1 + :caption: how to build and run + :name: sec-introduction + + how-to-build-and-run/build-with-docker.zh + how-to-build-and-run/build-from-source.zh + how-to-build-and-run/build-on-win10.zh + how-to-build-and-run/generate-rtsp.zh + +.. toctree:: + :maxdepth: 1 + :caption: how to use + :name: sec-how-to-use + + how-to-add-my-service/01-single-classification-model.zh + how-to-add-my-service/appendix-A-graph-definition + how-to-add-my-service/appendix-B-python-plugin.zh + +.. toctree:: + :maxdepth: 1 + :caption: home + + FAQ.zh + how-to-contribute.zh + how-to-pack-python-whl.zh diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..922152e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..f11fa32 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +sphinx +recommonmark +sphinx_markdown_tables +sphinx_rtd_theme diff --git a/flow-python/examples/cat_finder/det.py b/flow-python/examples/cat_finder/det.py index 95fe1cd..b5a4382 100644 --- a/flow-python/examples/cat_finder/det.py +++ b/flow-python/examples/cat_finder/det.py @@ -9,10 +9,11 @@ #!/usr/bin/env python # coding=utf-8 -from megflow import register -from loguru import logger -from warehouse.detection_yolox import * import numpy as np +from loguru import logger +from megflow import register +from warehouse.detection_yolox import PredictorLite + @register(inputs=['inp'], outputs=['out']) class Detect: @@ -24,14 +25,19 @@ def __init__(self, name, args): self.name = name # load detect model and warmup - self._predictor = PredictorLite(path=args['path'], confthre=args['conf'], nmsthre=args['nms'], test_size=(self._tsize, self._tsize), device=args['device'], device_id=args['device_id'] ) + self._predictor = PredictorLite(path=args['path'], + confthre=args['conf'], + nmsthre=args['nms'], + test_size=(self._tsize, self._tsize), + device=args['device'], + device_id=args['device_id']) warmup_data = np.zeros((224, 224, 3), dtype=np.uint8) self._predictor.inference(warmup_data) logger.info(" YOLOX loaded.") @staticmethod def restrict(val, min, max): - assert(min < max) + assert min < max if val < min: val = min if val > max: @@ -72,7 +78,6 @@ def exec(self): # name = 'frame{0:07d}.jpg'.format(envelope.partial_id) # cv2.imwrite(name, x) - if 1 == self._visualize: + if self._visualize == 1: image['data'] = self._predictor.visual(outputs, data) self.out.send(envelope) - diff --git a/flow-python/examples/cat_finder/redis_proxy.py b/flow-python/examples/cat_finder/redis_proxy.py index 3afe524..b30cac6 100644 --- a/flow-python/examples/cat_finder/redis_proxy.py +++ b/flow-python/examples/cat_finder/redis_proxy.py @@ -9,13 +9,15 @@ #!/usr/bin/env python # coding=utf-8 +import base64 +import binascii import json import redis -import base64 import numpy as np from loguru import logger from megflow import register + @register(inputs=['inp'], outputs=['out']) class RedisProxy: def __init__(self, name, args): @@ -27,58 +29,64 @@ def __init__(self, name, args): ip = args['ip'] port = args['port'] - try: - self._pool = redis.ConnectionPool(host=ip, port=port, decode_responses=False) - except: - logger.error(f'connect redis failed, ip: {ip}, port: {port}') + self._pool = redis.ConnectionPool(host=ip, + port=port, + decode_responses=False) # save feature with highest detection score def save_feature(self, r, name, items): if len(items) == 0: - return + return None score = 0.0 best_item = None - for i in range(len(items)): - if items[i]["score"] > score: - best_item = items[i] - score = items[i]["score"] - - assert(best_item['feature'] is not None) + for item in items: + if item["score"] > score: + best_item = item + score = item["score"] + + assert best_item['feature'] is not None value = base64.b64encode(best_item['feature'].tobytes()) - r.set(f'{self._prefix}{name}', value) + + try: + r.set(f'{self._prefix}{name}', value) + except redis.exceptions.ConnectionError as e: + logger.error(str(e)) return value - + def search_key(self, r, feature): redis_keys = r.keys(self._prefix + '*') for key in redis_keys: if key not in self._db: - value_base64 = r.get(key) - assert(value_base64 is not None) try: - self._db[key] = np.frombuffer(base64.b64decode(value_base64), dtype=np.float32) - except: - logger.error(f'decode feature failed, key {key}') + value_base64 = r.get(key) + assert value_base64 is not None + self._db[key] = np.frombuffer( + base64.b64decode(value_base64), dtype=np.float32) + except redis.exceptions.ConnectionError as e: + logger.error(str(e)) + except binascii.Error as e: + logger.error(f'decode feature failed, key {key}, reason {str(e)}') - assert(feature is not None) - if 0 == len(self._db): + assert feature is not None + if len(self._db) == 0: logger.error("feature db empty") return {} min_dist = float("inf") min_key = '' for k, v in self._db.items(): - dist = np.linalg.norm(v-feature) + dist = np.linalg.norm(v - feature) logger.info(f'key: {k} dist: {dist}') if dist < min_dist: min_key = k min_dist = dist min_key = min_key.decode('utf-8') - name = min_key.replace(self._prefix, '', 1) + name = min_key.replace(self._prefix, '', 1) # send notification - r.lpush(f'notification.cat_finder', f'{name} leaving the room') - return {"name": name, "distance": str(min_dist) } + r.lpush('notification.cat_finder', f'{name} leaving the room') + return {"name": name, "distance": str(min_dist)} def exec(self): envelope = self.inp.recv() @@ -86,10 +94,10 @@ def exec(self): return image = envelope.msg items = image['items'] - assert(type(items) == list) + assert isinstance(items, list) r = redis.Redis(connection_pool=self._pool) - + if self._mode == 'save': self.save_feature(r, image["extra_data"], items) @@ -109,4 +117,3 @@ def exec(self): else: logger.error(f'unknown mode: {self._mode}') self.out.send(envelope) - diff --git a/flow-python/examples/cat_finder/reid_image.py b/flow-python/examples/cat_finder/reid_image.py index 5ac24ae..4205599 100644 --- a/flow-python/examples/cat_finder/reid_image.py +++ b/flow-python/examples/cat_finder/reid_image.py @@ -9,22 +9,23 @@ #!/usr/bin/env python # coding=utf-8 -import megengine as mge import numpy as np from loguru import logger from megflow import register -from warehouse.reid_alignedreid import * -from warehouse.quality_naive import * +from warehouse.reid_alignedreid import PredictorLite + @register(inputs=['inp'], outputs=['out']) class ReIDImage: def __init__(self, name, args): logger.info("loading Image Reid...") self.name = name - + # load ReID model and warmup - self._model = PredictorLite(path=args['path'], device=args['device'], device_id=args['device_id']) + self._model = PredictorLite(path=args['path'], + device=args['device'], + device_id=args['device_id']) warmup_data = np.zeros((224, 224, 3), dtype=np.uint8) self._model.inference(warmup_data) logger.info("Image Reid loaded.") @@ -37,11 +38,12 @@ def exec(self): data = image['data'] items = image['items'] - assert(type(items) == list) + assert isinstance(items, list) for item in items: bbox = item['bbox'] - crop = data[round(bbox[1]): round(bbox[3]), round(bbox[0]): round(bbox[2])] + crop = data[round(bbox[1]):round(bbox[3]), + round(bbox[0]):round(bbox[2])] # cv2.imwrite(f'reid_image_{envelope.partial_id}.jpg', crop) feature = self._model.inference(crop) diff --git a/flow-python/examples/cat_finder/reid_video.py b/flow-python/examples/cat_finder/reid_video.py index 57da218..ae2e523 100644 --- a/flow-python/examples/cat_finder/reid_video.py +++ b/flow-python/examples/cat_finder/reid_video.py @@ -10,12 +10,11 @@ # coding=utf-8 import numpy as np -import megengine as mge from loguru import logger from megflow import register -from warehouse.reid_alignedreid import * -from warehouse.quality_naive import * +from warehouse.reid_alignedreid import PredictorLite + @register(inputs=['inp'], outputs=['out']) class ReIDVideo: @@ -24,7 +23,9 @@ def __init__(self, name, args): self.name = name # load ReID model and warmup - self._model = PredictorLite(path=args['path'], device=args['device'], device_id=args['device_id']) + self._model = PredictorLite(path=args['path'], + device=args['device'], + device_id=args['device_id']) warmup_data = np.zeros((224, 224, 3), dtype=np.uint8) self._model.inference(warmup_data) logger.info(" Video Reid loaded.") @@ -36,7 +37,7 @@ def exec(self): msg = envelope.msg # for crop in image['shaper']: - # cv2.imwrite(f'reid_video_{envelope.partial_id}.jpg', crop) + # cv2.imwrite(f'reid_video_{envelope.partial_id}.jpg', crop) # logger.info(f'envelope id {envelope.partial_id}') msg['features'] = [] diff --git a/flow-python/examples/cat_finder/shaper.py b/flow-python/examples/cat_finder/shaper.py index d093553..3f03262 100644 --- a/flow-python/examples/cat_finder/shaper.py +++ b/flow-python/examples/cat_finder/shaper.py @@ -9,10 +9,10 @@ #!/usr/bin/env python # coding=utf-8 -from megflow import register from loguru import logger +from megflow import register from warehouse.quality_naive import Quality -import cv2 + @register(inputs=['inp'], outputs=['out']) class Shaper: @@ -44,7 +44,7 @@ def expand(self, box, max_w, max_h, ratio): def exec(self): envelope = self.inp.recv() if envelope is None: - logger.info(f'stream shaper finish') + logger.info('stream shaper finish') # last frame, throw out all cropped image for id in self._map: self.out.send(self._map[id]) @@ -59,14 +59,14 @@ def exec(self): box = track['bbox'] if tid not in self._map: self._map[tid] = envelope.repack(msg) - + data = msg['data'] l, t, r, b = self.expand(box, data.shape[1], data.shape[0], 1.1) crop = data[t:b, l:r] - assert(crop is not None) + assert crop is not None quality = Quality.area(crop) - if 'BEST' == self._mode: + if self._mode == 'BEST': tid_msg = self._map[tid].msg # save best image if 'quality' not in tid_msg: @@ -84,4 +84,3 @@ def exec(self): for id in ids: self.out.send(self._map[id]) self._map.pop(id) - diff --git a/flow-python/examples/cat_finder/track.py b/flow-python/examples/cat_finder/track.py index 006e948..023dd78 100644 --- a/flow-python/examples/cat_finder/track.py +++ b/flow-python/examples/cat_finder/track.py @@ -10,23 +10,23 @@ # coding=utf-8 from loguru import logger -from megflow import register, Envelope +from megflow import register from warehouse.track_iou import Tracker -import numpy as np + @register(inputs=['inp'], outputs=['out']) class Track: - def __init__(self, name, args): + def __init__(self, name, _): self.name = name self._tracker = Tracker() def exec(self): envelope = self.inp.recv() if envelope is None: - logger.info(f'stream tracker finish') + logger.info('stream tracker finish') return - + items = envelope.msg['items'] # logger.debug(f'track input: {items}') diff --git a/flow-python/examples/electric_bicycle/det.py b/flow-python/examples/electric_bicycle/det.py index 246d266..416046d 100644 --- a/flow-python/examples/electric_bicycle/det.py +++ b/flow-python/examples/electric_bicycle/det.py @@ -9,11 +9,11 @@ #!/usr/bin/env python # coding=utf-8 -import cv2 import numpy as np -from megflow import register from loguru import logger -from warehouse.detection_memd import * +from megflow import register +from warehouse.detection_memd import load_onnx_model + @register(inputs=['inp'], outputs=['out']) class Detect: @@ -28,13 +28,14 @@ def __init__(self, name, args): # load model and warmup self._model = load_onnx_model(args['path']) warmup_data = np.zeros((256, 256, 3), dtype=np.uint8) - onnx_model.run(self._model, warmup_data, ["elec_cycle"], self._score, self._nms) - + self._model.run(self._model, warmup_data, ["elec_cycle"], self._score, + self._nms) + logger.info(" MEMD loaded.") @staticmethod def restrict(val, min, max): - assert(min < max) + assert min < max if val < min: val = min if val > max: @@ -52,7 +53,8 @@ def exec(self): if process: data = image['data'] - outputs = onnx_model.run(self._model, data, ["elec_cycle"], self._score, self._nms) + outputs = self._model.run(self._model, data, ["elec_cycle"], + self._score, self._nms) items = [] (max_h, max_w, _) = data.shape @@ -70,4 +72,3 @@ def exec(self): image['items'] = items self.out.send(envelope) - diff --git a/flow-python/examples/electric_bicycle/redis_proxy.py b/flow-python/examples/electric_bicycle/redis_proxy.py index 0f3e8fd..6baa1a2 100644 --- a/flow-python/examples/electric_bicycle/redis_proxy.py +++ b/flow-python/examples/electric_bicycle/redis_proxy.py @@ -9,13 +9,11 @@ #!/usr/bin/env python # coding=utf-8 -import json import redis -import base64 -import numpy as np from loguru import logger from megflow import register + @register(inputs=['inp'], outputs=['out']) class RedisProxy: def __init__(self, name, args): @@ -27,11 +25,10 @@ def __init__(self, name, args): ip = args['ip'] port = args['port'] - try: - self._pool = redis.ConnectionPool(host=ip, port=port, decode_responses=False) - logger.info('redis pool initialized.') - except: - logger.error(f'connect redis failed, ip: {ip}, port: {port}') + self._pool = redis.ConnectionPool(host=ip, + port=port, + decode_responses=False) + logger.info('redis pool initialized.') def exec(self): @@ -40,7 +37,7 @@ def exec(self): return msg = envelope.msg crops = msg['shaper'] - assert(type(crops) == list) + assert isinstance(crops, list) if len(crops) > 0: try: @@ -49,5 +46,5 @@ def exec(self): logger.info('alert {}'.format(alert)) r.lpush(self._key, alert) self.out.send(envelope.repack(alert)) - except: - logger.error() + except redis.exceptions.ConnectionError as e: + logger.error(str(e)) diff --git a/flow-python/examples/electric_bicycle/shaper.py b/flow-python/examples/electric_bicycle/shaper.py index dd93a65..defc6aa 100644 --- a/flow-python/examples/electric_bicycle/shaper.py +++ b/flow-python/examples/electric_bicycle/shaper.py @@ -10,9 +10,7 @@ # coding=utf-8 from megflow import register -from loguru import logger -from warehouse.quality_naive import Quality -import cv2 + @register(inputs=['inp'], outputs=['out']) class Shaper: @@ -21,7 +19,7 @@ def __init__(self, name, args): self._mode = args['mode'] self._map = dict() - self.idx=0 + self.idx = 0 def expand(self, box, max_w, max_h, ratio): l = box[0] @@ -51,7 +49,7 @@ def exec(self): msg = envelope.msg - # push the first + # push the first msg['shaper'] = [] for track in msg['tracks']: tid = track['tid'] @@ -60,7 +58,8 @@ def exec(self): self._map[tid] = dict() data = msg['data'] - l, t, r, b = self.expand(box, data.shape[1], data.shape[0], 1.1) + l, t, r, b = self.expand(box, data.shape[1], data.shape[0], + 1.1) crop = data[t:b, l:r] msg['shaper'].append(crop) # cv2.imwrite(f'shaper_{envelope.partial_id}.jpg', crop) diff --git a/flow-python/examples/electric_bicycle/track.py b/flow-python/examples/electric_bicycle/track.py index 38811fa..8ef8a90 100644 --- a/flow-python/examples/electric_bicycle/track.py +++ b/flow-python/examples/electric_bicycle/track.py @@ -9,16 +9,14 @@ #!/usr/bin/env python # coding=utf-8 -from loguru import logger -from megflow import register, Envelope +from megflow import register from warehouse.track_iou import Tracker -import numpy as np @register(inputs=['inp'], outputs=['out']) class Track: - def __init__(self, name, args): + def __init__(self, name, _): self.name = name self._tracker = Tracker() diff --git a/flow-python/examples/logical_test/__init__.py b/flow-python/examples/logical_test/__init__.py index 9a29ad3..f57558f 100644 --- a/flow-python/examples/logical_test/__init__.py +++ b/flow-python/examples/logical_test/__init__.py @@ -8,4 +8,3 @@ #!/usr/bin/env python # coding=utf-8 - diff --git a/flow-python/examples/logical_test/buffer.py b/flow-python/examples/logical_test/buffer.py index e772deb..2f4ca8f 100644 --- a/flow-python/examples/logical_test/buffer.py +++ b/flow-python/examples/logical_test/buffer.py @@ -3,6 +3,7 @@ from megflow import res_register + @res_register() class Buffer: def __init__(self, name, args): diff --git a/flow-python/examples/logical_test/printer.py b/flow-python/examples/logical_test/printer.py index 27858f4..5177b89 100644 --- a/flow-python/examples/logical_test/printer.py +++ b/flow-python/examples/logical_test/printer.py @@ -12,13 +12,14 @@ instance_id = 0 + @register('Printer', inputs=['inp']) class Node: def __init__(self, name, args): global instance_id self.id = instance_id instance_id += 1 - + def exec(self): envelope = self.inp.recv() if envelope is not None: @@ -26,5 +27,6 @@ def exec(self): pbuf = self.parent_buf.get() buf = self.buf.get() - print('Printer[{}] get msg: {}, buf(global, parent, local): ({}, {}, {})'.format(self.id, envelope.msg['message'], gbuf, pbuf, buf)) - + print( + 'Printer[{}] get msg: {}, buf(global, parent, local): ({}, {}, {})' + .format(self.id, envelope.msg['message'], gbuf, pbuf, buf)) diff --git a/flow-python/examples/logical_test/process.py b/flow-python/examples/logical_test/process.py index 2088282..f1b5c9c 100644 --- a/flow-python/examples/logical_test/process.py +++ b/flow-python/examples/logical_test/process.py @@ -12,6 +12,7 @@ import multiprocessing as mp from multiprocessing import Process, Pipe + def repeat(n, s, r): while True: envelope = r.recv() @@ -19,7 +20,8 @@ def repeat(n, s, r): break for i in range(n): msg = {} - msg['message'] = "a message[{}] repeat {} by process node".format(envelope.msg['message'], i) + msg['message'] = "a message[{}] repeat {} by process node".format( + envelope.msg['message'], i) s.send(envelope.repack(msg)) @@ -36,12 +38,10 @@ def __init__(self, name, args): self.p = Process(target=repeat, args=(10, s2, r1)) self.p.start() - def __del__(self): self.send.send(None) self.p.join() - def exec(self): envelope = self.inp.recv() @@ -56,4 +56,3 @@ def exec(self): for i in range(10): envelope = self.recv.recv() self.out.send(envelope) - diff --git a/flow-python/examples/logical_test/source.py b/flow-python/examples/logical_test/source.py index eb91962..8e257fd 100644 --- a/flow-python/examples/logical_test/source.py +++ b/flow-python/examples/logical_test/source.py @@ -10,6 +10,7 @@ # coding=utf-8 from megflow import register, Envelope, sleep + @register(outputs=['out']) class Source: def __init__(self, name, args): @@ -29,4 +30,3 @@ def exec(self): envelope = Envelope.pack(None) envelope.to_addr = i self.out.send(envelope) - diff --git a/flow-python/examples/simple_classification/__init__.py b/flow-python/examples/simple_classification/__init__.py new file mode 100644 index 0000000..f57558f --- /dev/null +++ b/flow-python/examples/simple_classification/__init__.py @@ -0,0 +1,10 @@ +# MegFlow is Licensed under the Apache License, Version 2.0 (the "License") +# +# Copyright (c) 2019-2021 Megvii Inc. All rights reserved. +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +#!/usr/bin/env python +# coding=utf-8 diff --git a/flow-python/examples/simple_classification/classify.py b/flow-python/examples/simple_classification/classify.py index 8b61c8b..b33c547 100644 --- a/flow-python/examples/simple_classification/classify.py +++ b/flow-python/examples/simple_classification/classify.py @@ -9,21 +9,24 @@ #!/usr/bin/env python # coding=utf-8 +import json import numpy as np from loguru import logger from megflow import register -import json -from .lite import * +from .lite import PredictorLite + @register(inputs=['inp'], outputs=['out']) class Classify: - def __init__(self, name, args): + def __init__(self, name, arg): logger.info("loading Resnet18 Classification...") self.name = name - + # load ReID model and warmup - self._model = PredictorLite(path=args['path'], device=args['device'], device_id=args['device_id']) + self._model = PredictorLite(path=arg['path'], + device=arg['device'], + device_id=arg['device_id']) warmup_data = np.zeros((224, 224, 3), dtype=np.uint8) self._model.inference(warmup_data) logger.info("Resnet18 loaded.") diff --git a/flow-python/examples/simple_classification/dump.py b/flow-python/examples/simple_classification/dump.py deleted file mode 100644 index 16ec1a8..0000000 --- a/flow-python/examples/simple_classification/dump.py +++ /dev/null @@ -1,29 +0,0 @@ -import model as resnet_model -import megengine as mge -from megengine import jit -import numpy as np - -def dump_static_graph(model, graph_name="model.mge"): - model.eval() - - data = mge.Tensor(np.random.random((1, 3, 224, 224))) - - @jit.trace(capture_as_const=True) - def pred_func(data): - outputs = model(data) - return outputs - - pred_func(data) - pred_func.dump( - graph_name, - arg_names=["data"], - optimize_for_inference=True, - enable_fuse_conv_bias_nonlinearity=True, - ) - -def main(): - model = resnet_model.__dict__['resnet18'](pretrained=True) - dump_static_graph(model) - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/flow-python/examples/simple_classification/lite.py b/flow-python/examples/simple_classification/lite.py index 8983701..034a7c4 100644 --- a/flow-python/examples/simple_classification/lite.py +++ b/flow-python/examples/simple_classification/lite.py @@ -2,23 +2,25 @@ # -*- coding:utf-8 -*- # Copyright (c) Megvii, Inc. and its affiliates. +import argparse import cv2 +import numpy as np import megenginelite as mgelite from loguru import logger -import numpy as np -class PredictorLite(object): + +class PredictorLite: def __init__( self, path, device="gpu", device_id=0, ): - + if "gpu" in device.lower(): - device_type=mgelite.LiteDeviceType.LITE_CUDA + device_type = mgelite.LiteDeviceType.LITE_CUDA else: - device_type=mgelite.LiteDeviceType.LITE_CPU + device_type = mgelite.LiteDeviceType.LITE_CPU net_config = mgelite.LiteConfig(device_type=device_type) ios = mgelite.LiteNetworkIO() @@ -30,7 +32,13 @@ def __init__( self.net = net - def preprocess(self, image, input_size, scale_im, mean, std, swap=(2, 0, 1)): + def preprocess(self, + image, + input_size, + scale_im, + mean, + std, + swap=(2, 0, 1)): if image is None: logger.error("image is None") return image @@ -48,12 +56,16 @@ def preprocess(self, image, input_size, scale_im, mean, std, swap=(2, 0, 1)): return image def inference(self, mat): - img = self.preprocess(mat, input_size=(224,224), scale_im = False, mean=[103.530, 116.280, 123.675], std=[57.375, 57.120, 58.395]) + img = self.preprocess(mat, + input_size=(224, 224), + scale_im=False, + mean=[103.530, 116.280, 123.675], + std=[57.375, 57.120, 58.395]) # build input tensor - inp_data =self.net.get_io_tensor("data") + inp_data = self.net.get_io_tensor("data") inp_data.set_data_by_share(img) - + # forward self.net.forward() self.net.wait() @@ -63,16 +75,21 @@ def inference(self, mat): output = self.net.get_io_tensor(output_keys[0]).to_numpy() return np.argmax(output[0]) + def make_parser(): - import argparse parser = argparse.ArgumentParser("Classification Demo!") - parser.add_argument("--path", default="./test.png", help="path to images or video") - parser.add_argument("--model", default=None, type=str, help=".mge for eval") + parser.add_argument("--path", + default="./test.png", + help="path to images or video") + parser.add_argument("--model", + default=None, + type=str, + help=".mge for eval") return parser + if __name__ == "__main__": args = make_parser().parse_args() predictor = PredictorLite(args.model) - img = cv2.imread(args.path) - output = predictor.inference(img) - logger.info(f'{output}') + out = predictor.inference(cv2.imread(args.path)) + logger.info(f'{out}') diff --git a/flow-python/examples/utils.py b/flow-python/examples/utils.py index 7e2c720..008d03e 100644 --- a/flow-python/examples/utils.py +++ b/flow-python/examples/utils.py @@ -33,6 +33,7 @@ def is_overlap(rect1: np.array, rect2: np.array, iou_thr: float) -> bool: ov = iou(rect1, rect2) return ov >= iou_thr + def shrink_rect(rect): x1, y1, x2, y2 = rect @@ -210,4 +211,4 @@ def nms(boxes, scores, iou_threshold=0.3): if len(rects) != right + 1: rects = rects[:right + 1] idx += 1 - return [x[5] for x in rects] \ No newline at end of file + return [x[5] for x in rects] diff --git a/flow-python/examples/warehouse/detection_memd/main.py b/flow-python/examples/warehouse/detection_memd/main.py index ef543b1..c8e4bba 100644 --- a/flow-python/examples/warehouse/detection_memd/main.py +++ b/flow-python/examples/warehouse/detection_memd/main.py @@ -9,7 +9,7 @@ #!/usr/bin/env python # coding=utf-8 -import sys +import sys import json import argparse @@ -19,6 +19,7 @@ sys.path.append('.') from .onnx_model import load_onnx_model, run + def inference(detector_path, img, output_path): class_names = ["elec_cycle"] onnx_session = load_onnx_model(detector_path) @@ -58,21 +59,23 @@ def inference(detector_path, img, output_path): return box_num + def parse_args(): parser = argparse.ArgumentParser("Electric Moped Detector") - parser.add_argument( - "--detector", default="./models/model.onnx", help="The path to onnx detector. " - ) - parser.add_argument( - "--input-img", default="./demo/input.jpg", help="The path to demo image to inference. " - ) - parser.add_argument( - "--output-path", default="./demo/output.jpg", help="The path of output images. " - ) + parser.add_argument("--detector", + default="./models/model.onnx", + help="The path to onnx detector. ") + parser.add_argument("--input-img", + default="./demo/input.jpg", + help="The path to demo image to inference. ") + parser.add_argument("--output-path", + default="./demo/output.jpg", + help="The path of output images. ") args = parser.parse_args() return args + def main(): args = parse_args() img = cv2.imread(args.input_img) diff --git a/flow-python/examples/warehouse/detection_memd/onnx_model.py b/flow-python/examples/warehouse/detection_memd/onnx_model.py index f5c36bf..7117ef7 100644 --- a/flow-python/examples/warehouse/detection_memd/onnx_model.py +++ b/flow-python/examples/warehouse/detection_memd/onnx_model.py @@ -11,19 +11,22 @@ from loguru import logger import onnxruntime -import cv2 -import numpy as np +import cv2 +import numpy as np -def load_onnx_model(onnx_path): + +def load_onnx_model(onnx_path): onnx_session = onnxruntime.InferenceSession(onnx_path) return onnx_session + def get_output_name(onnx_session): output_name = [] for node in onnx_session.get_outputs(): output_name.append(node.name) return output_name + def transform(image, target_shape=(960, 960)): image_height, image_width, _ = image.shape ratio_h = target_shape[1] * 1.0 / image_height @@ -31,6 +34,7 @@ def transform(image, target_shape=(960, 960)): image = cv2.resize(image, target_shape) return image, ratio_h, ratio_w + def is_overlap_v1(rect1, rect2, iou_threshold): xx1 = max(rect1[0], rect2[0]) yy1 = max(rect1[1], rect2[1]) @@ -44,6 +48,7 @@ def is_overlap_v1(rect1, rect2, iou_threshold): ov = i / u return ov >= iou_threshold + def raw_nms(boxes, iou_threshold=0.3): if 0 == len(boxes): return [] @@ -65,7 +70,8 @@ def raw_nms(boxes, iou_threshold=0.3): return [x[5] for i, x in enumerate(rects) if rect_valid[i]] -def onnx_inference(onnx_session, num_classes, image, topk_candidates=1000): + +def onnx_inference(onnx_session, num_classes, image, topk_candidates=1000): output_name = get_output_name(onnx_session) @@ -73,9 +79,7 @@ def onnx_inference(onnx_session, num_classes, image, topk_candidates=1000): image = image.astype(np.float32) image = np.expand_dims(image.transpose((2, 0, 1)), 0) - scores, boxes = onnx_session.run( - output_name, input_feed={"input": image} - ) + scores, boxes = onnx_session.run(output_name, input_feed={"input": image}) keep = scores.max(axis=1) > 0.1 scores = scores[keep] @@ -102,6 +106,7 @@ def onnx_inference(onnx_session, num_classes, image, topk_candidates=1000): return boxes, scores, classes + def run(onnx_session, image, class_names, score_thrs, nms_thr=0.6): num_classes = len(class_names) import time @@ -119,8 +124,7 @@ def run(onnx_session, image, class_names, score_thrs, nms_thr=0.6): keep = scores > np.maximum(score_thrs[cls_idxs], 0.2) pred_boxes = np.concatenate( - [boxes, scores[:, np.newaxis], cls_idxs[:, np.newaxis]], axis=1 - ) + [boxes, scores[:, np.newaxis], cls_idxs[:, np.newaxis]], axis=1) pred_boxes = pred_boxes[keep] all_boxes = [] diff --git a/flow-python/examples/warehouse/detection_yolox/__init__.py b/flow-python/examples/warehouse/detection_yolox/__init__.py index 796cb51..dce1601 100644 --- a/flow-python/examples/warehouse/detection_yolox/__init__.py +++ b/flow-python/examples/warehouse/detection_yolox/__init__.py @@ -9,9 +9,4 @@ #!/usr/bin/env python # coding=utf-8 -# from .coco_classes import COCO_CLASSES -# from .process import postprocess, preprocess -# from .models.yolo_fpn import YOLOFPN -# from .build import build_and_load -# from .main import Predictor from .lite import PredictorLite diff --git a/flow-python/examples/warehouse/detection_yolox/build.py b/flow-python/examples/warehouse/detection_yolox/build.py deleted file mode 100644 index ca3b29b..0000000 --- a/flow-python/examples/warehouse/detection_yolox/build.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- - -import megengine as mge -import megengine.module as M -from megengine import jit - -from .models.yolo_fpn import YOLOFPN -from .models.yolo_head import YOLOXHead -from .models.yolo_pafpn import YOLOPAFPN -from .models.yolox import YOLOX - - -def build_yolox(name="yolox-s"): - num_classes = 80 - - # value meaning: depth, width - param_dict = { - "yolox-nano": (0.33, 0.25), - "yolox-tiny": (0.33, 0.375), - "yolox-s": (0.33, 0.50), - "yolox-m": (0.67, 0.75), - "yolox-l": (1.0, 1.0), - "yolox-x": (1.33, 1.25), - } - if name == "yolov3": - depth = 1.0 - width = 1.0 - backbone = YOLOFPN() - head = YOLOXHead(num_classes, width, in_channels=[128, 256, 512], act="lrelu") - model = YOLOX(backbone, head) - else: - assert name in param_dict - kwargs = {} - depth, width = param_dict[name] - if name == "yolox-nano": - kwargs["depthwise"] = True - in_channels = [256, 512, 1024] - backbone = YOLOPAFPN(depth, width, in_channels=in_channels, **kwargs) - head = YOLOXHead(num_classes, width, in_channels=in_channels, **kwargs) - model = YOLOX(backbone, head) - - for m in model.modules(): - if isinstance(m, M.BatchNorm2d): - m.eps = 1e-3 - - return model - - -def build_and_load(weight_file, name="yolox-s"): - model = build_yolox(name) - model_weights = mge.load(weight_file) - model.load_state_dict(model_weights, strict=False) - return model diff --git a/flow-python/examples/warehouse/detection_yolox/lite.py b/flow-python/examples/warehouse/detection_yolox/lite.py index 39d3d51..bf38653 100644 --- a/flow-python/examples/warehouse/detection_yolox/lite.py +++ b/flow-python/examples/warehouse/detection_yolox/lite.py @@ -21,13 +21,29 @@ def make_parser(): parser = argparse.ArgumentParser("YOLOX Demo!") - parser.add_argument("-n", "--name", type=str, default="yolox-s", help="model name") - parser.add_argument("--path", default="./test.png", help="path to images or video") - - parser.add_argument("-c", "--ckpt", default=None, type=str, help="ckpt for eval") + parser.add_argument("-n", + "--name", + type=str, + default="yolox-s", + help="model name") + parser.add_argument("--path", + default="./test.png", + help="path to images or video") + + parser.add_argument("-c", + "--ckpt", + default=None, + type=str, + help="ckpt for eval") parser.add_argument("--conf", default=None, type=float, help="test conf") - parser.add_argument("--nms", default=None, type=float, help="test nms threshold") - parser.add_argument("--tsize", default=None, type=int, help="test img size") + parser.add_argument("--nms", + default=None, + type=float, + help="test nms threshold") + parser.add_argument("--tsize", + default=None, + type=int, + help="test img size") return parser @@ -55,11 +71,11 @@ def __init__( device="gpu", device_id=0, ): - + if "gpu" in device.lower(): - device_type=mgelite.LiteDeviceType.LITE_CUDA + device_type = mgelite.LiteDeviceType.LITE_CUDA else: - device_type=mgelite.LiteDeviceType.LITE_CPU + device_type = mgelite.LiteDeviceType.LITE_CPU net_config = mgelite.LiteConfig(device_type=device_type) ios = mgelite.LiteNetworkIO() @@ -81,7 +97,6 @@ def __init__( self.rgb_means = (0.485, 0.456, 0.406) self.std = (0.229, 0.224, 0.225) - def lite_postprocess(self, outputs, img_size, p6=False): grids = [] expanded_strides = [] @@ -108,9 +123,8 @@ def lite_postprocess(self, outputs, img_size, p6=False): return outputs - def restrict(self, val, min, max): - assert(min < max) + assert (min < max) if val < min: val = min if val > max: @@ -126,10 +140,10 @@ def inference(self, img): img, ratio = preprocess(img, self.test_size, self.rgb_means, self.std) # build input tensor - data = img[np.newaxis,:] - inp_data =self.net.get_io_tensor("data") + data = img[np.newaxis, :] + inp_data = self.net.get_io_tensor("data") inp_data.set_data_by_copy(data) - + # forward self.net.forward() self.net.wait() @@ -139,15 +153,16 @@ def inference(self, img): outputs = self.net.get_io_tensor(output_keys[0]).to_numpy() outputs = self.lite_postprocess(outputs[0], list(self.test_size)) - outputs = outputs[np.newaxis,:] + outputs = outputs[np.newaxis, :] output = mge.tensor(outputs) - ret = postprocess(output, self.num_classes, self.confthre, self.nmsthre) + ret = postprocess(output, self.num_classes, self.confthre, + self.nmsthre) if ret is None: return None bboxes = ret.copy() - for i in range(bboxes.shape[0]): - bbox = bboxes[i][0:4]/ratio + for i in range(bboxes.shape[0]): + bbox = bboxes[i][0:4] / ratio bbox[0] = self.restrict(bbox[0], 0, max_w) bbox[1] = self.restrict(bbox[1], 0, max_h) bbox[2] = self.restrict(bbox[2], bbox[0], max_w) @@ -184,15 +199,17 @@ def main(args): if args.tsize is not None: test_size = (args.tsize, args.tsize) - predictor = PredictorLite(args.ckpt, confthre, nmsthre, test_size, COCO_CLASSES, None, None, "gpu", 0) + predictor = PredictorLite(args.ckpt, confthre, nmsthre, test_size, + COCO_CLASSES, None, None, "gpu", 0) frame = cv2.imread(args.path) outputs = predictor.inference(frame) result_frame = predictor.visual(outputs, frame) - filename = os.path.join(dirname, "out.jpg") + filename = os.path.join(dirname, "out.jpg") cv2.imwrite(filename, result_frame) + if __name__ == "__main__": args = make_parser().parse_args() main(args) diff --git a/flow-python/examples/warehouse/detection_yolox/main.py b/flow-python/examples/warehouse/detection_yolox/main.py deleted file mode 100644 index f016824..0000000 --- a/flow-python/examples/warehouse/detection_yolox/main.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -# Copyright (c) Megvii, Inc. and its affiliates. - -import argparse -import os -import time - -import cv2 -import megengine as mge -import megengine.functional as F -from loguru import logger - -from .coco_classes import COCO_CLASSES -from .process import postprocess, preprocess -from .visualize import vis -from .build import build_and_load - -IMAGE_EXT = [".jpg", ".jpeg", ".webp", ".bmp", ".png"] - - -def make_parser(): - parser = argparse.ArgumentParser("YOLOX Demo!") - parser.add_argument( - "demo", default="image", help="demo type, eg. image, video and webcam" - ) - parser.add_argument("-n", "--name", type=str, default="yolox-s", help="model name") - parser.add_argument("--path", default="./test.png", help="path to images or video") - parser.add_argument("--camid", type=int, default=0, help="webcam demo camera id") - parser.add_argument( - "--save_result", - action="store_true", - help="whether to save the inference result of image/video", - ) - - parser.add_argument("-c", "--ckpt", default=None, type=str, help="ckpt for eval") - parser.add_argument("--conf", default=None, type=float, help="test conf") - parser.add_argument("--nms", default=None, type=float, help="test nms threshold") - parser.add_argument("--tsize", default=None, type=int, help="test img size") - return parser - - -def get_image_list(path): - image_names = [] - for maindir, subdir, file_name_list in os.walk(path): - for filename in file_name_list: - apath = os.path.join(maindir, filename) - ext = os.path.splitext(apath)[1] - if ext in IMAGE_EXT: - image_names.append(apath) - return image_names - - -class Predictor(object): - def __init__( - self, - model, - confthre=0.01, - nmsthre=0.65, - test_size=(640, 640), - cls_names=COCO_CLASSES, - trt_file=None, - decoder=None, - ): - self.model = model - self.cls_names = cls_names - self.decoder = decoder - self.num_classes = 80 - self.confthre = confthre - self.nmsthre = nmsthre - self.test_size = test_size - self.rgb_means = (0.485, 0.456, 0.406) - self.std = (0.229, 0.224, 0.225) - - def inference(self, img): - img_info = {"id": 0} - if isinstance(img, str): - img_info["file_name"] = os.path.basename(img) - img = cv2.imread(img) - if img is None: - raise ValueError("test image path is invalid!") - else: - img_info["file_name"] = None - - height, width = img.shape[:2] - img_info["height"] = height - img_info["width"] = width - img_info["raw_img"] = img - - img, ratio = preprocess(img, self.test_size, self.rgb_means, self.std) - img_info["ratio"] = ratio - img = F.expand_dims(mge.tensor(img), 0) - - t0 = time.time() - outputs = self.model(img) - - outputs = postprocess(outputs, self.num_classes, self.confthre, self.nmsthre) - logger.debug("YOLOX infer time: {:.4f}s".format(time.time() - t0)) - return outputs, img_info - - def visual(self, output, img_info, cls_conf=0.35): - ratio = img_info["ratio"] - img = img_info["raw_img"] - if output is None: - return img - - # preprocessing: resize - bboxes = output[:, 0:4] / ratio - - cls = output[:, 6] - scores = output[:, 4] * output[:, 5] - - vis_res = vis(img, bboxes, scores, cls, cls_conf, self.cls_names) - return vis_res - - -def image_demo(predictor, vis_folder, path, current_time, save_result): - if os.path.isdir(path): - files = get_image_list(path) - else: - files = [path] - files.sort() - for image_name in files: - outputs, img_info = predictor.inference(image_name) - result_image = predictor.visual(outputs, img_info) - if save_result: - save_folder = os.path.join( - vis_folder, time.strftime("%Y_%m_%d_%H_%M_%S", current_time) - ) - os.makedirs(save_folder, exist_ok=True) - save_file_name = os.path.join(save_folder, os.path.basename(image_name)) - logger.info("Saving detection result in {}".format(save_file_name)) - cv2.imwrite(save_file_name, result_image) - ch = cv2.waitKey(0) - if ch == 27 or ch == ord("q") or ch == ord("Q"): - break - - -def imageflow_demo(predictor, vis_folder, current_time, args): - cap = cv2.VideoCapture(args.path if args.demo == "video" else args.camid) - width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # float - height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # float - fps = cap.get(cv2.CAP_PROP_FPS) - save_folder = os.path.join( - vis_folder, time.strftime("%Y_%m_%d_%H_%M_%S", current_time) - ) - os.makedirs(save_folder, exist_ok=True) - if args.demo == "video": - save_path = os.path.join(save_folder, args.path.split("/")[-1]) - else: - save_path = os.path.join(save_folder, "camera.mp4") - logger.info(f"video save_path is {save_path}") - vid_writer = cv2.VideoWriter( - save_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (int(width), int(height)) - ) - while True: - ret_val, frame = cap.read() - if ret_val: - outputs, img_info = predictor.inference(frame) - result_frame = predictor.visual(outputs, img_info) - if args.save_result: - vid_writer.write(result_frame) - ch = cv2.waitKey(1) - if ch == 27 or ch == ord("q") or ch == ord("Q"): - break - else: - break - - -def main(args): - - file_name = os.path.join("./yolox_outputs", args.name) - os.makedirs(file_name, exist_ok=True) - - if args.save_result: - vis_folder = os.path.join(file_name, "vis_res") - os.makedirs(vis_folder, exist_ok=True) - - confthre = 0.01 - nmsthre = 0.65 - test_size = (640, 640) - if args.conf is not None: - confthre = args.conf - if args.nms is not None: - nmsthre = args.nms - if args.tsize is not None: - test_size = (args.tsize, args.tsize) - - model = build_and_load(args.ckpt, name=args.name) - model.eval() - - predictor = Predictor(model, confthre, nmsthre, test_size, COCO_CLASSES, None, None) - current_time = time.localtime() - if args.demo == "image": - image_demo(predictor, vis_folder, args.path, current_time, args.save_result) - elif args.demo == "video" or args.demo == "webcam": - imageflow_demo(predictor, vis_folder, current_time, args) - - -if __name__ == "__main__": - args = make_parser().parse_args() - main(args) diff --git a/flow-python/examples/warehouse/detection_yolox/models/__init__.py b/flow-python/examples/warehouse/detection_yolox/models/__init__.py deleted file mode 100644 index 7c0902b..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -from .darknet import CSPDarknet, Darknet -from .yolo_fpn import YOLOFPN -from .yolo_head import YOLOXHead -from .yolo_pafpn import YOLOPAFPN -from .yolox import YOLOX diff --git a/flow-python/examples/warehouse/detection_yolox/models/darknet.py b/flow-python/examples/warehouse/detection_yolox/models/darknet.py deleted file mode 100644 index 61a3d8b..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/darknet.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.module as M - -from .network_blocks import BaseConv, CSPLayer, DWConv, Focus, ResLayer, SPPBottleneck - - -class Darknet(M.Module): - # number of blocks from dark2 to dark5. - depth2blocks = {21: [1, 2, 2, 1], 53: [2, 8, 8, 4]} - - def __init__( - self, depth, in_channels=3, stem_out_channels=32, out_features=("dark3", "dark4", "dark5"), - ): - """ - Args: - depth (int): depth of darknet used in model, usually use [21, 53] for this param. - in_channels (int): number of input channels, for example, use 3 for RGB image. - stem_out_channels (int): number of output chanels of darknet stem. - It decides channels of darknet layer2 to layer5. - out_features (Tuple[str]): desired output layer name. - """ - super().__init__() - assert out_features, "please provide output features of Darknet" - self.out_features = out_features - self.stem = M.Sequential( - BaseConv(in_channels, stem_out_channels, ksize=3, stride=1, act="lrelu"), - *self.make_group_layer(stem_out_channels, num_blocks=1, stride=2), - ) - in_channels = stem_out_channels * 2 # 64 - - num_blocks = Darknet.depth2blocks[depth] - # create darknet with `stem_out_channels` and `num_blocks` layers. - # to make model structure more clear, we don't use `for` statement in python. - self.dark2 = M.Sequential(*self.make_group_layer(in_channels, num_blocks[0], stride=2)) - in_channels *= 2 # 128 - self.dark3 = M.Sequential(*self.make_group_layer(in_channels, num_blocks[1], stride=2)) - in_channels *= 2 # 256 - self.dark4 = M.Sequential(*self.make_group_layer(in_channels, num_blocks[2], stride=2)) - in_channels *= 2 # 512 - - self.dark5 = M.Sequential( - *self.make_group_layer(in_channels, num_blocks[3], stride=2), - *self.make_spp_block([in_channels, in_channels * 2], in_channels * 2), - ) - - def make_group_layer(self, in_channels: int, num_blocks: int, stride: int = 1): - "starts with conv layer then has `num_blocks` `ResLayer`" - return [ - BaseConv(in_channels, in_channels * 2, ksize=3, stride=stride, act="lrelu"), - *[(ResLayer(in_channels * 2)) for _ in range(num_blocks)] - ] - - def make_spp_block(self, filters_list, in_filters): - m = M.Sequential( - *[ - BaseConv(in_filters, filters_list[0], 1, stride=1, act="lrelu"), - BaseConv(filters_list[0], filters_list[1], 3, stride=1, act="lrelu"), - SPPBottleneck( - in_channels=filters_list[1], - out_channels=filters_list[0], - activation="lrelu" - ), - BaseConv(filters_list[0], filters_list[1], 3, stride=1, act="lrelu"), - BaseConv(filters_list[1], filters_list[0], 1, stride=1, act="lrelu"), - ] - ) - return m - - def forward(self, x): - outputs = {} - x = self.stem(x) - outputs["stem"] = x - x = self.dark2(x) - outputs["dark2"] = x - x = self.dark3(x) - outputs["dark3"] = x - x = self.dark4(x) - outputs["dark4"] = x - x = self.dark5(x) - outputs["dark5"] = x - return {k: v for k, v in outputs.items() if k in self.out_features} - - -class CSPDarknet(M.Module): - - def __init__( - self, dep_mul, wid_mul, - out_features=("dark3", "dark4", "dark5"), - depthwise=False, act="silu", - ): - super().__init__() - assert out_features, "please provide output features of Darknet" - self.out_features = out_features - Conv = DWConv if depthwise else BaseConv - - base_channels = int(wid_mul * 64) # 64 - base_depth = max(round(dep_mul * 3), 1) # 3 - - # stem - self.stem = Focus(3, base_channels, ksize=3, act=act) - - # dark2 - self.dark2 = M.Sequential( - Conv(base_channels, base_channels * 2, 3, 2, act=act), - CSPLayer( - base_channels * 2, base_channels * 2, - n=base_depth, depthwise=depthwise, act=act - ), - ) - - # dark3 - self.dark3 = M.Sequential( - Conv(base_channels * 2, base_channels * 4, 3, 2, act=act), - CSPLayer( - base_channels * 4, base_channels * 4, - n=base_depth * 3, depthwise=depthwise, act=act, - ), - ) - - # dark4 - self.dark4 = M.Sequential( - Conv(base_channels * 4, base_channels * 8, 3, 2, act=act), - CSPLayer( - base_channels * 8, base_channels * 8, - n=base_depth * 3, depthwise=depthwise, act=act, - ), - ) - - # dark5 - self.dark5 = M.Sequential( - Conv(base_channels * 8, base_channels * 16, 3, 2, act=act), - SPPBottleneck(base_channels * 16, base_channels * 16, activation=act), - CSPLayer( - base_channels * 16, base_channels * 16, n=base_depth, - shortcut=False, depthwise=depthwise, act=act, - ), - ) - - def forward(self, x): - outputs = {} - x = self.stem(x) - outputs["stem"] = x - x = self.dark2(x) - outputs["dark2"] = x - x = self.dark3(x) - outputs["dark3"] = x - x = self.dark4(x) - outputs["dark4"] = x - x = self.dark5(x) - outputs["dark5"] = x - return {k: v for k, v in outputs.items() if k in self.out_features} diff --git a/flow-python/examples/warehouse/detection_yolox/models/network_blocks.py b/flow-python/examples/warehouse/detection_yolox/models/network_blocks.py deleted file mode 100644 index 304e32f..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/network_blocks.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.functional as F -import megengine.module as M - - -class UpSample(M.Module): - - def __init__(self, scale_factor=2, mode="bilinear"): - super().__init__() - self.scale_factor = scale_factor - self.mode = mode - - def forward(self, x): - return F.vision.interpolate(x, scale_factor=self.scale_factor, mode=self.mode) - - -class SiLU(M.Module): - """export-friendly version of M.SiLU()""" - - @staticmethod - def forward(x): - return x * F.sigmoid(x) - - -def get_activation(name="silu"): - if name == "silu": - module = SiLU() - elif name == "relu": - module = M.ReLU() - elif name == "lrelu": - module = M.LeakyReLU(0.1) - else: - raise AttributeError("Unsupported act type: {}".format(name)) - return module - - -class BaseConv(M.Module): - """A Conv2d -> Batchnorm -> silu/leaky relu block""" - - def __init__(self, in_channels, out_channels, ksize, stride, groups=1, bias=False, act="silu"): - super().__init__() - # same padding - pad = (ksize - 1) // 2 - self.conv = M.Conv2d( - in_channels, - out_channels, - kernel_size=ksize, - stride=stride, - padding=pad, - groups=groups, - bias=bias, - ) - self.bn = M.BatchNorm2d(out_channels) - self.act = get_activation(act) - - def forward(self, x): - return self.act(self.bn(self.conv(x))) - - def fuseforward(self, x): - return self.act(self.conv(x)) - - -class DWConv(M.Module): - """Depthwise Conv + Conv""" - def __init__(self, in_channels, out_channels, ksize, stride=1, act="silu"): - super().__init__() - self.dconv = BaseConv( - in_channels, in_channels, ksize=ksize, - stride=stride, groups=in_channels, act=act - ) - self.pconv = BaseConv( - in_channels, out_channels, ksize=1, - stride=1, groups=1, act=act - ) - - def forward(self, x): - x = self.dconv(x) - return self.pconv(x) - - -class Bottleneck(M.Module): - # Standard bottleneck - def __init__( - self, in_channels, out_channels, shortcut=True, - expansion=0.5, depthwise=False, act="silu" - ): - super().__init__() - hidden_channels = int(out_channels * expansion) - Conv = DWConv if depthwise else BaseConv - self.conv1 = BaseConv(in_channels, hidden_channels, 1, stride=1, act=act) - self.conv2 = Conv(hidden_channels, out_channels, 3, stride=1, act=act) - self.use_add = shortcut and in_channels == out_channels - - def forward(self, x): - y = self.conv2(self.conv1(x)) - if self.use_add: - y = y + x - return y - - -class ResLayer(M.Module): - "Residual layer with `in_channels` inputs." - def __init__(self, in_channels: int): - super().__init__() - mid_channels = in_channels // 2 - self.layer1 = BaseConv(in_channels, mid_channels, ksize=1, stride=1, act="lrelu") - self.layer2 = BaseConv(mid_channels, in_channels, ksize=3, stride=1, act="lrelu") - - def forward(self, x): - out = self.layer2(self.layer1(x)) - return x + out - - -class SPPBottleneck(M.Module): - """Spatial pyramid pooling layer used in YOLOv3-SPP""" - def __init__(self, in_channels, out_channels, kernel_sizes=(5, 9, 13), activation="silu"): - super().__init__() - hidden_channels = in_channels // 2 - self.conv1 = BaseConv(in_channels, hidden_channels, 1, stride=1, act=activation) - self.m = [M.MaxPool2d(kernel_size=ks, stride=1, padding=ks // 2) for ks in kernel_sizes] - conv2_channels = hidden_channels * (len(kernel_sizes) + 1) - self.conv2 = BaseConv(conv2_channels, out_channels, 1, stride=1, act=activation) - - def forward(self, x): - x = self.conv1(x) - x = F.concat([x] + [m(x) for m in self.m], axis=1) - x = self.conv2(x) - return x - - -class CSPLayer(M.Module): - """C3 in yolov5, CSP Bottleneck with 3 convolutions""" - - def __init__( - self, in_channels, out_channels, n=1, - shortcut=True, expansion=0.5, depthwise=False, act="silu" - ): - """ - Args: - in_channels (int): input channels. - out_channels (int): output channels. - n (int): number of Bottlenecks. Default value: 1. - """ - # ch_in, ch_out, number, shortcut, groups, expansion - super().__init__() - hidden_channels = int(out_channels * expansion) # hidden channels - self.conv1 = BaseConv(in_channels, hidden_channels, 1, stride=1, act=act) - self.conv2 = BaseConv(in_channels, hidden_channels, 1, stride=1, act=act) - self.conv3 = BaseConv(2 * hidden_channels, out_channels, 1, stride=1, act=act) - module_list = [ - Bottleneck(hidden_channels, hidden_channels, shortcut, 1.0, depthwise, act=act) - for _ in range(n) - ] - self.m = M.Sequential(*module_list) - - def forward(self, x): - x_1 = self.conv1(x) - x_2 = self.conv2(x) - x_1 = self.m(x_1) - x = F.concat((x_1, x_2), axis=1) - return self.conv3(x) - - -class Focus(M.Module): - """Focus width and height information into channel space.""" - - def __init__(self, in_channels, out_channels, ksize=1, stride=1, act="silu"): - super().__init__() - self.conv = BaseConv(in_channels * 4, out_channels, ksize, stride, act=act) - - def forward(self, x): - # shape of x (b,c,w,h) -> y(b,4c,w/2,h/2) - patch_top_left = x[..., ::2, ::2] - patch_top_right = x[..., ::2, 1::2] - patch_bot_left = x[..., 1::2, ::2] - patch_bot_right = x[..., 1::2, 1::2] - x = F.concat( - (patch_top_left, patch_bot_left, patch_top_right, patch_bot_right,), axis=1, - ) - return self.conv(x) diff --git a/flow-python/examples/warehouse/detection_yolox/models/yolo_fpn.py b/flow-python/examples/warehouse/detection_yolox/models/yolo_fpn.py deleted file mode 100644 index f6f2f15..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/yolo_fpn.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.functional as F -import megengine.module as M - -from .darknet import Darknet -from .network_blocks import BaseConv, UpSample - - -class YOLOFPN(M.Module): - """ - YOLOFPN module. Darknet 53 is the default backbone of this model. - """ - - def __init__( - self, depth=53, in_features=["dark3", "dark4", "dark5"], - ): - super().__init__() - - self.backbone = Darknet(depth) - self.in_features = in_features - - # out 1 - self.out1_cbl = self._make_cbl(512, 256, 1) - self.out1 = self._make_embedding([256, 512], 512 + 256) - - # out 2 - self.out2_cbl = self._make_cbl(256, 128, 1) - self.out2 = self._make_embedding([128, 256], 256 + 128) - - # upsample - self.upsample = UpSample(scale_factor=2, mode="bilinear") - - def _make_cbl(self, _in, _out, ks): - return BaseConv(_in, _out, ks, stride=1, act="lrelu") - - def _make_embedding(self, filters_list, in_filters): - m = M.Sequential( - *[ - self._make_cbl(in_filters, filters_list[0], 1), - self._make_cbl(filters_list[0], filters_list[1], 3), - - self._make_cbl(filters_list[1], filters_list[0], 1), - - self._make_cbl(filters_list[0], filters_list[1], 3), - self._make_cbl(filters_list[1], filters_list[0], 1), - ] - ) - return m - - def forward(self, inputs): - """ - Args: - inputs (Tensor): input image. - - Returns: - Tuple[Tensor]: FPN output features.. - """ - # backbone - out_features = self.backbone(inputs) - x2, x1, x0 = [out_features[f] for f in self.in_features] - - # yolo branch 1 - x1_in = self.out1_cbl(x0) - x1_in = self.upsample(x1_in) - x1_in = F.concat([x1_in, x1], 1) - out_dark4 = self.out1(x1_in) - - # yolo branch 2 - x2_in = self.out2_cbl(out_dark4) - x2_in = self.upsample(x2_in) - x2_in = F.concat([x2_in, x2], 1) - out_dark3 = self.out2(x2_in) - - outputs = (out_dark3, out_dark4, x0) - return outputs diff --git a/flow-python/examples/warehouse/detection_yolox/models/yolo_head.py b/flow-python/examples/warehouse/detection_yolox/models/yolo_head.py deleted file mode 100644 index 2dbee3f..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/yolo_head.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.functional as F -import megengine.module as M - -from .network_blocks import BaseConv, DWConv - - -def meshgrid(x, y): - """meshgrid wrapper for megengine""" - assert len(x.shape) == 1 - assert len(y.shape) == 1 - mesh_shape = (y.shape[0], x.shape[0]) - mesh_x = F.broadcast_to(x, mesh_shape) - mesh_y = F.broadcast_to(y.reshape(-1, 1), mesh_shape) - return mesh_x, mesh_y - - -class YOLOXHead(M.Module): - def __init__( - self, num_classes, width=1.0, strides=[8, 16, 32], - in_channels=[256, 512, 1024], act="silu", depthwise=False - ): - """ - Args: - act (str): activation type of conv. Defalut value: "silu". - depthwise (bool): wheather apply depthwise conv in conv branch. Defalut value: False. - """ - super().__init__() - - self.n_anchors = 1 - self.num_classes = num_classes - self.decode_in_inference = True # save for matching - - self.cls_convs = [] - self.reg_convs = [] - self.cls_preds = [] - self.reg_preds = [] - self.obj_preds = [] - self.stems = [] - Conv = DWConv if depthwise else BaseConv - - for i in range(len(in_channels)): - self.stems.append( - BaseConv( - in_channels=int(in_channels[i] * width), - out_channels=int(256 * width), - ksize=1, - stride=1, - act=act, - ) - ) - self.cls_convs.append( - M.Sequential( - *[ - Conv( - in_channels=int(256 * width), - out_channels=int(256 * width), - ksize=3, - stride=1, - act=act, - ), - Conv( - in_channels=int(256 * width), - out_channels=int(256 * width), - ksize=3, - stride=1, - act=act, - ), - ] - ) - ) - self.reg_convs.append( - M.Sequential( - *[ - Conv( - in_channels=int(256 * width), - out_channels=int(256 * width), - ksize=3, - stride=1, - act=act, - ), - Conv( - in_channels=int(256 * width), - out_channels=int(256 * width), - ksize=3, - stride=1, - act=act, - ), - ] - ) - ) - self.cls_preds.append( - M.Conv2d( - in_channels=int(256 * width), - out_channels=self.n_anchors * self.num_classes, - kernel_size=1, - stride=1, - padding=0, - ) - ) - self.reg_preds.append( - M.Conv2d( - in_channels=int(256 * width), - out_channels=4, - kernel_size=1, - stride=1, - padding=0, - ) - ) - self.obj_preds.append( - M.Conv2d( - in_channels=int(256 * width), - out_channels=self.n_anchors * 1, - kernel_size=1, - stride=1, - padding=0, - ) - ) - - self.use_l1 = False - self.strides = strides - self.grids = [F.zeros(1)] * len(in_channels) - - def forward(self, xin, labels=None, imgs=None): - outputs = [] - assert not self.training - - for k, (cls_conv, reg_conv, stride_this_level, x) in enumerate( - zip(self.cls_convs, self.reg_convs, self.strides, xin) - ): - x = self.stems[k](x) - cls_x = x - reg_x = x - - cls_feat = cls_conv(cls_x) - cls_output = self.cls_preds[k](cls_feat) - - reg_feat = reg_conv(reg_x) - reg_output = self.reg_preds[k](reg_feat) - obj_output = self.obj_preds[k](reg_feat) - output = F.concat([reg_output, F.sigmoid(obj_output), F.sigmoid(cls_output)], 1) - outputs.append(output) - - self.hw = [x.shape[-2:] for x in outputs] - # [batch, n_anchors_all, 85] - outputs = F.concat([F.flatten(x, start_axis=2) for x in outputs], axis=2) - outputs = F.transpose(outputs, (0, 2, 1)) - if self.decode_in_inference: - return self.decode_outputs(outputs) - else: - return outputs - - def get_output_and_grid(self, output, k, stride, dtype): - grid = self.grids[k] - - batch_size = output.shape[0] - n_ch = 5 + self.num_classes - hsize, wsize = output.shape[-2:] - if grid.shape[2:4] != output.shape[2:4]: - yv, xv = meshgrid([F.arange(hsize), F.arange(wsize)]) - grid = F.stack((xv, yv), 2).reshape(1, 1, hsize, wsize, 2).type(dtype) - self.grids[k] = grid - - output = output.view(batch_size, self.n_anchors, n_ch, hsize, wsize) - output = ( - output.permute(0, 1, 3, 4, 2) - .reshape(batch_size, self.n_anchors * hsize * wsize, -1) - ) - grid = grid.view(1, -1, 2) - output[..., :2] = (output[..., :2] + grid) * stride - output[..., 2:4] = F.exp(output[..., 2:4]) * stride - return output, grid - - def decode_outputs(self, outputs): - grids = [] - strides = [] - for (hsize, wsize), stride in zip(self.hw, self.strides): - xv, yv = meshgrid(F.arange(hsize), F.arange(wsize)) - grid = F.stack((xv, yv), 2).reshape(1, -1, 2) - grids.append(grid) - shape = grid.shape[:2] - strides.append(F.full((*shape, 1), stride)) - - grids = F.concat(grids, axis=1) - strides = F.concat(strides, axis=1) - - outputs[..., :2] = (outputs[..., :2] + grids) * strides - outputs[..., 2:4] = F.exp(outputs[..., 2:4]) * strides - return outputs diff --git a/flow-python/examples/warehouse/detection_yolox/models/yolo_pafpn.py b/flow-python/examples/warehouse/detection_yolox/models/yolo_pafpn.py deleted file mode 100644 index cd4e0a9..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/yolo_pafpn.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.module as M -import megengine.functional as F - -from .darknet import CSPDarknet -from .network_blocks import BaseConv, CSPLayer, DWConv, UpSample - - -class YOLOPAFPN(M.Module): - """ - YOLOv3 model. Darknet 53 is the default backbone of this model. - """ - - def __init__( - self, depth=1.0, width=1.0, in_features=("dark3", "dark4", "dark5"), - in_channels=[256, 512, 1024], depthwise=False, act="silu", - ): - super().__init__() - self.backbone = CSPDarknet(depth, width, depthwise=depthwise, act=act) - self.in_features = in_features - self.in_channels = in_channels - Conv = DWConv if depthwise else BaseConv - - self.upsample = UpSample(scale_factor=2, mode="bilinear") - self.lateral_conv0 = BaseConv( - int(in_channels[2] * width), int(in_channels[1] * width), 1, 1, act=act - ) - self.C3_p4 = CSPLayer( - int(2 * in_channels[1] * width), - int(in_channels[1] * width), - round(3 * depth), - False, - depthwise=depthwise, - act=act, - ) # cat - - self.reduce_conv1 = BaseConv( - int(in_channels[1] * width), int(in_channels[0] * width), 1, 1, act=act - ) - self.C3_p3 = CSPLayer( - int(2 * in_channels[0] * width), - int(in_channels[0] * width), - round(3 * depth), - False, - depthwise=depthwise, - act=act, - ) - - # bottom-up conv - self.bu_conv2 = Conv( - int(in_channels[0] * width), int(in_channels[0] * width), 3, 2, act=act - ) - self.C3_n3 = CSPLayer( - int(2 * in_channels[0] * width), - int(in_channels[1] * width), - round(3 * depth), - False, - depthwise=depthwise, - act=act, - ) - - # bottom-up conv - self.bu_conv1 = Conv( - int(in_channels[1] * width), int(in_channels[1] * width), 3, 2, act=act - ) - self.C3_n4 = CSPLayer( - int(2 * in_channels[1] * width), - int(in_channels[2] * width), - round(3 * depth), - False, - depthwise=depthwise, - act=act, - ) - - def forward(self, input): - """ - Args: - inputs: input images. - - Returns: - Tuple[Tensor]: FPN feature. - """ - - # backbone - out_features = self.backbone(input) - features = [out_features[f] for f in self.in_features] - [x2, x1, x0] = features - - fpn_out0 = self.lateral_conv0(x0) # 1024->512/32 - f_out0 = self.upsample(fpn_out0) # 512/16 - f_out0 = F.concat([f_out0, x1], 1) # 512->1024/16 - f_out0 = self.C3_p4(f_out0) # 1024->512/16 - - fpn_out1 = self.reduce_conv1(f_out0) # 512->256/16 - f_out1 = self.upsample(fpn_out1) # 256/8 - f_out1 = F.concat([f_out1, x2], 1) # 256->512/8 - pan_out2 = self.C3_p3(f_out1) # 512->256/8 - - p_out1 = self.bu_conv2(pan_out2) # 256->256/16 - p_out1 = F.concat([p_out1, fpn_out1], 1) # 256->512/16 - pan_out1 = self.C3_n3(p_out1) # 512->512/16 - - p_out0 = self.bu_conv1(pan_out1) # 512->512/32 - p_out0 = F.concat([p_out0, fpn_out0], 1) # 512->1024/32 - pan_out0 = self.C3_n4(p_out0) # 1024->1024/32 - - outputs = (pan_out2, pan_out1, pan_out0) - return outputs diff --git a/flow-python/examples/warehouse/detection_yolox/models/yolox.py b/flow-python/examples/warehouse/detection_yolox/models/yolox.py deleted file mode 100644 index adcc957..0000000 --- a/flow-python/examples/warehouse/detection_yolox/models/yolox.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -# Copyright (c) 2014-2021 Megvii Inc. All rights reserved. - -import megengine.module as M - -from .yolo_head import YOLOXHead -from .yolo_pafpn import YOLOPAFPN - - -class YOLOX(M.Module): - """ - YOLOX model module. The module list is defined by create_yolov3_modules function. - The network returns loss values from three YOLO layers during training - and detection results during test. - """ - - def __init__(self, backbone=None, head=None): - super().__init__() - if backbone is None: - backbone = YOLOPAFPN() - if head is None: - head = YOLOXHead(80) - - self.backbone = backbone - self.head = head - - def forward(self, x): - # fpn output content features of [dark3, dark4, dark5] - fpn_outs = self.backbone(x) - assert not self.training - outputs = self.head(fpn_outs) - - return outputs diff --git a/flow-python/examples/warehouse/detection_yolox/process.py b/flow-python/examples/warehouse/detection_yolox/process.py index 33a2605..6fee179 100644 --- a/flow-python/examples/warehouse/detection_yolox/process.py +++ b/flow-python/examples/warehouse/detection_yolox/process.py @@ -25,6 +25,7 @@ def is_overlap_v1(rect1, rect2, iou_threshold): ov = i / u return ov >= iou_threshold + def cpu_nms(boxes, scores, iou_threshold=0.3): if 0 == len(boxes): return [] @@ -47,6 +48,7 @@ def cpu_nms(boxes, scores, iou_threshold=0.3): return [x[5] for i, x in enumerate(rects) if rect_valid[i]] + def preprocess(image, input_size, mean, std, swap=(2, 0, 1)): # print(f'{image.shape}') if len(image.shape) == 3: @@ -60,7 +62,7 @@ def preprocess(image, input_size, mean, std, swap=(2, 0, 1)): (int(img.shape[1] * r), int(img.shape[0] * r)), interpolation=cv2.INTER_LINEAR, ).astype(np.float32) - padded_img[: int(img.shape[0] * r), : int(img.shape[1] * r)] = resized_img + padded_img[:int(img.shape[0] * r), :int(img.shape[1] * r)] = resized_img image = padded_img image = image.astype(np.float32) @@ -74,11 +76,13 @@ def preprocess(image, input_size, mean, std, swap=(2, 0, 1)): image = np.ascontiguousarray(image, dtype=np.float32) return image, r + def argmax_keepdims(x, axis): output_shape = list(x.shape) output_shape[axis] = 1 return np.argmax(x, axis=axis).reshape(output_shape) + def postprocess(prediction, num_classes, conf_thre=0.7, nms_thre=0.45): box_corner = F.zeros_like(prediction) box_corner[:, :, 0] = prediction[:, :, 0] - prediction[:, :, 2] / 2 @@ -94,8 +98,10 @@ def postprocess(prediction, num_classes, conf_thre=0.7, nms_thre=0.45): if not image_pred.shape[0]: continue # Get score and class with highest confidence - class_conf = F.max(image_pred[:, 5 : 5 + num_classes], 1, keepdims=True) - class_pred = F.argmax(image_pred[:, 5 : 5 + num_classes], 1, keepdims=True) + class_conf = F.max(image_pred[:, 5:5 + num_classes], 1, keepdims=True) + class_pred = F.argmax(image_pred[:, 5:5 + num_classes], + 1, + keepdims=True) class_conf_squeeze = F.squeeze(class_conf) conf_mask = image_pred[:, 4] * class_conf_squeeze >= conf_thre @@ -105,7 +111,9 @@ def postprocess(prediction, num_classes, conf_thre=0.7, nms_thre=0.45): continue nms_out_index = F.vision.nms( - detections[:, :4], detections[:, 4] * detections[:, 5], nms_thre, + detections[:, :4], + detections[:, 4] * detections[:, 5], + nms_thre, ) detections = detections[nms_out_index] if output[i] is None: diff --git a/flow-python/examples/warehouse/detection_yolox/tools/convert_weights.py b/flow-python/examples/warehouse/detection_yolox/tools/convert_weights.py deleted file mode 100644 index 198caee..0000000 --- a/flow-python/examples/warehouse/detection_yolox/tools/convert_weights.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -import argparse -from collections import OrderedDict - -import megengine as mge -import torch - - -def make_parser(): - parser = argparse.ArgumentParser() - parser.add_argument("-w", "--weights", type=str, help="path of weight file") - parser.add_argument( - "-o", - "--output", - default="weight_mge.pkl", - type=str, - help="path of weight file", - ) - return parser - - -def numpy_weights(weight_file): - torch_weights = torch.load(weight_file, map_location="cpu") - if "model" in torch_weights: - torch_weights = torch_weights["model"] - new_dict = OrderedDict() - for k, v in torch_weights.items(): - new_dict[k] = v.cpu().numpy() - return new_dict - - -def map_weights(weight_file, output_file): - torch_weights = numpy_weights(weight_file) - - new_dict = OrderedDict() - for k, v in torch_weights.items(): - if "num_batches_tracked" in k: - print("drop: {}".format(k)) - continue - if k.endswith("bias"): - print("bias key: {}".format(k)) - v = v.reshape(1, -1, 1, 1) - new_dict[k] = v - elif "dconv" in k and "conv.weight" in k: - print("depthwise conv key: {}".format(k)) - cout, cin, k1, k2 = v.shape - v = v.reshape(cout, 1, cin, k1, k2) - new_dict[k] = v - else: - new_dict[k] = v - - mge.save(new_dict, output_file) - print("save weights to {}".format(output_file)) - - -def main(): - parser = make_parser() - args = parser.parse_args() - map_weights(args.weights, args.output) - - -if __name__ == "__main__": - main() diff --git a/flow-python/examples/warehouse/detection_yolox/tools/dump.py b/flow-python/examples/warehouse/detection_yolox/tools/dump.py deleted file mode 100644 index c00180a..0000000 --- a/flow-python/examples/warehouse/detection_yolox/tools/dump.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -# Copyright (c) Megvii, Inc. and its affiliates. - -import argparse - -import megengine as mge -import numpy as np -from megengine import jit - -from ..build import build_and_load - - -def make_parser(): - parser = argparse.ArgumentParser("YOLOX Demo Dump") - parser.add_argument("-n", "--name", type=str, default="yolox-s", help="model name") - parser.add_argument("-c", "--ckpt", default=None, type=str, help="ckpt for eval") - parser.add_argument( - "--dump_path", default="model.mge", help="path to save the dumped model" - ) - return parser - - -def dump_static_graph(model, graph_name="model.mge"): - model.eval() - model.head.decode_in_inference = False - - data = mge.Tensor(np.random.random((1, 3, 640, 640))) - - @jit.trace(capture_as_const=True) - def pred_func(data): - outputs = model(data) - return outputs - - pred_func(data) - pred_func.dump( - graph_name, - arg_names=["data"], - optimize_for_inference=True, - enable_fuse_conv_bias_nonlinearity=True, - ) - - -def main(args): - model = build_and_load(args.ckpt, name=args.name) - dump_static_graph(model, args.dump_path) - - -if __name__ == "__main__": - args = make_parser().parse_args() - main(args) diff --git a/flow-python/examples/warehouse/detection_yolox/visualize.py b/flow-python/examples/warehouse/detection_yolox/visualize.py index 39f63d8..257cc07 100644 --- a/flow-python/examples/warehouse/detection_yolox/visualize.py +++ b/flow-python/examples/warehouse/detection_yolox/visualize.py @@ -23,106 +23,50 @@ def vis(img, boxes, scores, cls_ids, conf=0.5, class_names=None): color = (_COLORS[cls_id] * 255).astype(np.uint8).tolist() text = '{}:{:.1f}%'.format(class_names[cls_id], score * 100) - txt_color = (0, 0, 0) if np.mean(_COLORS[cls_id]) > 0.5 else (255, 255, 255) + txt_color = (0, 0, 0) if np.mean(_COLORS[cls_id]) > 0.5 else (255, 255, + 255) font = cv2.FONT_HERSHEY_SIMPLEX txt_size = cv2.getTextSize(text, font, 0.4, 1)[0] cv2.rectangle(img, (x0, y0), (x1, y1), color, 2) txt_bk_color = (_COLORS[cls_id] * 255 * 0.7).astype(np.uint8).tolist() - cv2.rectangle( - img, - (x0, y0 + 1), - (x0 + txt_size[0] + 1, y0 + int(1.5*txt_size[1])), - txt_bk_color, - -1 - ) - cv2.putText(img, text, (x0, y0 + txt_size[1]), font, 0.4, txt_color, thickness=1) + cv2.rectangle(img, (x0, y0 + 1), + (x0 + txt_size[0] + 1, y0 + int(1.5 * txt_size[1])), + txt_bk_color, -1) + cv2.putText(img, + text, (x0, y0 + txt_size[1]), + font, + 0.4, + txt_color, + thickness=1) return img -_COLORS = np.array( - [ - 0.000, 0.447, 0.741, - 0.850, 0.325, 0.098, - 0.929, 0.694, 0.125, - 0.494, 0.184, 0.556, - 0.466, 0.674, 0.188, - 0.301, 0.745, 0.933, - 0.635, 0.078, 0.184, - 0.300, 0.300, 0.300, - 0.600, 0.600, 0.600, - 1.000, 0.000, 0.000, - 1.000, 0.500, 0.000, - 0.749, 0.749, 0.000, - 0.000, 1.000, 0.000, - 0.000, 0.000, 1.000, - 0.667, 0.000, 1.000, - 0.333, 0.333, 0.000, - 0.333, 0.667, 0.000, - 0.333, 1.000, 0.000, - 0.667, 0.333, 0.000, - 0.667, 0.667, 0.000, - 0.667, 1.000, 0.000, - 1.000, 0.333, 0.000, - 1.000, 0.667, 0.000, - 1.000, 1.000, 0.000, - 0.000, 0.333, 0.500, - 0.000, 0.667, 0.500, - 0.000, 1.000, 0.500, - 0.333, 0.000, 0.500, - 0.333, 0.333, 0.500, - 0.333, 0.667, 0.500, - 0.333, 1.000, 0.500, - 0.667, 0.000, 0.500, - 0.667, 0.333, 0.500, - 0.667, 0.667, 0.500, - 0.667, 1.000, 0.500, - 1.000, 0.000, 0.500, - 1.000, 0.333, 0.500, - 1.000, 0.667, 0.500, - 1.000, 1.000, 0.500, - 0.000, 0.333, 1.000, - 0.000, 0.667, 1.000, - 0.000, 1.000, 1.000, - 0.333, 0.000, 1.000, - 0.333, 0.333, 1.000, - 0.333, 0.667, 1.000, - 0.333, 1.000, 1.000, - 0.667, 0.000, 1.000, - 0.667, 0.333, 1.000, - 0.667, 0.667, 1.000, - 0.667, 1.000, 1.000, - 1.000, 0.000, 1.000, - 1.000, 0.333, 1.000, - 1.000, 0.667, 1.000, - 0.333, 0.000, 0.000, - 0.500, 0.000, 0.000, - 0.667, 0.000, 0.000, - 0.833, 0.000, 0.000, - 1.000, 0.000, 0.000, - 0.000, 0.167, 0.000, - 0.000, 0.333, 0.000, - 0.000, 0.500, 0.000, - 0.000, 0.667, 0.000, - 0.000, 0.833, 0.000, - 0.000, 1.000, 0.000, - 0.000, 0.000, 0.167, - 0.000, 0.000, 0.333, - 0.000, 0.000, 0.500, - 0.000, 0.000, 0.667, - 0.000, 0.000, 0.833, - 0.000, 0.000, 1.000, - 0.000, 0.000, 0.000, - 0.143, 0.143, 0.143, - 0.286, 0.286, 0.286, - 0.429, 0.429, 0.429, - 0.571, 0.571, 0.571, - 0.714, 0.714, 0.714, - 0.857, 0.857, 0.857, - 0.000, 0.447, 0.741, - 0.314, 0.717, 0.741, - 0.50, 0.5, 0 - ] -).astype(np.float32).reshape(-1, 3) +_COLORS = np.array([ + 0.000, 0.447, 0.741, 0.850, 0.325, 0.098, 0.929, 0.694, 0.125, 0.494, + 0.184, 0.556, 0.466, 0.674, 0.188, 0.301, 0.745, 0.933, 0.635, 0.078, + 0.184, 0.300, 0.300, 0.300, 0.600, 0.600, 0.600, 1.000, 0.000, 0.000, + 1.000, 0.500, 0.000, 0.749, 0.749, 0.000, 0.000, 1.000, 0.000, 0.000, + 0.000, 1.000, 0.667, 0.000, 1.000, 0.333, 0.333, 0.000, 0.333, 0.667, + 0.000, 0.333, 1.000, 0.000, 0.667, 0.333, 0.000, 0.667, 0.667, 0.000, + 0.667, 1.000, 0.000, 1.000, 0.333, 0.000, 1.000, 0.667, 0.000, 1.000, + 1.000, 0.000, 0.000, 0.333, 0.500, 0.000, 0.667, 0.500, 0.000, 1.000, + 0.500, 0.333, 0.000, 0.500, 0.333, 0.333, 0.500, 0.333, 0.667, 0.500, + 0.333, 1.000, 0.500, 0.667, 0.000, 0.500, 0.667, 0.333, 0.500, 0.667, + 0.667, 0.500, 0.667, 1.000, 0.500, 1.000, 0.000, 0.500, 1.000, 0.333, + 0.500, 1.000, 0.667, 0.500, 1.000, 1.000, 0.500, 0.000, 0.333, 1.000, + 0.000, 0.667, 1.000, 0.000, 1.000, 1.000, 0.333, 0.000, 1.000, 0.333, + 0.333, 1.000, 0.333, 0.667, 1.000, 0.333, 1.000, 1.000, 0.667, 0.000, + 1.000, 0.667, 0.333, 1.000, 0.667, 0.667, 1.000, 0.667, 1.000, 1.000, + 1.000, 0.000, 1.000, 1.000, 0.333, 1.000, 1.000, 0.667, 1.000, 0.333, + 0.000, 0.000, 0.500, 0.000, 0.000, 0.667, 0.000, 0.000, 0.833, 0.000, + 0.000, 1.000, 0.000, 0.000, 0.000, 0.167, 0.000, 0.000, 0.333, 0.000, + 0.000, 0.500, 0.000, 0.000, 0.667, 0.000, 0.000, 0.833, 0.000, 0.000, + 1.000, 0.000, 0.000, 0.000, 0.167, 0.000, 0.000, 0.333, 0.000, 0.000, + 0.500, 0.000, 0.000, 0.667, 0.000, 0.000, 0.833, 0.000, 0.000, 1.000, + 0.000, 0.000, 0.000, 0.143, 0.143, 0.143, 0.286, 0.286, 0.286, 0.429, + 0.429, 0.429, 0.571, 0.571, 0.571, 0.714, 0.714, 0.714, 0.857, 0.857, + 0.857, 0.000, 0.447, 0.741, 0.314, 0.717, 0.741, 0.50, 0.5, 0 +]).astype(np.float32).reshape(-1, 3) diff --git a/flow-python/examples/warehouse/quality_naive/__init__.py b/flow-python/examples/warehouse/quality_naive/__init__.py index 7b3f394..c90acbc 100644 --- a/flow-python/examples/warehouse/quality_naive/__init__.py +++ b/flow-python/examples/warehouse/quality_naive/__init__.py @@ -9,4 +9,4 @@ #!/usr/bin/env python # coding=utf-8 -from .quality import * +from .quality import Quality diff --git a/flow-python/examples/warehouse/quality_naive/quality.py b/flow-python/examples/warehouse/quality_naive/quality.py index 21490d6..4c2a090 100644 --- a/flow-python/examples/warehouse/quality_naive/quality.py +++ b/flow-python/examples/warehouse/quality_naive/quality.py @@ -11,8 +11,8 @@ import cv2 + class Quality: - @staticmethod def clearness(mat): return cv2.Laplacian(mat, cv2.CV_64F).var() @@ -21,6 +21,7 @@ def clearness(mat): def area(mat): return mat.shape[0] * mat.shape[1] + if __name__ == "__main__": import sys mat = cv2.imread(sys.argv[1]) @@ -28,4 +29,3 @@ def area(mat): print(f'load {sys.argv[1]} failed') sys.exit(-1) print(f'brightness: {Quality.clearness(mat)}') - diff --git a/flow-python/examples/warehouse/reid_alignedreid/dump.py b/flow-python/examples/warehouse/reid_alignedreid/dump.py index 8b84258..fe80c21 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/dump.py +++ b/flow-python/examples/warehouse/reid_alignedreid/dump.py @@ -18,10 +18,14 @@ def make_parser(): parser = argparse.ArgumentParser("Resnet50 Dump") - parser.add_argument("-c", "--ckpt", default=None, type=str, help="ckpt for eval") - parser.add_argument( - "--dump_path", default="model.mge", help="path to save the dumped model" - ) + parser.add_argument("-c", + "--ckpt", + default=None, + type=str, + help="ckpt for eval") + parser.add_argument("--dump_path", + default="model.mge", + help="path to save the dumped model") return parser diff --git a/flow-python/examples/warehouse/reid_alignedreid/lite.py b/flow-python/examples/warehouse/reid_alignedreid/lite.py index 675839e..9ff523c 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/lite.py +++ b/flow-python/examples/warehouse/reid_alignedreid/lite.py @@ -20,11 +20,11 @@ def __init__( device="gpu", device_id=0, ): - + if "gpu" in device.lower(): - device_type=mgelite.LiteDeviceType.LITE_CUDA + device_type = mgelite.LiteDeviceType.LITE_CUDA else: - device_type=mgelite.LiteDeviceType.LITE_CPU + device_type = mgelite.LiteDeviceType.LITE_CPU net_config = mgelite.LiteConfig(device_type=device_type) ios = mgelite.LiteNetworkIO() @@ -36,17 +36,20 @@ def __init__( self.net = net - def inference(self, mat): t0 = time.time() - img = preprocess(mat, input_size=(224,224), scale_im = True, mean=[0.486, 0.459, 0.408], std=[0.229, 0.224, 0.225]) + img = preprocess(mat, + input_size=(224, 224), + scale_im=True, + mean=[0.486, 0.459, 0.408], + std=[0.229, 0.224, 0.225]) # build input tensor - data = img[np.newaxis,:] - inp_data =self.net.get_io_tensor("data") + data = img[np.newaxis, :] + inp_data = self.net.get_io_tensor("data") inp_data.set_data_by_copy(data) - + # forward self.net.forward() self.net.wait() @@ -70,9 +73,8 @@ def inference(self, mat): img4 = cv2.imread(sys.argv[4]) output4 = predictor.inference(img4) - positive = np.linalg.norm(output2-output3) + positive = np.linalg.norm(output2 - output3) print(f'distance_positive: {positive}') - negative = np.linalg.norm(output3-output4) + negative = np.linalg.norm(output3 - output4) print(f'distance_positive: {negative}') - diff --git a/flow-python/examples/warehouse/reid_alignedreid/main.py b/flow-python/examples/warehouse/reid_alignedreid/main.py index 513e9ab..29ef721 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/main.py +++ b/flow-python/examples/warehouse/reid_alignedreid/main.py @@ -21,7 +21,9 @@ if __name__ == "__main__": import sys if len(sys.argv) < 5: - print("usage: python3 -m reid_alignedreid/demo reid.pkl positive1.png positive2.png negtive.jpg") + print( + "usage: python3 -m reid_alignedreid/demo reid.pkl positive1.png positive2.png negtive.jpg" + ) sys.exit(0) model = Model() sd = mge.load(sys.argv[1]) @@ -35,8 +37,8 @@ feat3 = model.inference(cv2.imread(sys.argv[4])) logger.info(f'{feat3}') - positive = np.linalg.norm(feat1-feat2) + positive = np.linalg.norm(feat1 - feat2) print(f'distance_positive: {positive}') - negtive = np.linalg.norm(feat3-feat2) + negtive = np.linalg.norm(feat3 - feat2) print(f'distance_negtive: {negtive}') diff --git a/flow-python/examples/warehouse/reid_alignedreid/model.py b/flow-python/examples/warehouse/reid_alignedreid/model.py index 127c995..4bfe74c 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/model.py +++ b/flow-python/examples/warehouse/reid_alignedreid/model.py @@ -9,7 +9,7 @@ #!/usr/bin/env python # coding=utf-8 -import megengine as mge +import megengine as mge import megengine.module as nn import megengine.module.init as init import megengine.functional as F @@ -19,31 +19,36 @@ from .resnet import resnet50, resnet18 from .process import preprocess + class Model(nn.Module): - def __init__(self): - super(Model, self).__init__() - self.base = resnet50() - # planes = 2048 + def __init__(self): + super(Model, self).__init__() + self.base = resnet50() + # planes = 2048 - def forward(self, x): - """ + def forward(self, x): + """ Returns: global_feat: shape [N, C] local_feat: shape [N, H, c] """ - # shape [N, C, H, W] - feat = self.base(x) - feat = F.avg_pool2d(feat, (feat.shape[2], feat.shape[3])) - # shape [N, C] - feat = F.flatten(feat, 1) - feat = F.normalize(feat, axis=1) - return feat - - def inference(self, mat): - t0 = time.time() - img = preprocess(mat, input_size=(224,224), scale_im = True, mean=[0.486, 0.459, 0.408], std=[0.229, 0.224, 0.225]) - img = F.expand_dims(mge.tensor(img), 0) - feat = self.forward(img) - logger.info("AlignedReID infer time: {:.4f}s".format(time.time() - t0)) - - return feat[0].numpy() + # shape [N, C, H, W] + feat = self.base(x) + feat = F.avg_pool2d(feat, (feat.shape[2], feat.shape[3])) + # shape [N, C] + feat = F.flatten(feat, 1) + feat = F.normalize(feat, axis=1) + return feat + + def inference(self, mat): + t0 = time.time() + img = preprocess(mat, + input_size=(224, 224), + scale_im=True, + mean=[0.486, 0.459, 0.408], + std=[0.229, 0.224, 0.225]) + img = F.expand_dims(mge.tensor(img), 0) + feat = self.forward(img) + logger.info("AlignedReID infer time: {:.4f}s".format(time.time() - t0)) + + return feat[0].numpy() diff --git a/flow-python/examples/warehouse/reid_alignedreid/process.py b/flow-python/examples/warehouse/reid_alignedreid/process.py index a579f24..835ce24 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/process.py +++ b/flow-python/examples/warehouse/reid_alignedreid/process.py @@ -14,9 +14,8 @@ import numpy as np from loguru import logger -__all__ = [ - "preprocess" -] +__all__ = ["preprocess"] + def preprocess(image, input_size, scale_im, mean, std, swap=(2, 0, 1)): if image is None: diff --git a/flow-python/examples/warehouse/reid_alignedreid/resnet.py b/flow-python/examples/warehouse/reid_alignedreid/resnet.py index aaafbdb..90cc355 100644 --- a/flow-python/examples/warehouse/reid_alignedreid/resnet.py +++ b/flow-python/examples/warehouse/reid_alignedreid/resnet.py @@ -12,193 +12,209 @@ import megengine.module as nn import math -__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', - 'resnet152'] +__all__ = [ + 'ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152' +] + def conv3x3(in_planes, out_planes, stride=1): - """3x3 convolution with padding""" - return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, - padding=1, bias=False) + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, + out_planes, + kernel_size=3, + stride=stride, + padding=1, + bias=False) class BasicBlock(nn.Module): - expansion = 1 + expansion = 1 - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(BasicBlock, self).__init__() - self.conv1 = conv3x3(inplanes, planes, stride) - self.bn1 = nn.BatchNorm2d(planes) - self.relu = nn.ReLU() - self.conv2 = conv3x3(planes, planes) - self.bn2 = nn.BatchNorm2d(planes) - self.downsample = downsample - self.stride = stride + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU() + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride - def forward(self, x): - residual = x + def forward(self, x): + residual = x - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) - out = self.conv2(out) - out = self.bn2(out) + out = self.conv2(out) + out = self.bn2(out) - if self.downsample is not None: - residual = self.downsample(x) + if self.downsample is not None: + residual = self.downsample(x) - out += residual - out = self.relu(out) + out += residual + out = self.relu(out) - return out + return out class Bottleneck(nn.Module): - expansion = 4 + expansion = 4 - def __init__(self, inplanes, planes, stride=1, downsample=None): - super(Bottleneck, self).__init__() - self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) - self.bn1 = nn.BatchNorm2d(planes) - self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, - padding=1, bias=False) - self.bn2 = nn.BatchNorm2d(planes) - self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) - self.bn3 = nn.BatchNorm2d(planes * 4) - self.relu = nn.ReLU() - self.downsample = downsample - self.stride = stride + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, + planes, + kernel_size=3, + stride=stride, + padding=1, + bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU() + self.downsample = downsample + self.stride = stride - def forward(self, x): - residual = x + def forward(self, x): + residual = x - out = self.conv1(x) - out = self.bn1(out) - out = self.relu(out) + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) - out = self.conv2(out) - out = self.bn2(out) - out = self.relu(out) + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) - out = self.conv3(out) - out = self.bn3(out) + out = self.conv3(out) + out = self.bn3(out) - if self.downsample is not None: - residual = self.downsample(x) + if self.downsample is not None: + residual = self.downsample(x) - out += residual - out = self.relu(out) + out += residual + out = self.relu(out) - return out + return out class ResNet(nn.Module): - - def __init__(self, block, layers): - self.inplanes = 64 - super(ResNet, self).__init__() - self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, - bias=False) - self.bn1 = nn.BatchNorm2d(64) - self.relu = nn.ReLU() - self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) - self.layer1 = self._make_layer(block, 64, layers[0]) - self.layer2 = self._make_layer(block, 128, layers[1], stride=2) - self.layer3 = self._make_layer(block, 256, layers[2], stride=2) - self.layer4 = self._make_layer(block, 512, layers[3], stride=2) - - for m in self.modules(): - if isinstance(m, nn.Conv2d): - n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels - nn.init.uniform_(m.weight, 0, math.sqrt(2./ n)) - elif isinstance(m, nn.BatchNorm2d): - nn.init.ones_(m.weight) - nn.init.zeros_(m.bias) - - def _make_layer(self, block, planes, blocks, stride=1): - downsample = None - if stride != 1 or self.inplanes != planes * block.expansion: - downsample = nn.Sequential( - nn.Conv2d(self.inplanes, planes * block.expansion, - kernel_size=1, stride=stride, bias=False), - nn.BatchNorm2d(planes * block.expansion), - ) - - layers = [] - layers.append(block(self.inplanes, planes, stride, downsample)) - self.inplanes = planes * block.expansion - for i in range(1, blocks): - layers.append(block(self.inplanes, planes)) - - return nn.Sequential(*layers) - - def forward(self, x): - x = self.conv1(x) - x = self.bn1(x) - x = self.relu(x) - x = self.maxpool(x) - - x = self.layer1(x) - x = self.layer2(x) - x = self.layer3(x) - x = self.layer4(x) - - return x + def __init__(self, block, layers): + self.inplanes = 64 + super(ResNet, self).__init__() + self.conv1 = nn.Conv2d(3, + 64, + kernel_size=7, + stride=2, + padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU() + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + nn.init.uniform_(m.weight, 0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + nn.init.ones_(m.weight) + nn.init.zeros_(m.bias) + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, + planes * block.expansion, + kernel_size=1, + stride=stride, + bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + return x def remove_fc(state_dict): - """Remove the fc layer parameters from state_dict.""" - for key in list(state_dict.keys()): - if key.startswith('fc.'): - del state_dict[key] - return state_dict + """Remove the fc layer parameters from state_dict.""" + for key in list(state_dict.keys()): + if key.startswith('fc.'): + del state_dict[key] + return state_dict def resnet18(): - """Constructs a ResNet-18 model. + """Constructs a ResNet-18 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ - model = ResNet(BasicBlock, [2, 2, 2, 2]) - return model + model = ResNet(BasicBlock, [2, 2, 2, 2]) + return model def resnet34(): - """Constructs a ResNet-34 model. + """Constructs a ResNet-34 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ - model = ResNet(BasicBlock, [3, 4, 6, 3]) - return model + model = ResNet(BasicBlock, [3, 4, 6, 3]) + return model def resnet50(): - """Constructs a ResNet-50 model. + """Constructs a ResNet-50 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ - model = ResNet(Bottleneck, [3, 4, 6, 3]) - return model + model = ResNet(Bottleneck, [3, 4, 6, 3]) + return model def resnet101(): - """Constructs a ResNet-101 model. + """Constructs a ResNet-101 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ - model = ResNet(Bottleneck, [3, 4, 23, 3]) - return model + model = ResNet(Bottleneck, [3, 4, 23, 3]) + return model def resnet152(): - """Constructs a ResNet-152 model. + """Constructs a ResNet-152 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ - model = ResNet(Bottleneck, [3, 8, 36, 3]) - return model + model = ResNet(Bottleneck, [3, 8, 36, 3]) + return model diff --git a/flow-python/examples/warehouse/track_iou/__init__.py b/flow-python/examples/warehouse/track_iou/__init__.py index 49caf13..73676d0 100644 --- a/flow-python/examples/warehouse/track_iou/__init__.py +++ b/flow-python/examples/warehouse/track_iou/__init__.py @@ -9,4 +9,4 @@ #!/usr/bin/env python # coding=utf-8 -from .track_iou import * +from .track_iou import Tracker diff --git a/flow-python/examples/warehouse/track_iou/track_iou.py b/flow-python/examples/warehouse/track_iou/track_iou.py index 17aaf0d..10d70f7 100644 --- a/flow-python/examples/warehouse/track_iou/track_iou.py +++ b/flow-python/examples/warehouse/track_iou/track_iou.py @@ -13,6 +13,7 @@ import numpy as np from scipy.optimize import linear_sum_assignment, leastsq + class CostGenerator: def __init__(self): self.linear_pred_funcs = [] @@ -105,9 +106,7 @@ def _get_results(self, use_smooth=True): else: bbox = tracker['boxes'][-1]['bbox'] - ret.append( - dict(tid=tracker_id, - bbox=bbox)) + ret.append(dict(tid=tracker_id, bbox=bbox)) return ret @@ -195,7 +194,7 @@ def _update_trackers(self, det_boxes): np.array([0]), [ det_box, ]) - + # return finished track id return failed_ids @@ -273,16 +272,17 @@ def update(self, x, y): def predict(self, x): return linear_func(self.param[0], x) + if __name__ == "__main__": def build_test_input1(): item1 = dict() - item1["bbox"] = np.array([10, 20, 300, 300]) + item1["bbox"] = np.array([10, 20, 300, 300]) item1["score"] = 0.7 item1["cls"] = int(15) item2 = dict() - item2["bbox"] = np.array([300, 300, 600, 600]) + item2["bbox"] = np.array([300, 300, 600, 600]) item2["score"] = 0.8 item2["cls"] = int(15) @@ -290,12 +290,12 @@ def build_test_input1(): def build_test_input2(): item1 = dict() - item1["bbox"] = np.array([60, 60, 360, 360]) + item1["bbox"] = np.array([60, 60, 360, 360]) item1["score"] = 0.77 item1["cls"] = int(15) item2 = dict() - item2["bbox"] = np.array([310, 310, 660, 660]) + item2["bbox"] = np.array([310, 310, 660, 660]) item2["score"] = 0.88 item2["cls"] = int(15) @@ -303,7 +303,7 @@ def build_test_input2(): def build_test_input3(): item1 = dict() - item1["bbox"] = np.array([60, 60, 360, 360]) + item1["bbox"] = np.array([60, 60, 360, 360]) item1["score"] = 0.77 item1["cls"] = int(15) @@ -329,4 +329,4 @@ def build_test_input3(): # clean all for i in range(10): - print(f'{t.track([])}') \ No newline at end of file + print(f'{t.track([])}') diff --git a/flow-python/megflow/command_line.py b/flow-python/megflow/command_line.py index 81d27b4..782a7c3 100644 --- a/flow-python/megflow/command_line.py +++ b/flow-python/megflow/command_line.py @@ -1,6 +1,5 @@ #!/usr/bin/env python # coding=utf-8 -import os import sys import subprocess import pkg_resources diff --git a/flow-python/megflow/registry.py b/flow-python/megflow/registry.py index 5f641a3..5007527 100644 --- a/flow-python/megflow/registry.py +++ b/flow-python/megflow/registry.py @@ -8,10 +8,6 @@ #!/usr/bin/env python # coding=utf-8 -import inspect -import ast -import types -import os from collections import Iterable def __register(name, inputs, outputs, exclusive, func): diff --git a/flow-python/setup.py b/flow-python/setup.py index d04b3db..460143c 100644 --- a/flow-python/setup.py +++ b/flow-python/setup.py @@ -9,10 +9,11 @@ #!/usr/bin/env python # coding=utf-8 -from setuptools import setup import sys import os +from setuptools import setup + devel_version = os.environ.get("DEVEL_VERSION") if not devel_version: devel_version = "0.1.0" # fall back diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..db110b9 --- /dev/null +++ b/pylintrc @@ -0,0 +1,610 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist=['cv2'] + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,_internal + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=print-statement, + no-else-return, + len-as-condition, + bad-continuation, + redefined-builtin, # TBD + arguments-differ, # TBD + invalid-name, # TBD + too-many-locals, # TBD + too-many-attributes, # TBD + too-many-arguments, # TBD + too-many-instance-attributes, # TBD + too-few-public-methods, # TBD + protected-access, # TBD + no-self-use, # TBD + cyclic-import, # TBD + no-else-raise, # TBD + line-too-long, # Although We ensure line length by YAPF, there are some cases YAPF won't split lines (e.g. comments). We just ignore these cases. + fixme, # Will be enable after a while + duplicate-code, # Will be enable after a while + missing-function-docstring, # Will be enable after a while + missing-module-docstring, # Will be enable after a while + missing-class-docstring, # Will be enable after a while + singleton-comparison, + parameter-unpacking, + unpacking-in-except, + old-raise-syntax, + backtick, + long-suffix, + old-ne-operator, + old-octal-literal, + import-star-module-level, + non-ascii-bytes-literal, + raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead, + apply-builtin, + basestring-builtin, + buffer-builtin, + cmp-builtin, + coerce-builtin, + execfile-builtin, + file-builtin, + long-builtin, + raw_input-builtin, + reduce-builtin, + standarderror-builtin, + unicode-builtin, + xrange-builtin, + coerce-method, + delslice-method, + getslice-method, + setslice-method, + no-absolute-import, + old-division, + dict-iter-method, + dict-view-method, + next-method-called, + metaclass-assignment, + indexing-exception, + raising-string, + reload-builtin, + oct-method, + hex-method, + nonzero-method, + cmp-method, + input-builtin, + round-builtin, + intern-builtin, + unichr-builtin, + map-builtin-not-iterating, + zip-builtin-not-iterating, + range-builtin-not-iterating, + filter-builtin-not-iterating, + using-cmp-argument, + eq-without-hash, + div-method, + idiv-method, + rdiv-method, + exception-message-attribute, + invalid-str-codec, + sys-max-int, + bad-python3-import, + deprecated-string-function, + deprecated-str-translate-call, + deprecated-itertools-function, + deprecated-types-field, + next-method-defined, + dict-items-not-iterating, + dict-keys-not-iterating, + dict-values-not-iterating, + deprecated-operator-function, + deprecated-urllib-function, + xreadlines-attribute, + deprecated-sys-function, + exception-escape, + comprehension-escape, + attribute-defined-outside-init, + logging-format-interpolation, + unsubscriptable-object, # pylint bug for numpy array + abstract-class-instantiated, # FIXME: Abstract class 'Tensor' with abstract methods instantiated + no-member, + import-error + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'error', 'warning', 'refactor', and 'convention' +# which contain the number of messages in each category, as well as 'statement' +# which is the total number of statements analyzed. This score is used by the +# global evaluation report (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members=numpy.*, torch.*, megbrain.*, cv2.* + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules=numpy.random + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[STRING] + +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps=no + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it work, +# install the python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=88 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + f, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception +