"git@developer.sourcefind.cn:OpenDAS/torch-sparce.git" did not exist on "6f6c92855d0f0c4ea0a70651e3094b92b736f093"
Commit 5f71fde2 authored by Miquel Jubert Hermoso's avatar Miquel Jubert Hermoso Committed by Facebook GitHub Bot
Browse files

Change reference from modeling to directly qconfig

Summary:
Pull Request resolved: https://github.com/facebookresearch/d2go/pull/239

*This diff is part of a stack which has the goal of "buckifying" D2 (https://github.com/facebookresearch/d2go/commit/87374efb134e539090e0b5c476809dc35bf6aedb)Go core and enabling autodeps and other tooling. The last diff in the stack introduces the TARGETS. The diffs earlier in the stack are resolving circular dependencies and other issues which prevent the buckification from occurring.*

Break cyclic dependency by referring directly to the source file, instead to a different file that imports it.

Reviewed By: tglik

Differential Revision: D36166602

fbshipit-source-id: 7deafc02a52ab978a21593184d1b3d3810dc9346
parent ca094a0a
...@@ -8,7 +8,7 @@ import logging ...@@ -8,7 +8,7 @@ import logging
import torch import torch
import torch.nn as nn import torch.nn as nn
from d2go.export.api import PredictorExportConfig from d2go.export.api import PredictorExportConfig
from d2go.quantization.modeling import set_backend_and_create_qconfig from d2go.quantization.qconfig import set_backend_and_create_qconfig
from detectron2.modeling import GeneralizedRCNN from detectron2.modeling import GeneralizedRCNN
from detectron2.modeling.backbone.fpn import FPN from detectron2.modeling.backbone.fpn import FPN
from detectron2.modeling.postprocessing import detector_postprocess from detectron2.modeling.postprocessing import detector_postprocess
......
...@@ -15,7 +15,8 @@ from detectron2.engine import HookBase, SimpleTrainer ...@@ -15,7 +15,8 @@ from detectron2.engine import HookBase, SimpleTrainer
from mobile_cv.arch.quantization.observer import update_stat as observer_update_stat from mobile_cv.arch.quantization.observer import update_stat as observer_update_stat
from mobile_cv.arch.utils import fuse_utils from mobile_cv.arch.utils import fuse_utils
from mobile_cv.common.misc.iter_utils import recursive_iterate from mobile_cv.common.misc.iter_utils import recursive_iterate
from mobile_cv.common.misc.registry import Registry
from .qconfig import set_backend_and_create_qconfig, smart_decode_backend
TORCH_VERSION: Tuple[int, ...] = tuple(int(x) for x in torch.__version__.split(".")[:2]) TORCH_VERSION: Tuple[int, ...] = tuple(int(x) for x in torch.__version__.split(".")[:2])
if TORCH_VERSION > (1, 10): if TORCH_VERSION > (1, 10):
...@@ -210,108 +211,6 @@ def mock_quantization_type(quant_func): ...@@ -210,108 +211,6 @@ def mock_quantization_type(quant_func):
return wrapper return wrapper
def holistic_get_qconfig(backend, is_qat, use_symmetric=False):
"""
Config-less vanilla way to create the QConfig, suitable for explicitly creating qconfig.
"""
if use_symmetric:
if not backend == "qnnpack":
raise ValueError(
f"Only qnnpack supports Symmetric quantization, given: {backend}"
)
if is_qat:
return torch.ao.quantization.default_symmetric_qnnpack_qat_qconfig
else:
return torch.ao.quantization.default_symmetric_qnnpack_qconfig
else:
if is_qat:
return torch.ao.quantization.get_default_qat_qconfig(backend)
else:
return torch.ao.quantization.get_default_qconfig(backend)
def validate_native_backend(backend):
_PYTORCH_NATIVE_BACKENDS = ["fbgemm", "qnnpack"]
if backend not in _PYTORCH_NATIVE_BACKENDS:
raise ValueError(
f"Unrecognized backend: {backend}, PyTorch"
f" supported backends are: {_PYTORCH_NATIVE_BACKENDS}"
)
def _smart_parse_extended_backend(extended_backend):
"""
D2Go extends the definition of quantization "backend". In addition to PyTorch's
native backends (i.e. qnnpack and fbgemm), we allow other type of backend so users
can easily express different settings. Here are the supported cases:
1. Symmetric quantization: "qnnpack@symmetric" refers to using QNNPACK with
symmetric QConfig.
"""
backend = extended_backend
# default options
options = {
"is_symmetric": False,
}
if "@symmetric" in backend:
options["is_symmetric"] = True
backend = backend.replace("@symmetric", "", 1)
validate_native_backend(backend)
return backend, options
def _smart_decode_backend(extended_backend):
"""
Since we extend the definition of quantization backend, user shouldn't directly use
cfg.QUANTIZATION.BACKEND under PyTorch's context, this is the translation function
if direct use is necessary.
"""
return _smart_parse_extended_backend(extended_backend)[0]
QCONFIG_CREATOR_REGISTRY = Registry("QCONFIG_CREATOR_REGISTRY")
@QCONFIG_CREATOR_REGISTRY.register("smart")
def _smart_set_backend_and_create_qconfig(cfg, *, is_train):
"""
This is the default / "smart" way to create qconfig based on various of configs,
supports:
- learnable QAT
- set symmetric quantization via backend.
"""
backend, options = _smart_parse_extended_backend(cfg.QUANTIZATION.BACKEND)
is_symmetric = options["is_symmetric"]
# Set backend
torch.backends.quantized.engine = backend
qat_method = cfg.QUANTIZATION.QAT.FAKE_QUANT_METHOD
assert qat_method in ["default", "learnable"]
qconfig = holistic_get_qconfig(
backend=backend, is_qat=is_train, use_symmetric=is_symmetric
)
if is_train and qat_method == "learnable":
qconfig = learnable_qat.convert_to_learnable_qconfig(qconfig)
return qconfig
def set_backend_and_create_qconfig(cfg, *, is_train):
"""
Recommended function to create qconfig given D2Go's quantization config.
"""
# In case we need different implmentation, we can add a new key called
# QUANTIZATION.QCONFIG_CREATOR with "smart" as default value, and use this key
# to toggle between registries.
return QCONFIG_CREATOR_REGISTRY.get("smart")(cfg, is_train=is_train)
def default_prepare_for_quant(cfg, model): def default_prepare_for_quant(cfg, model):
""" """
Default implementation of preparing a model for quantization. This function will Default implementation of preparing a model for quantization. This function will
...@@ -445,7 +344,7 @@ def setup_qat_model( ...@@ -445,7 +344,7 @@ def setup_qat_model(
device = model_fp32.device device = model_fp32.device
# FIXME: seems that we can remove this # FIXME: seems that we can remove this
torch.backends.quantized.engine = _smart_decode_backend(cfg.QUANTIZATION.BACKEND) torch.backends.quantized.engine = smart_decode_backend(cfg.QUANTIZATION.BACKEND)
qat_method = cfg.QUANTIZATION.QAT.FAKE_QUANT_METHOD qat_method = cfg.QUANTIZATION.QAT.FAKE_QUANT_METHOD
# prepare for qat may modify the fp32 model directly so we create a copy # prepare for qat may modify the fp32 model directly so we create a copy
......
from typing import Tuple
import torch
from d2go.quantization import learnable_qat
from mobile_cv.common.misc.registry import Registry
TORCH_VERSION: Tuple[int, ...] = tuple(int(x) for x in torch.__version__.split(".")[:2])
if TORCH_VERSION > (1, 10):
from torch.ao.quantization.quantize_fx import convert_fx, prepare_fx, prepare_qat_fx
else:
from torch.quantization.quantize_fx import convert_fx, prepare_fx, prepare_qat_fx
QCONFIG_CREATOR_REGISTRY = Registry("QCONFIG_CREATOR_REGISTRY")
def set_backend_and_create_qconfig(cfg, *, is_train):
"""
Recommended function to create qconfig given D2Go's quantization config.
"""
# In case we need different implmentation, we can add a new key called
# QUANTIZATION.QCONFIG_CREATOR with "smart" as default value, and use this key
# to toggle between registries.
return QCONFIG_CREATOR_REGISTRY.get("smart")(cfg, is_train=is_train)
def holistic_get_qconfig(backend, is_qat, use_symmetric=False):
"""
Config-less vanilla way to create the QConfig, suitable for explicitly creating qconfig.
"""
if use_symmetric:
if not backend == "qnnpack":
raise ValueError(
f"Only qnnpack supports Symmetric quantization, given: {backend}"
)
if is_qat:
return torch.ao.quantization.default_symmetric_qnnpack_qat_qconfig
else:
return torch.ao.quantization.default_symmetric_qnnpack_qconfig
else:
if is_qat:
return torch.ao.quantization.get_default_qat_qconfig(backend)
else:
return torch.ao.quantization.get_default_qconfig(backend)
@QCONFIG_CREATOR_REGISTRY.register("smart")
def _smart_set_backend_and_create_qconfig(cfg, *, is_train):
"""
This is the default / "smart" way to create qconfig based on various of configs,
supports:
- learnable QAT
- set symmetric quantization via backend.
"""
backend, options = _smart_parse_extended_backend(cfg.QUANTIZATION.BACKEND)
is_symmetric = options["is_symmetric"]
# Set backend
torch.backends.quantized.engine = backend
qat_method = cfg.QUANTIZATION.QAT.FAKE_QUANT_METHOD
assert qat_method in ["default", "learnable"]
qconfig = holistic_get_qconfig(
backend=backend, is_qat=is_train, use_symmetric=is_symmetric
)
if is_train and qat_method == "learnable":
qconfig = learnable_qat.convert_to_learnable_qconfig(qconfig)
return qconfig
def validate_native_backend(backend):
_PYTORCH_NATIVE_BACKENDS = ["fbgemm", "qnnpack"]
if backend not in _PYTORCH_NATIVE_BACKENDS:
raise ValueError(
f"Unrecognized backend: {backend}, PyTorch"
f" supported backends are: {_PYTORCH_NATIVE_BACKENDS}"
)
def _smart_parse_extended_backend(extended_backend):
"""
D2Go extends the definition of quantization "backend". In addition to PyTorch's
native backends (i.e. qnnpack and fbgemm), we allow other type of backend so users
can easily express different settings. Here are the supported cases:
1. Symmetric quantization: "qnnpack@symmetric" refers to using QNNPACK with
symmetric QConfig.
"""
backend = extended_backend
# default options
options = {
"is_symmetric": False,
}
if "@symmetric" in backend:
options["is_symmetric"] = True
backend = backend.replace("@symmetric", "", 1)
validate_native_backend(backend)
return backend, options
def smart_decode_backend(extended_backend):
"""
Since we extend the definition of quantization backend, user shouldn't directly use
cfg.QUANTIZATION.BACKEND under PyTorch's context, this is the translation function
if direct use is necessary.
"""
return _smart_parse_extended_backend(extended_backend)[0]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment