Spaces:
Runtime error
Runtime error
#!/usr/bin/env python3 | |
# Copyright (c) Megvii, Inc. and its affiliates. All Rights Reserved | |
import glob | |
import importlib | |
import os | |
import sys | |
import time | |
from typing import List | |
__all__ = ["JitOp", "FastCOCOEvalOp"] | |
class JitOp: | |
""" | |
Just-in-time compilation of ops. | |
Some code of `JitOp` is inspired by `deepspeed.op_builder`, | |
check the following link for more details: | |
https://github.com/microsoft/DeepSpeed/blob/master/op_builder/builder.py | |
""" | |
def __init__(self, name): | |
self.name = name | |
def absolute_name(self) -> str: | |
"""Get absolute build path for cases where the op is pre-installed.""" | |
pass | |
def sources(self) -> List: | |
"""Get path list of source files of op. | |
NOTE: the path should be elative to root of package during building, | |
Otherwise, exception will be raised when building package. | |
However, for runtime building, path will be absolute. | |
""" | |
pass | |
def include_dirs(self) -> List: | |
""" | |
Get list of include paths, relative to root of package. | |
NOTE: the path should be elative to root of package. | |
Otherwise, exception will be raised when building package. | |
""" | |
return [] | |
def define_macros(self) -> List: | |
"""Get list of macros to define for op""" | |
return [] | |
def cxx_args(self) -> List: | |
"""Get optional list of compiler flags to forward""" | |
args = ["-O2"] if sys.platform == "win32" else ["-O3", "-std=c++14", "-g", "-Wno-reorder"] | |
return args | |
def nvcc_args(self) -> List: | |
"""Get optional list of compiler flags to forward to nvcc when building CUDA sources""" | |
args = [ | |
"-O3", "--use_fast_math", | |
"-std=c++17" if sys.platform == "win32" else "-std=c++14", | |
"-U__CUDA_NO_HALF_OPERATORS__", | |
"-U__CUDA_NO_HALF_CONVERSIONS__", | |
"-U__CUDA_NO_HALF2_OPERATORS__", | |
] | |
return args | |
def build_op(self): | |
from torch.utils.cpp_extension import CppExtension | |
return CppExtension( | |
name=self.absolute_name(), | |
sources=self.sources(), | |
include_dirs=self.include_dirs(), | |
define_macros=self.define_macros(), | |
extra_compile_args={ | |
"cxx": self.cxx_args(), | |
}, | |
) | |
def load(self, verbose=True): | |
try: | |
# try to import op from pre-installed package | |
return importlib.import_module(self.absolute_name()) | |
except Exception: # op not compiled, jit load | |
from yolox.utils import wait_for_the_master | |
with wait_for_the_master(): # to avoid race condition | |
return self.jit_load(verbose) | |
def jit_load(self, verbose=True): | |
from torch.utils.cpp_extension import load | |
from loguru import logger | |
try: | |
import ninja # noqa | |
except ImportError: | |
if verbose: | |
logger.warning( | |
f"Ninja is not installed, fall back to normal installation for {self.name}." | |
) | |
build_tik = time.time() | |
# build op and load | |
op_module = load( | |
name=self.name, | |
sources=self.sources(), | |
extra_cflags=self.cxx_args(), | |
extra_cuda_cflags=self.nvcc_args(), | |
verbose=verbose, | |
) | |
build_duration = time.time() - build_tik | |
if verbose: | |
logger.info(f"Load {self.name} op in {build_duration:.3f}s.") | |
return op_module | |
def clear_dynamic_library(self): | |
"""Remove dynamic libraray files generated by JIT compilation.""" | |
module = self.load() | |
os.remove(module.__file__) | |
class FastCOCOEvalOp(JitOp): | |
def __init__(self, name="fast_cocoeval"): | |
super().__init__(name=name) | |
def absolute_name(self): | |
return f'yolox.layers.{self.name}' | |
def sources(self): | |
sources = glob.glob(os.path.join("yolox", "layers", "cocoeval", "*.cpp")) | |
if not sources: # source will be empty list if the so file is removed after install | |
# use abosolute path to compile | |
import yolox | |
code_path = os.path.join(yolox.__path__[0], "layers", "cocoeval", "*.cpp") | |
sources = glob.glob(code_path) | |
return sources | |
def include_dirs(self): | |
return [os.path.join("yolox", "layers", "cocoeval")] | |