withopen(train_txt_path, "w") as f: for filename in os.listdir(train_dir): if filename.endswith(".jpg") or filename.endswith(".png"): # 添加你的图像文件扩展名 file_path = os.path.join(train_dir, filename) f.write(file_path + "\n")
print(f"train2017.txt has been created at {train_txt_path}")
withopen(val_txt_path, "w") as f: for filename in os.listdir(val_dir): if filename.endswith(".jpg") or filename.endswith(".png"): # 添加你的图像文件扩展名 file_path = os.path.join(val_dir, filename) f.write(file_path + "\n")
print(f"val2017.txt has been created at {val_txt_path}")
import os import test import torch import collections from pathlib import Path from models.yolo import Model from utils.datasets import create_dataloader
defload_yolov7_model(weight, device='cpu'): ckpt = torch.load(weight, map_location=device) model = Model("cfg/training/yolov7.yaml", ch=3, nc=80).to(device) state_dict = ckpt['model'].float().state_dict() model.load_state_dict(state_dict, strict=False) return model
# train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/] train:D:\\YOLO\\yolov7-qat\\yolov7-main\\dataset\\coco2017\\train2017.txt# 118287 images val:D:\\YOLO\\yolov7-qat\\yolov7-main\\dataset\\coco2017\\val2017.txt# 5000 images # test: ./coco/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
definitialize(float_module_list=None, custom_quant_modules=None): """Dynamic module replacement using monkey patching. Dynamically monkey patches the modules with their quantized versions. Internally, the state is maintained by a helper class object which helps in replacing the original modules back. Args: float_module_list: A list. User supplied list which indicates which modules to not monkey patch. custom_quant_modules: A dict. A mapping provided by user to indicate any other module apart from torch.nn and its corresponding quantized version. Returns: nothing. Typical usage example: # Define the deny list for torch.nn modules and custom map for modules other than torch.nn. float_module_list = ["Linear"] custom_quant_modules = [(torch.nn, "Linear", quant_nn.QuantLinear)] ## Monkey patch the modules pytorch_quantization.quant_modules.initialize(float_module_list, custom_modules) ## Use the quantized modules pytorch_quantization.quant_modules.deactivate() """ _quant_module_helper_object.prepare_state(float_module_list, custom_quant_modules) _quant_module_helper_object.apply_quant_modules()
@classmethod defset_default_quant_desc_input(cls, value): """ Args: value: An instance of :class:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>` """ ifnotisinstance(value, QuantDescriptor): raise ValueError("{} is not an instance of QuantDescriptor!") cls.default_quant_desc_input = copy.deepcopy(value)
@classmethod defset_default_quant_desc_weight(cls, value): """ Args: value: An instance of :class:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>` """ ifnotisinstance(value, QuantDescriptor): raise ValueError("{} is not an instance of QuantDescriptor!") cls.default_quant_desc_weight = copy.deepcopy(value)
definit_quantizer(self, quant_desc_input, quant_desc_weight, num_layers=None): """Helper function for __init__ of quantized module Create input and weight quantizer based on quant_desc passed by kwargs, or default of the class. Args: quant_desc_input: An instance of :class:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>` quant_desc_weight: An instance of :class:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>` num_layers: An integer. Default None. If not None, create a list of quantizers. """ ifnot inspect.stack()[1].function == "__init__": raise TypeError("{} should be only called by __init__ of quantized module.".format(__name__)) self._fake_quant = True if (not quant_desc_input.fake_quant) or (not quant_desc_weight.fake_quant): raise ValueError("Only fake quantization is supported!")
logging.info("Input is %squantized to %d bits in %s with axis %s!", "" ifnot quant_desc_input.fake_quant else"fake ", quant_desc_input.num_bits, self.__class__.__name__, quant_desc_input.axis) logging.info("Weight is %squantized to %d bits in %s with axis %s!", "" ifnot quant_desc_weight.fake_quant else"fake ", quant_desc_weight.num_bits, self.__class__.__name__, quant_desc_weight.axis)
if num_layers isNone: self._input_quantizer = TensorQuantizer(quant_desc_input) self._weight_quantizer = TensorQuantizer(quant_desc_weight) else: self._input_quantizers = nn.ModuleList([TensorQuantizer(quant_desc_input) for _ inrange(num_layers)]) self._weight_quantizers = nn.ModuleList([TensorQuantizer(quant_desc_weight) for _ inrange(num_layers)])
classScaledQuantDescriptor(): """Supportive descriptor of quantization Describe how a tensor should be quantized. A QuantDescriptor and a tensor defines a quantized tensor. Args: num_bits: An integer. Number of bits of quantization. It is used to calculate scaling factor. Default 8. name: Seems a nice thing to have Keyword Arguments: fake_quant: A boolean. If True, use fake quantization mode. Default True. axis: None, int or tuple of int. axes which will have its own max for computing scaling factor. If None (the default), use per tensor scale. Must be in the range [-rank(input_tensor), rank(input_tensor)). e.g. For a KCRS weight tensor, quant_axis=(0) will yield per channel scaling. Default None. amax: A float or list/ndarray of floats of user specified absolute max range. If supplied, ignore quant_axis and use this to quantize. If learn_amax is True, will be used to initialize learnable amax. Default None. learn_amax: A boolean. If True, learn amax. Default False. scale_amax: A float. If supplied, multiply amax by scale_amax. Default None. It is useful for some quick experiment. calib_method: A string. One of ["max", "histogram"] indicates which calibration to use. Except the simple max calibration, other methods are all hisogram based. Default "max". unsigned: A Boolean. If True, use unsigned. Default False. Raises: TypeError: If unsupported type is passed in. Read-only properties: - fake_quant: - name: - learn_amax: - scale_amax: - axis: - calib_method: - num_bits: - amax: - unsigned: """
classTensorQuantizer(nn.Module): """Tensor quantizer module This module uses tensor_quant or fake_tensor_quant function to quantize a tensor. And wrappers variable, moving statistics we'd want when training a quantized network. Experimental features: ``clip`` stage learns range before enabling quantization. ``calib`` stage runs calibration Args: quant_desc: An instance of :func:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>`. disabled: A boolean. If True, by pass the whole module returns input. Default False. if_quant: A boolean. If True, run main quantization body. Default True. if_clip: A boolean. If True, clip before quantization and learn amax. Default False. if_calib: A boolean. If True, run calibration. Not implemented yet. Settings of calibration will probably go to :func:`QuantDescriptor <pytorch_quantization.tensor_quant.QuantDescriptor>`. Raises: Readonly Properties: - axis: - fake_quant: - scale: - step_size: Mutable Properties: - num_bits: - unsigned: - amax: """
# An experimental static switch for using pytorch's native fake quantization # Primary usage is to export to ONNX use_fb_fake_quant = False
def__init__(self, quant_desc=QuantDescriptor(), disabled=False, if_quant=True, if_clip=False, if_calib=False): """Initialize quantizer and set up required variables""" ...
deftorch_module_find_quant_module(model, module_list, prefix=''): for name in model._modules: submodule = model._modules[name] path = name if prefix == ''else prefix + '.' + name torch_module_find_quant_module(submodule, module_list, prefix=path) # 递归
submodule_id = id(type(submodule)) if submodule_id in module_list: # 转换 model._modules[name] = transfer_torch_to_quantization(submodule, module_list[submodule_id])
import torch from models.yolo import Model from pytorch_quantization import calib from pytorch_quantization import quant_modules from pytorch_quantization.nn.modules import _utils as quant_nn_utils
defload_yolov7_model(weight, device='cpu'): ckpt = torch.load(weight, map_location=device) model = Model("cfg/training/yolov7.yaml", ch=3, nc=80).to(device) state_dict = ckpt['model'].float().state_dict() model.load_state_dict(state_dict, strict=False) return model
defprepare_model(weight, device): model = load_yolov7_model(weight, device) model.float() model.eval() with torch.no_grad(): model.fuse() # conv bn 进行层的合并, 加速 return model
deftorch_module_find_quant_module(model, module_list, prefix=''): for name in model._modules: submodule = model._modules[name] path = name if prefix == ''else prefix + '.' + name torch_module_find_quant_module(submodule, module_list, prefix=path) # 递归
submodule_id = id(type(submodule)) if submodule_id in module_list: # 转换 model._modules[name] = transfer_torch_to_quantization(submodule, module_list[submodule_id]) defreplace_to_quantization_model(model): module_list = {} for entry in quant_modules._DEFAULT_QUANT_MAP: module = getattr(entry.orig_mod, entry.mod_name) # module -> torch.nn.modules.conv.Conv1d module_list[id(module)] = entry.replace_mod torch_module_find_quant_module(model, module_list)
下面我们手动来实现 initialize,不使用默认的 Max 量化器而是去使用直方图,我们来看下应该怎么去操作。
initialize 函数的实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
from absl import logging as quant_logging from pytorch_quantization import nn as quant_nn from pytorch_quantization.tensor_quant import QuantDescriptor