chendl's picture
Add application file
0b7b08a
raw
history blame
4.46 kB
#!/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")]