Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/compressed_tensors/__init__.py +22 -0
- lib/python3.12/site-packages/compressed_tensors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/__pycache__/version.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/base.py +20 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/__init__.py +22 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/helpers.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/base.py +197 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/helpers.py +137 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__init__.py +17 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__pycache__/model_compressor.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/model_compressor.py +580 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__init__.py +18 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/naive_quantized.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/pack_quantized.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/base.py +205 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/naive_quantized.py +148 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/pack_quantized.py +236 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__init__.py +19 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/dense.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_24_bitmask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_bitmask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/base.py +147 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/dense.py +42 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/sparse_24_bitmask.py +246 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/sparse_bitmask.py +169 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__init__.py +16 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/marlin_24.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/marlin_24.py +257 -0
- lib/python3.12/site-packages/compressed_tensors/config/__init__.py +19 -0
- lib/python3.12/site-packages/compressed_tensors/config/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/config/__pycache__/base.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/config/__pycache__/dense.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/config/__pycache__/sparse_24_bitmask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/config/__pycache__/sparse_bitmask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/config/base.py +111 -0
- lib/python3.12/site-packages/compressed_tensors/config/dense.py +36 -0
- lib/python3.12/site-packages/compressed_tensors/config/sparse_24_bitmask.py +40 -0
- lib/python3.12/site-packages/compressed_tensors/config/sparse_bitmask.py +36 -0
- lib/python3.12/site-packages/compressed_tensors/linear/__init__.py +13 -0
- lib/python3.12/site-packages/compressed_tensors/linear/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/compressed_tensors/linear/__pycache__/compressed_linear.cpython-312.pyc +0 -0
lib/python3.12/site-packages/compressed_tensors/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from .base import *
|
| 16 |
+
|
| 17 |
+
# flake8: noqa
|
| 18 |
+
from .compressors import *
|
| 19 |
+
from .config import *
|
| 20 |
+
from .quantization import QuantizationConfig, QuantizationStatus
|
| 21 |
+
from .utils import *
|
| 22 |
+
from .version import *
|
lib/python3.12/site-packages/compressed_tensors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (401 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (497 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/__pycache__/version.cpython-312.pyc
ADDED
|
Binary file (1.14 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/base.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
SPARSITY_CONFIG_NAME = "sparsity_config"
|
| 16 |
+
QUANTIZATION_CONFIG_NAME = "quantization_config"
|
| 17 |
+
COMPRESSION_CONFIG_NAME = "compression_config"
|
| 18 |
+
KV_CACHE_SCHEME_NAME = "kv_cache_scheme"
|
| 19 |
+
COMPRESSION_VERSION_NAME = "version"
|
| 20 |
+
QUANTIZATION_METHOD_NAME = "quant_method"
|
lib/python3.12/site-packages/compressed_tensors/compressors/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# flake8: noqa
|
| 16 |
+
|
| 17 |
+
from .base import *
|
| 18 |
+
from .helpers import *
|
| 19 |
+
from .model_compressors import *
|
| 20 |
+
from .quantized_compressors import *
|
| 21 |
+
from .sparse_compressors import *
|
| 22 |
+
from .sparse_quantized_compressors import *
|
lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (403 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (7.56 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/__pycache__/helpers.cpython-312.pyc
ADDED
|
Binary file (5.69 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/base.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from abc import ABC, abstractmethod
|
| 16 |
+
from typing import Dict, Generator, Optional, Tuple, Union
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from compressed_tensors.config import SparsityCompressionConfig
|
| 20 |
+
from compressed_tensors.quantization import QuantizationArgs, QuantizationConfig
|
| 21 |
+
from compressed_tensors.registry import RegistryMixin
|
| 22 |
+
from torch import Tensor
|
| 23 |
+
from torch.nn import Module
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
__all__ = ["BaseCompressor"]
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class BaseCompressor(RegistryMixin, ABC):
|
| 30 |
+
"""
|
| 31 |
+
Base class representing a model compression algorithm. Each child class should
|
| 32 |
+
implement compression_param_info, compress_weight and decompress_weight.
|
| 33 |
+
|
| 34 |
+
Compressors support compressing/decompressing a full module state dict or a single
|
| 35 |
+
quantized PyTorch leaf module.
|
| 36 |
+
|
| 37 |
+
Model Load Lifecycle (run_compressed=False):
|
| 38 |
+
- ModelCompressor.decompress()
|
| 39 |
+
- apply_quantization_config()
|
| 40 |
+
- BaseCompressor.decompress()
|
| 41 |
+
|
| 42 |
+
Model Save Lifecycle:
|
| 43 |
+
- ModelCompressor.compress()
|
| 44 |
+
- BaseCompressor.compress()
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
Module Lifecycle (run_compressed=True):
|
| 48 |
+
- apply_quantization_config()
|
| 49 |
+
- compressed_module = CompressedLinear(module)
|
| 50 |
+
- initialize_module_for_quantization()
|
| 51 |
+
- BaseCompressor.compression_param_info()
|
| 52 |
+
- register_parameters()
|
| 53 |
+
- compressed_module.forward()
|
| 54 |
+
-compressed_module.decompress()
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
:param config: config specifying compression parameters
|
| 58 |
+
"""
|
| 59 |
+
|
| 60 |
+
def __init__(
|
| 61 |
+
self, config: Union[SparsityCompressionConfig, QuantizationConfig, None] = None
|
| 62 |
+
):
|
| 63 |
+
self.config = config
|
| 64 |
+
|
| 65 |
+
def compression_param_info(
|
| 66 |
+
self,
|
| 67 |
+
weight_shape: torch.Size,
|
| 68 |
+
quantization_args: Optional[QuantizationArgs] = None,
|
| 69 |
+
) -> Dict[str, Tuple[torch.Size, torch.dtype]]:
|
| 70 |
+
"""
|
| 71 |
+
Creates a dictionary of expected shapes and dtypes for each compression
|
| 72 |
+
parameter used by the compressor
|
| 73 |
+
|
| 74 |
+
:param weight_shape: uncompressed weight shape
|
| 75 |
+
:param quantization_args: quantization parameters for the weight
|
| 76 |
+
:return: dictionary mapping compressed parameter names to shape and dtype
|
| 77 |
+
"""
|
| 78 |
+
raise NotImplementedError()
|
| 79 |
+
|
| 80 |
+
@property
|
| 81 |
+
@abstractmethod
|
| 82 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 83 |
+
"""
|
| 84 |
+
Returns a tuple of compression parameter names introduced by
|
| 85 |
+
the compressor during compression
|
| 86 |
+
"""
|
| 87 |
+
raise NotImplementedError()
|
| 88 |
+
|
| 89 |
+
@abstractmethod
|
| 90 |
+
def compress(
|
| 91 |
+
self,
|
| 92 |
+
model_state: Dict[str, Tensor],
|
| 93 |
+
**kwargs,
|
| 94 |
+
) -> Dict[str, Tensor]:
|
| 95 |
+
"""
|
| 96 |
+
Compresses a dense state dict
|
| 97 |
+
|
| 98 |
+
:param model_state: state dict of uncompressed model
|
| 99 |
+
:param kwargs: additional arguments for compression
|
| 100 |
+
:return: compressed state dict
|
| 101 |
+
"""
|
| 102 |
+
raise NotImplementedError()
|
| 103 |
+
|
| 104 |
+
@abstractmethod
|
| 105 |
+
def decompress(
|
| 106 |
+
self,
|
| 107 |
+
path_to_model_or_tensors: str,
|
| 108 |
+
device: str = "cpu",
|
| 109 |
+
**kwargs,
|
| 110 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 111 |
+
"""
|
| 112 |
+
Reads a compressed state dict located at path_to_model_or_tensors
|
| 113 |
+
and returns a generator for sequentially decompressing back to a
|
| 114 |
+
dense state dict
|
| 115 |
+
|
| 116 |
+
:param path_to_model_or_tensors: path to compressed safetensors model (directory
|
| 117 |
+
with one or more safetensors files) or compressed tensors file
|
| 118 |
+
:param names_to_scheme: quantization args for each quantized weight
|
| 119 |
+
:param device: optional device to load intermediate weights into
|
| 120 |
+
:return: compressed state dict
|
| 121 |
+
"""
|
| 122 |
+
raise NotImplementedError()
|
| 123 |
+
|
| 124 |
+
def compress_module(self, module: Module) -> Optional[Dict[str, torch.Tensor]]:
|
| 125 |
+
"""
|
| 126 |
+
Compresses a single quantized leaf PyTorch module. If the module is not
|
| 127 |
+
quantized, this function has no effect.
|
| 128 |
+
|
| 129 |
+
:param module: PyTorch module to compress
|
| 130 |
+
:return: dictionary of compressed weight data, or None if module is not
|
| 131 |
+
quantized
|
| 132 |
+
"""
|
| 133 |
+
if not hasattr(module, "quantization_scheme"):
|
| 134 |
+
return None # module is not quantized
|
| 135 |
+
quantization_scheme = module.quantization_scheme
|
| 136 |
+
if not hasattr(quantization_scheme, "weights"):
|
| 137 |
+
return None # weights are not quantized
|
| 138 |
+
|
| 139 |
+
quantization_args = quantization_scheme.weights
|
| 140 |
+
weight = getattr(module, "weight", None)
|
| 141 |
+
weight_scale = getattr(module, "weight_scale", None)
|
| 142 |
+
weight_zero_point = getattr(module, "weight_zero_point", None)
|
| 143 |
+
|
| 144 |
+
return self.compress_weight(
|
| 145 |
+
weight=weight,
|
| 146 |
+
scale=weight_scale,
|
| 147 |
+
zero_point=weight_zero_point,
|
| 148 |
+
quantization_args=quantization_args,
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
def compress_weight(
|
| 152 |
+
self,
|
| 153 |
+
weight: Tensor,
|
| 154 |
+
**kwargs,
|
| 155 |
+
) -> Dict[str, torch.Tensor]:
|
| 156 |
+
"""
|
| 157 |
+
Compresses a single uncompressed weight
|
| 158 |
+
|
| 159 |
+
:param weight: uncompressed weight tensor
|
| 160 |
+
:param kwargs: additional arguments for compression
|
| 161 |
+
"""
|
| 162 |
+
raise NotImplementedError()
|
| 163 |
+
|
| 164 |
+
def decompress_module(self, module: Module):
|
| 165 |
+
"""
|
| 166 |
+
Decompresses a single compressed leaf PyTorch module. If the module is not
|
| 167 |
+
quantized, this function has no effect.
|
| 168 |
+
|
| 169 |
+
:param module: PyTorch module to decompress
|
| 170 |
+
:return: tensor of the decompressed weight, or None if module is not quantized
|
| 171 |
+
"""
|
| 172 |
+
if not hasattr(module, "quantization_scheme"):
|
| 173 |
+
return None # module is not quantized
|
| 174 |
+
quantization_scheme = module.quantization_scheme
|
| 175 |
+
if not hasattr(quantization_scheme, "weights"):
|
| 176 |
+
return None # weights are not quantized
|
| 177 |
+
|
| 178 |
+
quantization_args = quantization_scheme.weights
|
| 179 |
+
compressed_data = {}
|
| 180 |
+
for name, parameter in module.named_parameters():
|
| 181 |
+
compressed_data[name] = parameter
|
| 182 |
+
|
| 183 |
+
return self.decompress_weight(
|
| 184 |
+
compressed_data=compressed_data, quantization_args=quantization_args
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
def decompress_weight(
|
| 188 |
+
self, compressed_data: Dict[str, Tensor], **kwargs
|
| 189 |
+
) -> torch.Tensor:
|
| 190 |
+
"""
|
| 191 |
+
Decompresses a single compressed weight
|
| 192 |
+
|
| 193 |
+
:param compressed_data: dictionary of data needed for decompression
|
| 194 |
+
:param kwargs: additional arguments for decompression
|
| 195 |
+
:return: tensor of the decompressed weight
|
| 196 |
+
"""
|
| 197 |
+
raise NotImplementedError()
|
lib/python3.12/site-packages/compressed_tensors/compressors/helpers.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from pathlib import Path
|
| 16 |
+
from typing import Dict, Generator, Optional, Tuple, Union
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from compressed_tensors.compressors import BaseCompressor
|
| 20 |
+
from compressed_tensors.config import CompressionFormat, SparsityCompressionConfig
|
| 21 |
+
from compressed_tensors.utils.safetensors_load import get_weight_mappings
|
| 22 |
+
from safetensors import safe_open
|
| 23 |
+
from safetensors.torch import save_file
|
| 24 |
+
from torch import Tensor
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
__all__ = [
|
| 28 |
+
"load_compressed",
|
| 29 |
+
"save_compressed",
|
| 30 |
+
"save_compressed_model",
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def save_compressed(
|
| 35 |
+
tensors: Dict[str, Tensor],
|
| 36 |
+
save_path: Union[str, Path],
|
| 37 |
+
compression_format: Optional[CompressionFormat] = None,
|
| 38 |
+
):
|
| 39 |
+
"""
|
| 40 |
+
Save compressed tensors to disk. If tensors are not compressed,
|
| 41 |
+
save them as is.
|
| 42 |
+
|
| 43 |
+
:param tensors: dictionary of tensors to compress
|
| 44 |
+
:param save_path: path to save compressed tensors
|
| 45 |
+
:param compression_format: compression format used for the tensors
|
| 46 |
+
:return: compression config, if tensors were compressed - None otherwise
|
| 47 |
+
"""
|
| 48 |
+
if tensors is None or len(tensors) == 0:
|
| 49 |
+
raise ValueError("No tensors or empty tensors provided to compress")
|
| 50 |
+
|
| 51 |
+
# if no compression_format specified, default to `dense`
|
| 52 |
+
compression_format = compression_format or CompressionFormat.dense.value
|
| 53 |
+
|
| 54 |
+
if not (
|
| 55 |
+
compression_format in BaseCompressor.registered_names()
|
| 56 |
+
or compression_format in BaseCompressor.registered_aliases()
|
| 57 |
+
):
|
| 58 |
+
raise ValueError(
|
| 59 |
+
f"Unknown compression format: {compression_format}. "
|
| 60 |
+
f"Must be one of {set(BaseCompressor.registered_names() + BaseCompressor.registered_aliases())}" # noqa E501
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
# compress
|
| 64 |
+
compressor = BaseCompressor.load_from_registry(compression_format)
|
| 65 |
+
# save compressed tensors
|
| 66 |
+
compressed_tensors = compressor.compress(tensors)
|
| 67 |
+
save_file(compressed_tensors, save_path)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def load_compressed(
|
| 71 |
+
compressed_tensors: Union[str, Path],
|
| 72 |
+
compression_config: SparsityCompressionConfig = None,
|
| 73 |
+
device: Optional[str] = "cpu",
|
| 74 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 75 |
+
"""
|
| 76 |
+
Load compressed tensors from disk.
|
| 77 |
+
If tensors are not compressed, load them as is.
|
| 78 |
+
|
| 79 |
+
:param compressed_tensors: path to compressed tensors.
|
| 80 |
+
This can be a path to a file or a directory containing
|
| 81 |
+
one or multiple safetensor files (if multiple - in the format
|
| 82 |
+
assumed by huggingface)
|
| 83 |
+
:param compression_config: compression config to use for decompressing tensors.
|
| 84 |
+
:param device: device to move tensors to. If None, tensors are loaded on CPU.
|
| 85 |
+
:param return_dict: if True, return a dictionary of decompressed tensors
|
| 86 |
+
:return a generator that yields the name and tensor of the decompressed tensor
|
| 87 |
+
"""
|
| 88 |
+
if compressed_tensors is None or not Path(compressed_tensors).exists():
|
| 89 |
+
raise ValueError("No compressed tensors provided to load")
|
| 90 |
+
|
| 91 |
+
if (
|
| 92 |
+
compression_config is None
|
| 93 |
+
or compression_config.format == CompressionFormat.dense.value
|
| 94 |
+
):
|
| 95 |
+
# if no compression_config specified, or `dense` format specified,
|
| 96 |
+
# assume tensors are not compressed on disk
|
| 97 |
+
weight_mappings = get_weight_mappings(compressed_tensors)
|
| 98 |
+
for weight_name, file_with_weight_name in weight_mappings.items():
|
| 99 |
+
with safe_open(file_with_weight_name, framework="pt", device=device) as f:
|
| 100 |
+
weight = f.get_tensor(weight_name)
|
| 101 |
+
yield weight_name, weight
|
| 102 |
+
else:
|
| 103 |
+
# decompress tensors
|
| 104 |
+
compression_format = compression_config.format
|
| 105 |
+
compressor = BaseCompressor.load_from_registry(
|
| 106 |
+
compression_format, config=compression_config
|
| 107 |
+
)
|
| 108 |
+
yield from compressor.decompress(compressed_tensors, device=device)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def save_compressed_model(
|
| 112 |
+
model: torch.nn.Module,
|
| 113 |
+
filename: str,
|
| 114 |
+
compression_format: Optional[CompressionFormat] = None,
|
| 115 |
+
force_contiguous: bool = True,
|
| 116 |
+
):
|
| 117 |
+
"""
|
| 118 |
+
Wrapper around safetensors `save_model` helper function, which allows for
|
| 119 |
+
saving compressed model to disk.
|
| 120 |
+
|
| 121 |
+
Note: The model is assumed to have a
|
| 122 |
+
state_dict with unique entries
|
| 123 |
+
|
| 124 |
+
:param model: model to save on disk
|
| 125 |
+
:param filename: filename location to save the file
|
| 126 |
+
:param compression_format: compression format used for the model
|
| 127 |
+
:param force_contiguous: forcing the state_dict to be saved as contiguous tensors
|
| 128 |
+
"""
|
| 129 |
+
state_dict = model.state_dict()
|
| 130 |
+
if force_contiguous:
|
| 131 |
+
state_dict = {k: v.contiguous() for k, v in state_dict.items()}
|
| 132 |
+
try:
|
| 133 |
+
save_compressed(state_dict, filename, compression_format=compression_format)
|
| 134 |
+
except ValueError as e:
|
| 135 |
+
msg = str(e)
|
| 136 |
+
msg += " Or use save_compressed_model(..., force_contiguous=True), read the docs for potential caveats." # noqa E501
|
| 137 |
+
raise ValueError(msg)
|
lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# flake8: noqa
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
from .model_compressor import *
|
lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (267 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/__pycache__/model_compressor.cpython-312.pyc
ADDED
|
Binary file (23.4 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/model_compressors/model_compressor.py
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import json
|
| 16 |
+
import logging
|
| 17 |
+
import operator
|
| 18 |
+
import os
|
| 19 |
+
import re
|
| 20 |
+
from contextlib import contextmanager
|
| 21 |
+
from copy import deepcopy
|
| 22 |
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Tuple, TypeVar, Union
|
| 23 |
+
|
| 24 |
+
import compressed_tensors
|
| 25 |
+
import torch
|
| 26 |
+
import transformers
|
| 27 |
+
from compressed_tensors.base import (
|
| 28 |
+
COMPRESSION_VERSION_NAME,
|
| 29 |
+
QUANTIZATION_CONFIG_NAME,
|
| 30 |
+
QUANTIZATION_METHOD_NAME,
|
| 31 |
+
SPARSITY_CONFIG_NAME,
|
| 32 |
+
)
|
| 33 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 34 |
+
from compressed_tensors.config import CompressionFormat, SparsityCompressionConfig
|
| 35 |
+
from compressed_tensors.quantization import (
|
| 36 |
+
DEFAULT_QUANTIZATION_METHOD,
|
| 37 |
+
QuantizationConfig,
|
| 38 |
+
QuantizationStatus,
|
| 39 |
+
apply_quantization_config,
|
| 40 |
+
load_pretrained_quantization,
|
| 41 |
+
)
|
| 42 |
+
from compressed_tensors.quantization.lifecycle import expand_target_names
|
| 43 |
+
from compressed_tensors.quantization.quant_args import QuantizationArgs
|
| 44 |
+
from compressed_tensors.quantization.utils import (
|
| 45 |
+
is_module_quantized,
|
| 46 |
+
iter_named_leaf_modules,
|
| 47 |
+
)
|
| 48 |
+
from compressed_tensors.utils import (
|
| 49 |
+
get_safetensors_folder,
|
| 50 |
+
merge_names,
|
| 51 |
+
update_parameter_data,
|
| 52 |
+
)
|
| 53 |
+
from compressed_tensors.utils.helpers import (
|
| 54 |
+
fix_fsdp_module_name,
|
| 55 |
+
is_compressed_tensors_config,
|
| 56 |
+
)
|
| 57 |
+
from torch import Tensor
|
| 58 |
+
from torch.nn import Module
|
| 59 |
+
from tqdm import tqdm
|
| 60 |
+
from transformers import AutoConfig
|
| 61 |
+
from transformers.file_utils import CONFIG_NAME
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
__all__ = ["ModelCompressor", "map_modules_to_quant_args"]
|
| 65 |
+
|
| 66 |
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
if TYPE_CHECKING:
|
| 70 |
+
# dummy type if not available from transformers
|
| 71 |
+
CompressedTensorsConfig = TypeVar("CompressedTensorsConfig")
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class ModelCompressor:
|
| 75 |
+
"""
|
| 76 |
+
Handles compression and decompression of a model with a sparsity config and/or
|
| 77 |
+
quantization config.
|
| 78 |
+
|
| 79 |
+
Compression LifeCycle
|
| 80 |
+
- compressor = ModelCompressor.from_pretrained_model(model)
|
| 81 |
+
- compressed_state_dict = compressor.compress(model, state_dict)
|
| 82 |
+
- compressor.quantization_compressor.compress(model, state_dict)
|
| 83 |
+
- compressor.sparsity_compressor.compress(model, state_dict)
|
| 84 |
+
- model.save_pretrained(output_dir, state_dict=compressed_state_dict)
|
| 85 |
+
- compressor.update_config(output_dir)
|
| 86 |
+
|
| 87 |
+
Decompression LifeCycle
|
| 88 |
+
- compressor = ModelCompressor.from_pretrained(comp_model_path)
|
| 89 |
+
- model = AutoModel.from_pretrained(comp_model_path)
|
| 90 |
+
- compressor.decompress(comp_model_path, model)
|
| 91 |
+
- compressor.sparsity_compressor.decompress(comp_model_path, model)
|
| 92 |
+
- compressor.quantization_compressor.decompress(comp_model_path, model)
|
| 93 |
+
|
| 94 |
+
:param sparsity_config: config specifying sparsity compression parameters
|
| 95 |
+
:param quantization_config: config specifying quantization compression parameters
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
@classmethod
|
| 99 |
+
def from_pretrained(
|
| 100 |
+
cls,
|
| 101 |
+
pretrained_model_name_or_path: str,
|
| 102 |
+
**kwargs,
|
| 103 |
+
) -> Optional["ModelCompressor"]:
|
| 104 |
+
"""
|
| 105 |
+
Given a path to a model config, extract the sparsity and/or quantization
|
| 106 |
+
configs and load a ModelCompressor
|
| 107 |
+
|
| 108 |
+
:param pretrained_model_name_or_path: path to model config on disk or HF hub
|
| 109 |
+
:return: compressor for the configs, or None if model is not compressed
|
| 110 |
+
"""
|
| 111 |
+
config = AutoConfig.from_pretrained(pretrained_model_name_or_path, **kwargs)
|
| 112 |
+
compression_config = getattr(config, QUANTIZATION_CONFIG_NAME, None)
|
| 113 |
+
return cls.from_compression_config(compression_config)
|
| 114 |
+
|
| 115 |
+
@classmethod
|
| 116 |
+
def from_compression_config(
|
| 117 |
+
cls,
|
| 118 |
+
compression_config: Union[Dict[str, Any], "CompressedTensorsConfig"],
|
| 119 |
+
):
|
| 120 |
+
"""
|
| 121 |
+
:param compression_config:
|
| 122 |
+
A compression or quantization config
|
| 123 |
+
|
| 124 |
+
The type is one of the following:
|
| 125 |
+
1. A Dict found under either "quantization_config" or "compression_config"
|
| 126 |
+
keys in the config.json
|
| 127 |
+
2. A CompressedTensorsConfig found under key "quantization_config" in HF
|
| 128 |
+
model config
|
| 129 |
+
:return: compressor for the configs, or None if model is not compressed
|
| 130 |
+
"""
|
| 131 |
+
if compression_config is None:
|
| 132 |
+
return None
|
| 133 |
+
|
| 134 |
+
sparsity_config = cls.parse_sparsity_config(compression_config)
|
| 135 |
+
quantization_config = cls.parse_quantization_config(compression_config)
|
| 136 |
+
if sparsity_config is None and quantization_config is None:
|
| 137 |
+
return None
|
| 138 |
+
|
| 139 |
+
if sparsity_config is not None:
|
| 140 |
+
format = sparsity_config.get("format")
|
| 141 |
+
sparsity_config = SparsityCompressionConfig.load_from_registry(
|
| 142 |
+
format, **sparsity_config
|
| 143 |
+
)
|
| 144 |
+
if quantization_config is not None:
|
| 145 |
+
quantization_config = QuantizationConfig.model_validate(quantization_config)
|
| 146 |
+
|
| 147 |
+
return cls(
|
| 148 |
+
sparsity_config=sparsity_config, quantization_config=quantization_config
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
@classmethod
|
| 152 |
+
def from_pretrained_model(
|
| 153 |
+
cls,
|
| 154 |
+
model: Module,
|
| 155 |
+
sparsity_config: Union[SparsityCompressionConfig, str, None] = None,
|
| 156 |
+
quantization_format: Optional[str] = None,
|
| 157 |
+
) -> Optional["ModelCompressor"]:
|
| 158 |
+
"""
|
| 159 |
+
Given a pytorch model and optional sparsity and/or quantization configs,
|
| 160 |
+
load the appropriate compressors
|
| 161 |
+
|
| 162 |
+
:param model: pytorch model to target for compression
|
| 163 |
+
:param sparsity_config: a filled in sparsity config or string corresponding
|
| 164 |
+
to a sparsity compression algorithm
|
| 165 |
+
:param quantization_format: string corresponding to a quantization compression
|
| 166 |
+
algorithm
|
| 167 |
+
:return: compressor for the configs, or None if model is not compressed
|
| 168 |
+
"""
|
| 169 |
+
quantization_config = QuantizationConfig.from_pretrained(
|
| 170 |
+
model, format=quantization_format
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
if isinstance(sparsity_config, str): # we passed in a sparsity format
|
| 174 |
+
sparsity_config = SparsityCompressionConfig.load_from_registry(
|
| 175 |
+
sparsity_config
|
| 176 |
+
)
|
| 177 |
+
|
| 178 |
+
if sparsity_config is None and quantization_config is None:
|
| 179 |
+
return None
|
| 180 |
+
|
| 181 |
+
return cls(
|
| 182 |
+
sparsity_config=sparsity_config, quantization_config=quantization_config
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
@staticmethod
|
| 186 |
+
def parse_sparsity_config(
|
| 187 |
+
compression_config: Union[Dict[str, Any], "CompressedTensorsConfig"]
|
| 188 |
+
) -> Union[Dict[str, Any], None]:
|
| 189 |
+
"""
|
| 190 |
+
Parse sparsity config from quantization/compression config. Sparsity
|
| 191 |
+
config is nested inside q/c config
|
| 192 |
+
|
| 193 |
+
:param compression_config: quantization/compression config
|
| 194 |
+
:return: sparsity config
|
| 195 |
+
"""
|
| 196 |
+
if compression_config is None:
|
| 197 |
+
return None
|
| 198 |
+
|
| 199 |
+
if is_compressed_tensors_config(compression_config):
|
| 200 |
+
s_config = compression_config.sparsity_config
|
| 201 |
+
return s_config.model_dump() if s_config is not None else None
|
| 202 |
+
|
| 203 |
+
return compression_config.get(SPARSITY_CONFIG_NAME, None)
|
| 204 |
+
|
| 205 |
+
@staticmethod
|
| 206 |
+
def parse_quantization_config(
|
| 207 |
+
compression_config: Union[Dict[str, Any], "CompressedTensorsConfig"]
|
| 208 |
+
) -> Union[Dict[str, Any], None]:
|
| 209 |
+
"""
|
| 210 |
+
Parse quantization config from quantization/compression config. The
|
| 211 |
+
quantization are all the fields that are not the sparsity config or
|
| 212 |
+
metadata fields
|
| 213 |
+
|
| 214 |
+
:param compression_config: quantization/compression config
|
| 215 |
+
:return: quantization config without sparsity config or metadata fields
|
| 216 |
+
"""
|
| 217 |
+
if compression_config is None:
|
| 218 |
+
return None
|
| 219 |
+
|
| 220 |
+
if is_compressed_tensors_config(compression_config):
|
| 221 |
+
q_config = compression_config.quantization_config
|
| 222 |
+
return q_config.model_dump() if q_config is not None else None
|
| 223 |
+
|
| 224 |
+
quantization_config = deepcopy(compression_config)
|
| 225 |
+
quantization_config.pop(SPARSITY_CONFIG_NAME, None)
|
| 226 |
+
|
| 227 |
+
# some fields are required, even if a qconfig is not present
|
| 228 |
+
# pop them off and if nothing remains, then there is no qconfig
|
| 229 |
+
quant_method = quantization_config.pop(QUANTIZATION_METHOD_NAME, None)
|
| 230 |
+
_ = quantization_config.pop(COMPRESSION_VERSION_NAME, None)
|
| 231 |
+
|
| 232 |
+
if len(quantization_config) == 0:
|
| 233 |
+
return None
|
| 234 |
+
|
| 235 |
+
# replace popped off values
|
| 236 |
+
# note that version is discarded for now
|
| 237 |
+
if quant_method is not None:
|
| 238 |
+
quantization_config[QUANTIZATION_METHOD_NAME] = quant_method
|
| 239 |
+
|
| 240 |
+
return quantization_config
|
| 241 |
+
|
| 242 |
+
def __init__(
|
| 243 |
+
self,
|
| 244 |
+
sparsity_config: Optional[SparsityCompressionConfig] = None,
|
| 245 |
+
quantization_config: Optional[QuantizationConfig] = None,
|
| 246 |
+
):
|
| 247 |
+
self.sparsity_config = sparsity_config
|
| 248 |
+
self.quantization_config = quantization_config
|
| 249 |
+
self.sparsity_compressor = None
|
| 250 |
+
self.quantization_compressor = None
|
| 251 |
+
|
| 252 |
+
if sparsity_config is not None:
|
| 253 |
+
self.sparsity_compressor = BaseCompressor.load_from_registry(
|
| 254 |
+
sparsity_config.format, config=sparsity_config
|
| 255 |
+
)
|
| 256 |
+
if quantization_config is not None:
|
| 257 |
+
self.quantization_compressor = BaseCompressor.load_from_registry(
|
| 258 |
+
quantization_config.format, config=quantization_config
|
| 259 |
+
)
|
| 260 |
+
|
| 261 |
+
def get_missing_module_keys(self, model: Module) -> List[str]:
|
| 262 |
+
"""
|
| 263 |
+
Identifies the expected missing weight keys in the compressed state_dict.
|
| 264 |
+
|
| 265 |
+
When a model undergoes sparsity or quantization compression, certain
|
| 266 |
+
weight tensors may be absent from the checkpoint by virtue of compression.
|
| 267 |
+
This function determines which weight keys are missing based on the
|
| 268 |
+
applied compression techniques.
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
:param model: The PyTorch model to check for missing keys.
|
| 272 |
+
:return: A list of missing keys expected in the compressed state_dict.
|
| 273 |
+
"""
|
| 274 |
+
missing_keys = set()
|
| 275 |
+
|
| 276 |
+
# Determine missing keys due to sparsity compression
|
| 277 |
+
if (
|
| 278 |
+
self.sparsity_compressor
|
| 279 |
+
and self.sparsity_config.format != CompressionFormat.dense.value
|
| 280 |
+
):
|
| 281 |
+
sparse_targets = expand_target_names(
|
| 282 |
+
model=model,
|
| 283 |
+
targets=self.sparsity_config.targets,
|
| 284 |
+
ignore=self.sparsity_config.ignore,
|
| 285 |
+
)
|
| 286 |
+
missing_keys.update(
|
| 287 |
+
merge_names(target, "weight") for target in sparse_targets
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
# Determine missing keys due to pack quantization
|
| 291 |
+
if (
|
| 292 |
+
self.quantization_compressor
|
| 293 |
+
and self.quantization_config.format
|
| 294 |
+
== CompressionFormat.pack_quantized.value
|
| 295 |
+
):
|
| 296 |
+
for scheme in self.quantization_config.config_groups.values():
|
| 297 |
+
quant_targets = expand_target_names(
|
| 298 |
+
model=model,
|
| 299 |
+
targets=scheme.targets,
|
| 300 |
+
ignore=self.quantization_config.ignore,
|
| 301 |
+
)
|
| 302 |
+
missing_keys.update(
|
| 303 |
+
merge_names(target, "weight") for target in quant_targets
|
| 304 |
+
)
|
| 305 |
+
|
| 306 |
+
return list(missing_keys)
|
| 307 |
+
|
| 308 |
+
def get_unexpected_file_keys(self, model: Module) -> List[str]:
|
| 309 |
+
"""
|
| 310 |
+
Identifies extra keys introduced by the compression process in the
|
| 311 |
+
compressed state_dict that are not expected by the model graph.
|
| 312 |
+
|
| 313 |
+
During sparsity or quantization compression, additional metadata or
|
| 314 |
+
auxiliary parameters may be stored in the checkpoint, which do not
|
| 315 |
+
correspond to any parameter in the original model. These keys are
|
| 316 |
+
typically introduced to support the reconstruction of compressed weights.
|
| 317 |
+
|
| 318 |
+
For example, Sparse24Bitmask compression may introduce keys such as
|
| 319 |
+
'compressed', 'bitmask', and 'shape' in the checkpoint, which are
|
| 320 |
+
not part of the original model parameters.
|
| 321 |
+
|
| 322 |
+
:param model: The PyTorch model to check for unexpected keys.
|
| 323 |
+
:return: A list of extra keys introduced by the compression process
|
| 324 |
+
that are not expected by the model.
|
| 325 |
+
"""
|
| 326 |
+
|
| 327 |
+
unexpected_keys = set()
|
| 328 |
+
|
| 329 |
+
# Identify unexpected keys from sparsity compression
|
| 330 |
+
if (
|
| 331 |
+
self.sparsity_compressor
|
| 332 |
+
and self.sparsity_config.format != CompressionFormat.dense.value
|
| 333 |
+
):
|
| 334 |
+
sparse_targets: Set[str] = expand_target_names(
|
| 335 |
+
model=model,
|
| 336 |
+
targets=self.sparsity_config.targets,
|
| 337 |
+
ignore=self.sparsity_config.ignore,
|
| 338 |
+
)
|
| 339 |
+
unexpected_keys.update(
|
| 340 |
+
merge_names(target, param)
|
| 341 |
+
for target in sparse_targets
|
| 342 |
+
for param in self.sparsity_compressor.compression_param_names
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
# Identify unexpected keys from quantization compression
|
| 346 |
+
if self.quantization_compressor:
|
| 347 |
+
for scheme in self.quantization_config.config_groups.values():
|
| 348 |
+
quant_targets: Set[str] = expand_target_names(
|
| 349 |
+
model=model,
|
| 350 |
+
targets=scheme.targets,
|
| 351 |
+
ignore=self.quantization_config.ignore,
|
| 352 |
+
)
|
| 353 |
+
unexpected_keys.update(
|
| 354 |
+
merge_names(target, param)
|
| 355 |
+
for target in quant_targets
|
| 356 |
+
for param in self.quantization_compressor.compression_param_names
|
| 357 |
+
if param != "weight"
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
return list(unexpected_keys)
|
| 361 |
+
|
| 362 |
+
def compress(
|
| 363 |
+
self, model: Module, state_dict: Optional[Dict[str, Tensor]] = None
|
| 364 |
+
) -> Dict[str, Tensor]:
|
| 365 |
+
"""
|
| 366 |
+
Compresses a dense state dict or model with sparsity and/or quantization
|
| 367 |
+
|
| 368 |
+
:param model: uncompressed model to compress
|
| 369 |
+
:param state_dict: optional uncompressed state_dict to insert into model
|
| 370 |
+
:return: compressed state dict
|
| 371 |
+
"""
|
| 372 |
+
if state_dict is None:
|
| 373 |
+
state_dict = model.state_dict()
|
| 374 |
+
|
| 375 |
+
compressed_state_dict = state_dict
|
| 376 |
+
|
| 377 |
+
quantized_modules_to_args: Dict[
|
| 378 |
+
str, QuantizationArgs
|
| 379 |
+
] = map_modules_to_quant_args(model)
|
| 380 |
+
|
| 381 |
+
if self.quantization_compressor is not None:
|
| 382 |
+
compressed_state_dict = self.quantization_compressor.compress(
|
| 383 |
+
state_dict, names_to_scheme=quantized_modules_to_args
|
| 384 |
+
)
|
| 385 |
+
if self.quantization_config.format != CompressionFormat.dense.value:
|
| 386 |
+
self.quantization_config.quantization_status = (
|
| 387 |
+
QuantizationStatus.COMPRESSED
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
if self.sparsity_compressor is not None:
|
| 391 |
+
sparse_compression_targets: Set[str] = expand_target_names(
|
| 392 |
+
model=model,
|
| 393 |
+
targets=self.sparsity_config.targets,
|
| 394 |
+
ignore=self.sparsity_config.ignore,
|
| 395 |
+
)
|
| 396 |
+
compressed_state_dict = self.sparsity_compressor.compress(
|
| 397 |
+
compressed_state_dict,
|
| 398 |
+
compression_targets=sparse_compression_targets,
|
| 399 |
+
)
|
| 400 |
+
|
| 401 |
+
# HACK: Override the dtype_byte_size function in transformers to
|
| 402 |
+
# support float8 types. Fix is posted upstream
|
| 403 |
+
# https://github.com/huggingface/transformers/pull/30488
|
| 404 |
+
transformers.modeling_utils.dtype_byte_size = new_dtype_byte_size
|
| 405 |
+
|
| 406 |
+
return compressed_state_dict
|
| 407 |
+
|
| 408 |
+
def decompress(self, model_path: str, model: Module):
|
| 409 |
+
"""
|
| 410 |
+
Overwrites the weights in model with weights decompressed from model_path
|
| 411 |
+
|
| 412 |
+
:param model_path: path to compressed weights
|
| 413 |
+
:param model: pytorch model to load decompressed weights into
|
| 414 |
+
"""
|
| 415 |
+
model_path = get_safetensors_folder(model_path)
|
| 416 |
+
sparse_decompressed = False
|
| 417 |
+
|
| 418 |
+
if (
|
| 419 |
+
self.sparsity_compressor is not None
|
| 420 |
+
and self.sparsity_config.format != CompressionFormat.dense.value
|
| 421 |
+
):
|
| 422 |
+
# Sparse decompression is applied on the model_path
|
| 423 |
+
dense_gen = self.sparsity_compressor.decompress(model_path)
|
| 424 |
+
self._replace_weights(dense_gen, model)
|
| 425 |
+
setattr(model, SPARSITY_CONFIG_NAME, self.sparsity_compressor.config)
|
| 426 |
+
sparse_decompressed = True
|
| 427 |
+
|
| 428 |
+
if self.quantization_compressor is not None:
|
| 429 |
+
# Temporarily set quantization status to FROZEN to prevent
|
| 430 |
+
# quantization during apply_quantization_config. This ensures
|
| 431 |
+
# that the dtypes of the weights are not unintentionally updated.
|
| 432 |
+
# The status is restored after quantization params are loaded.
|
| 433 |
+
with override_quantization_status(
|
| 434 |
+
self.quantization_config, QuantizationStatus.FROZEN
|
| 435 |
+
):
|
| 436 |
+
names_to_scheme = apply_quantization_config(
|
| 437 |
+
model, self.quantization_config
|
| 438 |
+
)
|
| 439 |
+
load_pretrained_quantization(model, model_path)
|
| 440 |
+
|
| 441 |
+
model_path_or_state_dict = (
|
| 442 |
+
model.state_dict() if sparse_decompressed else model_path
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
dense_gen = self.quantization_compressor.decompress(
|
| 446 |
+
model_path_or_state_dict, names_to_scheme=names_to_scheme
|
| 447 |
+
)
|
| 448 |
+
self._replace_weights(dense_gen, model)
|
| 449 |
+
|
| 450 |
+
def freeze_quantization_status(module):
|
| 451 |
+
module.quantization_status = QuantizationStatus.FROZEN
|
| 452 |
+
|
| 453 |
+
model.apply(freeze_quantization_status)
|
| 454 |
+
setattr(model, QUANTIZATION_CONFIG_NAME, self.quantization_config)
|
| 455 |
+
|
| 456 |
+
def update_config(self, save_directory: str):
|
| 457 |
+
"""
|
| 458 |
+
Update the model config located at save_directory with compression configs
|
| 459 |
+
for sparsity and/or quantization
|
| 460 |
+
|
| 461 |
+
:param save_directory: path to a folder containing a HF model config
|
| 462 |
+
"""
|
| 463 |
+
if self.quantization_config is None and self.sparsity_config is None:
|
| 464 |
+
return
|
| 465 |
+
|
| 466 |
+
config_file_path = os.path.join(save_directory, CONFIG_NAME)
|
| 467 |
+
if not os.path.exists(config_file_path):
|
| 468 |
+
_LOGGER.warning(
|
| 469 |
+
f"Could not find a valid model config file in "
|
| 470 |
+
f"{save_directory}. Compression config will not be saved."
|
| 471 |
+
)
|
| 472 |
+
return
|
| 473 |
+
|
| 474 |
+
with open(config_file_path, "r") as config_file:
|
| 475 |
+
config_data = json.load(config_file)
|
| 476 |
+
|
| 477 |
+
# required metadata whenever a quantization or sparsity config is present
|
| 478 |
+
# overwrite previous config and version if already existing
|
| 479 |
+
config_data[QUANTIZATION_CONFIG_NAME] = {}
|
| 480 |
+
config_data[QUANTIZATION_CONFIG_NAME][
|
| 481 |
+
COMPRESSION_VERSION_NAME
|
| 482 |
+
] = compressed_tensors.__version__
|
| 483 |
+
if self.quantization_config is not None:
|
| 484 |
+
self.quantization_config.quant_method = DEFAULT_QUANTIZATION_METHOD
|
| 485 |
+
else:
|
| 486 |
+
config_data[QUANTIZATION_CONFIG_NAME][
|
| 487 |
+
QUANTIZATION_METHOD_NAME
|
| 488 |
+
] = DEFAULT_QUANTIZATION_METHOD
|
| 489 |
+
|
| 490 |
+
# quantization and sparsity configs
|
| 491 |
+
if self.quantization_config is not None:
|
| 492 |
+
quant_config_data = self.quantization_config.model_dump()
|
| 493 |
+
config_data[QUANTIZATION_CONFIG_NAME] = quant_config_data
|
| 494 |
+
if self.sparsity_config is not None:
|
| 495 |
+
sparsity_config_data = self.sparsity_config.model_dump()
|
| 496 |
+
config_data[QUANTIZATION_CONFIG_NAME][
|
| 497 |
+
SPARSITY_CONFIG_NAME
|
| 498 |
+
] = sparsity_config_data
|
| 499 |
+
|
| 500 |
+
with open(config_file_path, "w") as config_file:
|
| 501 |
+
json.dump(config_data, config_file, indent=2, sort_keys=True)
|
| 502 |
+
|
| 503 |
+
def _replace_weights(self, dense_weight_generator, model: Module):
|
| 504 |
+
"""
|
| 505 |
+
Replace the weights of the model with the
|
| 506 |
+
provided dense weights.
|
| 507 |
+
|
| 508 |
+
This method iterates over the dense_weight_generator and
|
| 509 |
+
updates the corresponding weights in the model. If a parameter
|
| 510 |
+
name does not exist in the model, it will be skipped.
|
| 511 |
+
|
| 512 |
+
:param dense_weight_generator (generator): A generator that yields
|
| 513 |
+
tuples of (name, data), where 'name' is the parameter name and
|
| 514 |
+
'data' is the updated param data
|
| 515 |
+
:param model: The model whose weights are to be updated.
|
| 516 |
+
"""
|
| 517 |
+
for name, data in tqdm(dense_weight_generator, desc="Decompressing model"):
|
| 518 |
+
split_name = name.split(".")
|
| 519 |
+
prefix, param_name = ".".join(split_name[:-1]), split_name[-1]
|
| 520 |
+
module = operator.attrgetter(prefix)(model)
|
| 521 |
+
if hasattr(module, param_name):
|
| 522 |
+
update_parameter_data(module, data, param_name)
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
def map_modules_to_quant_args(
|
| 526 |
+
model: Module,
|
| 527 |
+
) -> Dict[str, Union[QuantizationArgs, Tuple[QuantizationArgs, QuantizationArgs]]]:
|
| 528 |
+
"""
|
| 529 |
+
Given a pytorch model, map out the submodule name (usually linear layers)
|
| 530 |
+
to the weight QuantizationArgs. If running input activation quantization, will also
|
| 531 |
+
map to the input QuantizationArgs in a tuple.
|
| 532 |
+
|
| 533 |
+
:param model: pytorch model
|
| 534 |
+
"""
|
| 535 |
+
quantized_modules_to_args = {}
|
| 536 |
+
for name, submodule in iter_named_leaf_modules(model):
|
| 537 |
+
if is_module_quantized(submodule):
|
| 538 |
+
if submodule.quantization_scheme.weights is not None:
|
| 539 |
+
name = fix_fsdp_module_name(name)
|
| 540 |
+
quantized_modules_to_args[name] = submodule.quantization_scheme.weights
|
| 541 |
+
if submodule.quantization_scheme.input_activations is not None:
|
| 542 |
+
weight_args = quantized_modules_to_args.get(name)
|
| 543 |
+
quantized_modules_to_args[name] = (
|
| 544 |
+
weight_args,
|
| 545 |
+
submodule.quantization_scheme.input_activations,
|
| 546 |
+
)
|
| 547 |
+
|
| 548 |
+
return quantized_modules_to_args
|
| 549 |
+
|
| 550 |
+
|
| 551 |
+
# HACK: Override the dtype_byte_size function in transformers to support float8 types
|
| 552 |
+
# Fix is posted upstream https://github.com/huggingface/transformers/pull/30488
|
| 553 |
+
def new_dtype_byte_size(dtype):
|
| 554 |
+
if dtype == torch.bool:
|
| 555 |
+
return 1 / 8
|
| 556 |
+
bit_search = re.search(r"[^\d](\d+)_?", str(dtype))
|
| 557 |
+
if bit_search is None:
|
| 558 |
+
raise ValueError(f"`dtype` is not a valid dtype: {dtype}.")
|
| 559 |
+
bit_size = int(bit_search.groups()[0])
|
| 560 |
+
return bit_size // 8
|
| 561 |
+
|
| 562 |
+
|
| 563 |
+
@contextmanager
|
| 564 |
+
def override_quantization_status(
|
| 565 |
+
config: QuantizationConfig, status: QuantizationStatus
|
| 566 |
+
):
|
| 567 |
+
"""
|
| 568 |
+
Within this context, the quantization status will be set to the
|
| 569 |
+
supplied status. After the context exits, the original status
|
| 570 |
+
will be restored.
|
| 571 |
+
|
| 572 |
+
:param config: the quantization config to override
|
| 573 |
+
:param status: the status to temporarily set
|
| 574 |
+
"""
|
| 575 |
+
original_status = config.quantization_status
|
| 576 |
+
config.quantization_status = status
|
| 577 |
+
try:
|
| 578 |
+
yield
|
| 579 |
+
finally:
|
| 580 |
+
config.quantization_status = original_status
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# flake8: noqa
|
| 15 |
+
|
| 16 |
+
from .base import *
|
| 17 |
+
from .naive_quantized import *
|
| 18 |
+
from .pack_quantized import *
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (318 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (8.23 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/naive_quantized.cpython-312.pyc
ADDED
|
Binary file (5.67 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/__pycache__/pack_quantized.cpython-312.pyc
ADDED
|
Binary file (9.94 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/base.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import logging
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
from typing import Any, Dict, Generator, Tuple, Union
|
| 18 |
+
|
| 19 |
+
import torch
|
| 20 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 21 |
+
from compressed_tensors.quantization import QuantizationArgs
|
| 22 |
+
from compressed_tensors.utils import (
|
| 23 |
+
get_nested_mappings_from_state_dict,
|
| 24 |
+
get_nested_weight_mappings,
|
| 25 |
+
merge_names,
|
| 26 |
+
)
|
| 27 |
+
from safetensors import safe_open
|
| 28 |
+
from torch import Tensor
|
| 29 |
+
from tqdm import tqdm
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
| 33 |
+
|
| 34 |
+
__all__ = ["BaseQuantizationCompressor"]
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class BaseQuantizationCompressor(BaseCompressor):
|
| 38 |
+
"""
|
| 39 |
+
Base class representing a quant compression algorithm. Each child class should
|
| 40 |
+
implement compression_param_info, compress_weight and decompress_weight.
|
| 41 |
+
|
| 42 |
+
Compressors support compressing/decompressing a full module state dict or a single
|
| 43 |
+
quantized PyTorch leaf module.
|
| 44 |
+
|
| 45 |
+
Model Load Lifecycle (run_compressed=False):
|
| 46 |
+
- ModelCompressor.decompress()
|
| 47 |
+
- apply_quantization_config()
|
| 48 |
+
- BaseQuantizationCompressor.decompress()
|
| 49 |
+
- BaseQuantizationCompressor.decompress_weight()
|
| 50 |
+
|
| 51 |
+
Model Save Lifecycle:
|
| 52 |
+
- ModelCompressor.compress()
|
| 53 |
+
- BaseQuantizationCompressor.compress()
|
| 54 |
+
- BaseQuantizationCompressor.compress_weight()
|
| 55 |
+
|
| 56 |
+
Module Lifecycle (run_compressed=True):
|
| 57 |
+
- apply_quantization_config()
|
| 58 |
+
- compressed_module = CompressedLinear(module)
|
| 59 |
+
- initialize_module_for_quantization()
|
| 60 |
+
- BaseQuantizationCompressor.compression_param_info()
|
| 61 |
+
- register_parameters()
|
| 62 |
+
- compressed_module.forward()
|
| 63 |
+
- compressed_module.decompress()
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
:param config: config specifying compression parameters
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
def compress(
|
| 70 |
+
self,
|
| 71 |
+
model_state: Dict[str, Tensor],
|
| 72 |
+
names_to_scheme: Dict[str, QuantizationArgs],
|
| 73 |
+
**kwargs,
|
| 74 |
+
) -> Dict[str, Tensor]:
|
| 75 |
+
"""
|
| 76 |
+
Compresses a dense state dict
|
| 77 |
+
|
| 78 |
+
:param model_state: state dict of uncompressed model
|
| 79 |
+
:param names_to_scheme: quantization args for each quantized weight, needed for
|
| 80 |
+
quantize function to calculate bit depth
|
| 81 |
+
:return: compressed state dict
|
| 82 |
+
"""
|
| 83 |
+
compressed_dict = {}
|
| 84 |
+
weight_suffix = ".weight"
|
| 85 |
+
input_zp_suffix = ".input_zero_point"
|
| 86 |
+
weight_zp_suffix = ".weight_zero_point"
|
| 87 |
+
_LOGGER.debug(
|
| 88 |
+
f"Compressing model with {len(model_state)} parameterized layers..."
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
+
for name, value in tqdm(model_state.items(), desc="Quantized Compression"):
|
| 92 |
+
# check if the parameter we're compressing is the weight zp
|
| 93 |
+
# or the input zp
|
| 94 |
+
is_weight_zp = name.endswith(weight_zp_suffix)
|
| 95 |
+
is_input_zp = name.endswith(input_zp_suffix)
|
| 96 |
+
|
| 97 |
+
# if we're saving the weight zp, fetch weight quant args
|
| 98 |
+
if is_weight_zp:
|
| 99 |
+
quant_args_zp = names_to_scheme.get(name[: -(len(weight_zp_suffix))])
|
| 100 |
+
if isinstance(quant_args_zp, tuple):
|
| 101 |
+
# If tuple, first value is weight args, second is input args
|
| 102 |
+
quant_args_zp = quant_args_zp[0]
|
| 103 |
+
|
| 104 |
+
# if we're saving the input zp, fetch input quant args
|
| 105 |
+
if is_input_zp:
|
| 106 |
+
input_args_zp = names_to_scheme.get(name[: -(len(input_zp_suffix))])
|
| 107 |
+
if isinstance(input_args_zp, tuple):
|
| 108 |
+
# If tuple, first value is weight args, second is input args
|
| 109 |
+
input_args_zp = input_args_zp[-1]
|
| 110 |
+
|
| 111 |
+
if name.endswith(weight_suffix):
|
| 112 |
+
prefix = name[: -(len(weight_suffix))]
|
| 113 |
+
scale = model_state.get(merge_names(prefix, "weight_scale"), None)
|
| 114 |
+
zp = model_state.get(merge_names(prefix, "weight_zero_point"), None)
|
| 115 |
+
g_idx = model_state.get(merge_names(prefix, "weight_g_idx"), None)
|
| 116 |
+
if scale is not None:
|
| 117 |
+
# weight is quantized, compress it
|
| 118 |
+
if isinstance(names_to_scheme[prefix], tuple):
|
| 119 |
+
quant_args = names_to_scheme[prefix][0]
|
| 120 |
+
else:
|
| 121 |
+
quant_args = names_to_scheme[prefix]
|
| 122 |
+
|
| 123 |
+
compressed_data = self.compress_weight(
|
| 124 |
+
weight=value,
|
| 125 |
+
scale=scale,
|
| 126 |
+
zero_point=zp,
|
| 127 |
+
g_idx=g_idx,
|
| 128 |
+
quantization_args=quant_args,
|
| 129 |
+
device="cpu",
|
| 130 |
+
)
|
| 131 |
+
for key, value in compressed_data.items():
|
| 132 |
+
compressed_dict[merge_names(prefix, key)] = value
|
| 133 |
+
else:
|
| 134 |
+
compressed_dict[name] = value.to("cpu")
|
| 135 |
+
# only save if asym
|
| 136 |
+
elif is_weight_zp and quant_args_zp.symmetric:
|
| 137 |
+
continue
|
| 138 |
+
# only save if asym
|
| 139 |
+
elif is_input_zp and input_args_zp.symmetric:
|
| 140 |
+
continue
|
| 141 |
+
elif name.endswith("g_idx") and torch.any(value <= -1):
|
| 142 |
+
continue
|
| 143 |
+
else:
|
| 144 |
+
compressed_dict[name] = value.to("cpu")
|
| 145 |
+
|
| 146 |
+
return compressed_dict
|
| 147 |
+
|
| 148 |
+
def decompress(
|
| 149 |
+
self,
|
| 150 |
+
path_to_model_or_tensors: Union[str, Path, Dict[str, Any]],
|
| 151 |
+
names_to_scheme: Dict[str, QuantizationArgs],
|
| 152 |
+
device: str = "cpu",
|
| 153 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 154 |
+
"""
|
| 155 |
+
Reads a compressed state dict located at path_to_model_or_tensors
|
| 156 |
+
and returns a generator for sequentially decompressing back to a
|
| 157 |
+
dense state dict
|
| 158 |
+
:param path_to_model_or_tensors: path to compressed safetensors model (directory
|
| 159 |
+
with one or more safetensors files) or compressed tensors file
|
| 160 |
+
:param names_to_scheme: quantization args for each quantized weight
|
| 161 |
+
:param device: optional device to load intermediate weights into
|
| 162 |
+
:return: compressed state dict
|
| 163 |
+
"""
|
| 164 |
+
if isinstance(path_to_model_or_tensors, (str, Path)):
|
| 165 |
+
yield from self._decompress_from_path(
|
| 166 |
+
path_to_model_or_tensors, names_to_scheme, device
|
| 167 |
+
)
|
| 168 |
+
|
| 169 |
+
else:
|
| 170 |
+
yield from self._decompress_from_state_dict(
|
| 171 |
+
path_to_model_or_tensors, names_to_scheme
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
def _decompress_from_path(self, path_to_model, names_to_scheme, device):
|
| 175 |
+
weight_mappings = get_nested_weight_mappings(
|
| 176 |
+
path_to_model, self.compression_param_names
|
| 177 |
+
)
|
| 178 |
+
for weight_name in weight_mappings.keys():
|
| 179 |
+
weight_data = {}
|
| 180 |
+
for param_name, safe_path in weight_mappings[weight_name].items():
|
| 181 |
+
full_name = merge_names(weight_name, param_name)
|
| 182 |
+
with safe_open(safe_path, framework="pt", device=device) as f:
|
| 183 |
+
weight_data[param_name] = f.get_tensor(full_name)
|
| 184 |
+
if "weight_scale" in weight_data:
|
| 185 |
+
quant_args = names_to_scheme[weight_name]
|
| 186 |
+
decompressed = self.decompress_weight(
|
| 187 |
+
compressed_data=weight_data, quantization_args=quant_args
|
| 188 |
+
)
|
| 189 |
+
yield merge_names(weight_name, "weight"), decompressed
|
| 190 |
+
|
| 191 |
+
def _decompress_from_state_dict(self, state_dict, names_to_scheme):
|
| 192 |
+
weight_mappings = get_nested_mappings_from_state_dict(
|
| 193 |
+
state_dict, self.compression_param_names
|
| 194 |
+
)
|
| 195 |
+
for weight_name in weight_mappings.keys():
|
| 196 |
+
weight_data = {}
|
| 197 |
+
for param_name, param_value in weight_mappings[weight_name].items():
|
| 198 |
+
weight_data[param_name] = param_value
|
| 199 |
+
|
| 200 |
+
if "weight_scale" in weight_data:
|
| 201 |
+
quant_args = names_to_scheme[weight_name]
|
| 202 |
+
decompressed = self.decompress_weight(
|
| 203 |
+
compressed_data=weight_data, quantization_args=quant_args
|
| 204 |
+
)
|
| 205 |
+
yield merge_names(weight_name, "weight"), decompressed
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/naive_quantized.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Dict, Optional, Tuple
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 19 |
+
from compressed_tensors.compressors.quantized_compressors.base import (
|
| 20 |
+
BaseQuantizationCompressor,
|
| 21 |
+
)
|
| 22 |
+
from compressed_tensors.config import CompressionFormat
|
| 23 |
+
from compressed_tensors.quantization import QuantizationArgs
|
| 24 |
+
from compressed_tensors.quantization.lifecycle.forward import dequantize, quantize
|
| 25 |
+
from compressed_tensors.quantization.utils import can_quantize
|
| 26 |
+
from torch import Tensor
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
__all__ = [
|
| 30 |
+
"NaiveQuantizationCompressor",
|
| 31 |
+
"IntQuantizationCompressor",
|
| 32 |
+
"FloatQuantizationCompressor",
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@BaseCompressor.register(name=CompressionFormat.naive_quantized.value)
|
| 37 |
+
class NaiveQuantizationCompressor(BaseQuantizationCompressor):
|
| 38 |
+
"""
|
| 39 |
+
Implements naive compression for quantized models. Weight of each
|
| 40 |
+
quantized layer is converted from its original float type to the closest Pytorch
|
| 41 |
+
type to the type specified by the layer's QuantizationArgs.
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
@property
|
| 45 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 46 |
+
"""
|
| 47 |
+
Returns a tuple of compression parameter names introduced by
|
| 48 |
+
the compressor during compression
|
| 49 |
+
"""
|
| 50 |
+
return (
|
| 51 |
+
"weight",
|
| 52 |
+
"weight_scale",
|
| 53 |
+
"weight_zero_point",
|
| 54 |
+
"weight_g_idx",
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
def compression_param_info(
|
| 58 |
+
self,
|
| 59 |
+
weight_shape: torch.Size,
|
| 60 |
+
quantization_args: Optional[QuantizationArgs] = None,
|
| 61 |
+
) -> Dict[str, Tuple[torch.Size, torch.dtype]]:
|
| 62 |
+
"""
|
| 63 |
+
Creates a dictionary of expected shapes and dtypes for each compression
|
| 64 |
+
parameter used by the compressor
|
| 65 |
+
|
| 66 |
+
:param weight_shape: uncompressed weight shape
|
| 67 |
+
:param quantization_args: quantization parameters for the weight
|
| 68 |
+
:return: dictionary mapping compressed parameter names to shape and dtype
|
| 69 |
+
"""
|
| 70 |
+
dtype = quantization_args.pytorch_dtype()
|
| 71 |
+
return {"weight": (weight_shape, dtype)}
|
| 72 |
+
|
| 73 |
+
def compress_weight(
|
| 74 |
+
self,
|
| 75 |
+
weight: Tensor,
|
| 76 |
+
scale: Tensor,
|
| 77 |
+
quantization_args: QuantizationArgs,
|
| 78 |
+
zero_point: Optional[Tensor] = None,
|
| 79 |
+
g_idx: Optional[torch.Tensor] = None,
|
| 80 |
+
device: Optional[torch.device] = None,
|
| 81 |
+
) -> Dict[str, torch.Tensor]:
|
| 82 |
+
"""
|
| 83 |
+
Compresses a single uncompressed weight
|
| 84 |
+
|
| 85 |
+
:param weight: uncompressed weight tensor
|
| 86 |
+
:param scale: quantization scale for weight
|
| 87 |
+
:param quantization_args: quantization parameters for weight
|
| 88 |
+
:param zero_point: quantization zero point for weight
|
| 89 |
+
:param g_idx: optional mapping from column index to group index
|
| 90 |
+
:param device: optional device to move compressed output to
|
| 91 |
+
:return: dictionary of compressed weight data
|
| 92 |
+
"""
|
| 93 |
+
if can_quantize(weight, quantization_args):
|
| 94 |
+
quantized_weight = quantize(
|
| 95 |
+
x=weight,
|
| 96 |
+
scale=scale,
|
| 97 |
+
zero_point=zero_point,
|
| 98 |
+
g_idx=g_idx,
|
| 99 |
+
args=quantization_args,
|
| 100 |
+
dtype=quantization_args.pytorch_dtype(),
|
| 101 |
+
)
|
| 102 |
+
else:
|
| 103 |
+
quantized_weight = weight
|
| 104 |
+
|
| 105 |
+
if device is not None:
|
| 106 |
+
quantized_weight = quantized_weight.to(device)
|
| 107 |
+
|
| 108 |
+
return {"weight": quantized_weight}
|
| 109 |
+
|
| 110 |
+
def decompress_weight(
|
| 111 |
+
self,
|
| 112 |
+
compressed_data: Dict[str, Tensor],
|
| 113 |
+
quantization_args: Optional[QuantizationArgs] = None,
|
| 114 |
+
) -> torch.Tensor:
|
| 115 |
+
"""
|
| 116 |
+
Decompresses a single compressed weight
|
| 117 |
+
|
| 118 |
+
:param compressed_data: dictionary of data needed for decompression
|
| 119 |
+
:param quantization_args: quantization parameters for the weight
|
| 120 |
+
:return: tensor of the decompressed weight
|
| 121 |
+
"""
|
| 122 |
+
weight = compressed_data["weight"]
|
| 123 |
+
scale = compressed_data["weight_scale"]
|
| 124 |
+
zero_point = compressed_data.get("weight_zero_point", None)
|
| 125 |
+
g_idx = compressed_data.get("weight_g_idx", None)
|
| 126 |
+
decompressed_weight = dequantize(
|
| 127 |
+
x_q=weight, scale=scale, zero_point=zero_point, g_idx=g_idx
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
return decompressed_weight
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
@BaseCompressor.register(name=CompressionFormat.int_quantized.value)
|
| 134 |
+
class IntQuantizationCompressor(NaiveQuantizationCompressor):
|
| 135 |
+
"""
|
| 136 |
+
Alias for integer quantized models
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
pass
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
@BaseCompressor.register(name=CompressionFormat.float_quantized.value)
|
| 143 |
+
class FloatQuantizationCompressor(NaiveQuantizationCompressor):
|
| 144 |
+
"""
|
| 145 |
+
Alias for fp quantized models
|
| 146 |
+
"""
|
| 147 |
+
|
| 148 |
+
pass
|
lib/python3.12/site-packages/compressed_tensors/compressors/quantized_compressors/pack_quantized.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
import math
|
| 15 |
+
from typing import Dict, Optional, Tuple
|
| 16 |
+
|
| 17 |
+
import numpy as np
|
| 18 |
+
import torch
|
| 19 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 20 |
+
from compressed_tensors.compressors.quantized_compressors.base import (
|
| 21 |
+
BaseQuantizationCompressor,
|
| 22 |
+
)
|
| 23 |
+
from compressed_tensors.config import CompressionFormat
|
| 24 |
+
from compressed_tensors.quantization import QuantizationArgs
|
| 25 |
+
from compressed_tensors.quantization.lifecycle.forward import dequantize, quantize
|
| 26 |
+
from compressed_tensors.quantization.utils import can_quantize
|
| 27 |
+
from torch import Tensor
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
__all__ = ["PackedQuantizationCompressor", "pack_to_int32", "unpack_from_int32"]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@BaseCompressor.register(name=CompressionFormat.pack_quantized.value)
|
| 34 |
+
class PackedQuantizationCompressor(BaseQuantizationCompressor):
|
| 35 |
+
"""
|
| 36 |
+
Compresses a quantized model by packing every eight 4-bit weights into an int32
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
@property
|
| 40 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 41 |
+
"""
|
| 42 |
+
Returns a tuple of compression parameter names introduced by
|
| 43 |
+
the compressor during compression
|
| 44 |
+
"""
|
| 45 |
+
return (
|
| 46 |
+
"weight_packed",
|
| 47 |
+
"weight_scale",
|
| 48 |
+
"weight_zero_point",
|
| 49 |
+
"weight_g_idx",
|
| 50 |
+
"weight_shape",
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
def compression_param_info(
|
| 54 |
+
self,
|
| 55 |
+
weight_shape: torch.Size,
|
| 56 |
+
quantization_args: Optional[QuantizationArgs] = None,
|
| 57 |
+
) -> Dict[str, Tuple[torch.Size, torch.dtype]]:
|
| 58 |
+
"""
|
| 59 |
+
Creates a dictionary of expected shapes and dtypes for each compression
|
| 60 |
+
parameter used by the compressor
|
| 61 |
+
|
| 62 |
+
:param weight_shape: uncompressed weight shape
|
| 63 |
+
:param quantization_args: quantization parameters for the weight
|
| 64 |
+
:return: dictionary mapping compressed parameter names to shape and dtype
|
| 65 |
+
"""
|
| 66 |
+
pack_factor = 32 // quantization_args.num_bits
|
| 67 |
+
packed_size = math.ceil(weight_shape[1] / pack_factor)
|
| 68 |
+
return {
|
| 69 |
+
"weight_packed": (torch.Size((weight_shape[0], packed_size)), torch.int32),
|
| 70 |
+
"weight_shape": (torch.Size((2,)), torch.int32),
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
def compress_weight(
|
| 74 |
+
self,
|
| 75 |
+
weight: Tensor,
|
| 76 |
+
scale: Tensor,
|
| 77 |
+
quantization_args: QuantizationArgs,
|
| 78 |
+
zero_point: Optional[Tensor] = None,
|
| 79 |
+
g_idx: Optional[torch.Tensor] = None,
|
| 80 |
+
device: Optional[torch.device] = None,
|
| 81 |
+
) -> Dict[str, torch.Tensor]:
|
| 82 |
+
"""
|
| 83 |
+
Compresses a single uncompressed weight
|
| 84 |
+
|
| 85 |
+
:param weight: uncompressed weight tensor
|
| 86 |
+
:param scale: quantization scale for weight
|
| 87 |
+
:param quantization_args: quantization parameters for weight
|
| 88 |
+
:param zero_point: quantization zero point for weight
|
| 89 |
+
:param g_idx: optional mapping from column index to group index
|
| 90 |
+
:param device: optional device to move compressed output to
|
| 91 |
+
:return: dictionary of compressed weight data
|
| 92 |
+
"""
|
| 93 |
+
compressed_dict = {}
|
| 94 |
+
if can_quantize(weight, quantization_args):
|
| 95 |
+
quantized_weight = quantize(
|
| 96 |
+
x=weight,
|
| 97 |
+
scale=scale,
|
| 98 |
+
zero_point=zero_point,
|
| 99 |
+
g_idx=g_idx,
|
| 100 |
+
args=quantization_args,
|
| 101 |
+
dtype=torch.int8,
|
| 102 |
+
)
|
| 103 |
+
else:
|
| 104 |
+
quantized_weight = weight
|
| 105 |
+
|
| 106 |
+
packed_weight = pack_to_int32(quantized_weight, quantization_args.num_bits)
|
| 107 |
+
weight_shape = torch.tensor(weight.shape)
|
| 108 |
+
if device is not None:
|
| 109 |
+
packed_weight = packed_weight.to(device)
|
| 110 |
+
weight_shape = weight_shape.to(device)
|
| 111 |
+
|
| 112 |
+
compressed_dict["weight_shape"] = weight_shape
|
| 113 |
+
compressed_dict["weight_packed"] = packed_weight
|
| 114 |
+
|
| 115 |
+
return compressed_dict
|
| 116 |
+
|
| 117 |
+
def decompress_weight(
|
| 118 |
+
self,
|
| 119 |
+
compressed_data: Dict[str, Tensor],
|
| 120 |
+
quantization_args: Optional[QuantizationArgs] = None,
|
| 121 |
+
) -> torch.Tensor:
|
| 122 |
+
"""
|
| 123 |
+
Decompresses a single compressed weight
|
| 124 |
+
|
| 125 |
+
:param compressed_data: dictionary of data needed for decompression
|
| 126 |
+
:param quantization_args: quantization parameters for the weight
|
| 127 |
+
:return: tensor of the decompressed weight
|
| 128 |
+
"""
|
| 129 |
+
weight = compressed_data["weight_packed"]
|
| 130 |
+
scale = compressed_data["weight_scale"]
|
| 131 |
+
zero_point = compressed_data.get("weight_zero_point", None)
|
| 132 |
+
g_idx = compressed_data.get("weight_g_idx", None)
|
| 133 |
+
original_shape = torch.Size(compressed_data["weight_shape"])
|
| 134 |
+
num_bits = quantization_args.num_bits
|
| 135 |
+
unpacked = unpack_from_int32(weight, num_bits, original_shape)
|
| 136 |
+
decompressed_weight = dequantize(
|
| 137 |
+
x_q=unpacked, scale=scale, zero_point=zero_point, g_idx=g_idx
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
return decompressed_weight
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
def pack_to_int32(value: torch.Tensor, num_bits: int) -> torch.Tensor:
|
| 144 |
+
"""
|
| 145 |
+
Packs a tensor of quantized weights stored in int8 into int32s with padding
|
| 146 |
+
|
| 147 |
+
Pseudocode:
|
| 148 |
+
1. Shift wrt num_bits to convert to unsigned. num_bits=8
|
| 149 |
+
[1,2] -> [129, 130]
|
| 150 |
+
2. Pad to fill in 32 bits
|
| 151 |
+
[129, 130] -> [129, 130, 0, 0]
|
| 152 |
+
3. convert to binary align in order
|
| 153 |
+
[129, 130, 0, 0] -> 00000000 00000000 10000010 10000001
|
| 154 |
+
4. convert aligned binary to number
|
| 155 |
+
00000000000000001000001010000001 -> 33409
|
| 156 |
+
5. covert back to uint32
|
| 157 |
+
33409 -> 33409
|
| 158 |
+
|
| 159 |
+
:param value: tensor to pack
|
| 160 |
+
:param num_bits: number of bits used to store underlying data, must be at least 1
|
| 161 |
+
:returns: packed int32 tensor
|
| 162 |
+
"""
|
| 163 |
+
if value.dtype is not torch.int8:
|
| 164 |
+
raise ValueError("Tensor must be quantized to torch.int8 before packing")
|
| 165 |
+
|
| 166 |
+
if num_bits > 8:
|
| 167 |
+
raise ValueError("Packing is only supported for less than 8 bits")
|
| 168 |
+
|
| 169 |
+
if num_bits < 1:
|
| 170 |
+
raise ValueError(f"num_bits must be at least 1, got {num_bits}")
|
| 171 |
+
|
| 172 |
+
# convert to unsigned for packing
|
| 173 |
+
offset = 1 << (num_bits - 1)
|
| 174 |
+
value = (value + offset).to(torch.uint8)
|
| 175 |
+
value = value.cpu().numpy().astype(np.uint32)
|
| 176 |
+
pack_factor = 32 // num_bits
|
| 177 |
+
|
| 178 |
+
# pad input tensor and initialize packed output
|
| 179 |
+
packed_size = math.ceil(value.shape[1] / pack_factor)
|
| 180 |
+
padding = packed_size * pack_factor - value.shape[1]
|
| 181 |
+
value = np.pad(value, pad_width=[(0, 0), (0, padding)], constant_values=0)
|
| 182 |
+
|
| 183 |
+
# pack values
|
| 184 |
+
packed = np.zeros((value.shape[0], packed_size), dtype=np.uint32)
|
| 185 |
+
for i in range(pack_factor):
|
| 186 |
+
packed |= value[:, i::pack_factor] << num_bits * i
|
| 187 |
+
|
| 188 |
+
# convert back to signed and torch
|
| 189 |
+
packed = np.ascontiguousarray(packed).view(np.int32)
|
| 190 |
+
return torch.from_numpy(packed)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def unpack_from_int32(
|
| 194 |
+
value: torch.Tensor, num_bits: int, shape: torch.Size
|
| 195 |
+
) -> torch.Tensor:
|
| 196 |
+
"""
|
| 197 |
+
Unpacks a tensor of packed int32 weights into individual int8s, maintaining the
|
| 198 |
+
original bit range.
|
| 199 |
+
|
| 200 |
+
Return tensors in int8
|
| 201 |
+
|
| 202 |
+
:param value: tensor to upack
|
| 203 |
+
:param num_bits: number of bits to unpack each data point into
|
| 204 |
+
:param shape: shape to unpack into, used to remove padding
|
| 205 |
+
:returns: unpacked int8 tensor
|
| 206 |
+
"""
|
| 207 |
+
if value.dtype is not torch.int32:
|
| 208 |
+
raise ValueError(
|
| 209 |
+
f"Expected {torch.int32} but got {value.dtype}, Aborting unpack."
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
if num_bits > 8:
|
| 213 |
+
raise ValueError("Unpacking is only supported for less than 8 bits")
|
| 214 |
+
|
| 215 |
+
pack_factor = 32 // num_bits
|
| 216 |
+
|
| 217 |
+
# unpack
|
| 218 |
+
mask = (1 << num_bits) - 1
|
| 219 |
+
unpacked = torch.zeros(
|
| 220 |
+
(value.shape[0], value.shape[1] * pack_factor),
|
| 221 |
+
device=value.device,
|
| 222 |
+
dtype=torch.int32,
|
| 223 |
+
)
|
| 224 |
+
for i in range(pack_factor):
|
| 225 |
+
unpacked[:, i::pack_factor] = (value >> (num_bits * i)) & mask
|
| 226 |
+
|
| 227 |
+
# remove padding
|
| 228 |
+
original_row_size = int(shape[1])
|
| 229 |
+
unpacked = unpacked[:, :original_row_size]
|
| 230 |
+
|
| 231 |
+
# bits are packed in unsigned format, reformat to signed
|
| 232 |
+
# update the value range from unsigned to signed
|
| 233 |
+
offset = pow(2, num_bits) // 2
|
| 234 |
+
unpacked = (unpacked - offset).to(torch.int8)
|
| 235 |
+
|
| 236 |
+
return unpacked
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# flake8: noqa
|
| 15 |
+
|
| 16 |
+
from .base import *
|
| 17 |
+
from .dense import *
|
| 18 |
+
from .sparse_24_bitmask import *
|
| 19 |
+
from .sparse_bitmask import *
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (337 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (6.52 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/dense.cpython-312.pyc
ADDED
|
Binary file (1.83 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_24_bitmask.cpython-312.pyc
ADDED
|
Binary file (11.3 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/__pycache__/sparse_bitmask.cpython-312.pyc
ADDED
|
Binary file (7.63 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/base.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import logging
|
| 16 |
+
from typing import Dict, Generator, Optional, Set, Tuple
|
| 17 |
+
|
| 18 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 19 |
+
from compressed_tensors.utils import get_nested_weight_mappings, merge_names
|
| 20 |
+
from safetensors import safe_open
|
| 21 |
+
from torch import Tensor
|
| 22 |
+
from tqdm import tqdm
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
__all__ = ["BaseSparseCompressor"]
|
| 26 |
+
|
| 27 |
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class BaseSparseCompressor(BaseCompressor):
|
| 31 |
+
"""
|
| 32 |
+
Base class representing a sparse compression algorithm. Each child class should
|
| 33 |
+
implement compression_param_names, compress_weight and decompress_weight;
|
| 34 |
+
|
| 35 |
+
Compressors support compressing/decompressing a full module state dict or a single
|
| 36 |
+
quantized PyTorch leaf module.
|
| 37 |
+
|
| 38 |
+
Model Load Lifecycle (run_compressed=False):
|
| 39 |
+
- ModelCompressor.decompress()
|
| 40 |
+
- apply_quantization_config()
|
| 41 |
+
- BaseSparseCompressor.decompress()
|
| 42 |
+
- BaseSparseCompressor.decompress_weight()
|
| 43 |
+
|
| 44 |
+
Model Save Lifecycle:
|
| 45 |
+
- ModelCompressor.compress()
|
| 46 |
+
- BaseSparseCompressor.compress()
|
| 47 |
+
- BaseSparseCompressor.compress_weight()
|
| 48 |
+
|
| 49 |
+
Module Lifecycle (run_compressed=True):
|
| 50 |
+
- apply_quantization_config()
|
| 51 |
+
- compressed_module = CompressedLinear(module)
|
| 52 |
+
- initialize_module_for_quantization()
|
| 53 |
+
- BaseSparseCompressor.compression_param_info()
|
| 54 |
+
- register_parameters()
|
| 55 |
+
- compressed_module.forward()
|
| 56 |
+
- compressed_module.decompress()
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
:param config: config specifying compression parameters
|
| 60 |
+
"""
|
| 61 |
+
|
| 62 |
+
def compress(
|
| 63 |
+
self,
|
| 64 |
+
model_state: Dict[str, Tensor],
|
| 65 |
+
compression_targets: Optional[Set[str]] = None,
|
| 66 |
+
) -> Dict[str, Tensor]:
|
| 67 |
+
"""
|
| 68 |
+
Compresses a dense state dict using bitmask compression
|
| 69 |
+
|
| 70 |
+
:param model_state: state dict of uncompressed model
|
| 71 |
+
:param compression_targets: optional set of layer prefixes to compress,
|
| 72 |
+
otherwise compress all layers (for backwards compatibility)
|
| 73 |
+
:return: compressed state dict
|
| 74 |
+
"""
|
| 75 |
+
compressed_dict = {}
|
| 76 |
+
_LOGGER.debug(
|
| 77 |
+
f"Compressing model with {len(model_state)} parameterized layers..."
|
| 78 |
+
)
|
| 79 |
+
for name, value in tqdm(model_state.items(), desc="Compressing model"):
|
| 80 |
+
if not self.should_compress(name, compression_targets):
|
| 81 |
+
compressed_dict[name] = value
|
| 82 |
+
continue
|
| 83 |
+
prefix = name
|
| 84 |
+
if prefix.endswith(".weight"):
|
| 85 |
+
prefix = prefix[: -(len(".weight"))]
|
| 86 |
+
|
| 87 |
+
compression_data = self.compress_weight(prefix, value)
|
| 88 |
+
for key in compression_data.keys():
|
| 89 |
+
if key in compressed_dict:
|
| 90 |
+
_LOGGER.warn(
|
| 91 |
+
f"Expected all compressed state_dict keys to be unique, but "
|
| 92 |
+
f"found an existing entry for {key}. The existing entry will "
|
| 93 |
+
"be replaced."
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
compressed_dict.update(compression_data)
|
| 97 |
+
|
| 98 |
+
return compressed_dict
|
| 99 |
+
|
| 100 |
+
def decompress(
|
| 101 |
+
self, path_to_model_or_tensors: str, device: str = "cpu", **kwargs
|
| 102 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 103 |
+
"""
|
| 104 |
+
Reads a bitmask compressed state dict located
|
| 105 |
+
at path_to_model_or_tensors and returns a generator
|
| 106 |
+
for sequentially decompressing back to a dense state dict
|
| 107 |
+
|
| 108 |
+
:param model_path: path to compressed safetensors model (directory with
|
| 109 |
+
one or more safetensors files) or compressed tensors file
|
| 110 |
+
:param device: device to load decompressed weights onto
|
| 111 |
+
:return: iterator for generating decompressed weights
|
| 112 |
+
"""
|
| 113 |
+
weight_mappings, ignored_params = get_nested_weight_mappings(
|
| 114 |
+
path_to_model_or_tensors,
|
| 115 |
+
self.compression_param_names,
|
| 116 |
+
return_unmatched_params=True,
|
| 117 |
+
)
|
| 118 |
+
for weight_name in weight_mappings.keys():
|
| 119 |
+
weight_data = {}
|
| 120 |
+
for param_name, safe_path in weight_mappings[weight_name].items():
|
| 121 |
+
full_name = merge_names(weight_name, param_name)
|
| 122 |
+
with safe_open(safe_path, framework="pt", device=device) as f:
|
| 123 |
+
weight_data[param_name] = f.get_tensor(full_name)
|
| 124 |
+
decompressed = self.decompress_weight(weight_data)
|
| 125 |
+
yield merge_names(weight_name, "weight"), decompressed
|
| 126 |
+
|
| 127 |
+
for ignored_param_name, safe_path in ignored_params.items():
|
| 128 |
+
with safe_open(safe_path, framework="pt", device=device) as f:
|
| 129 |
+
value = f.get_tensor(ignored_param_name)
|
| 130 |
+
yield ignored_param_name, value
|
| 131 |
+
|
| 132 |
+
@staticmethod
|
| 133 |
+
def should_compress(name: str, expanded_targets: Optional[Set[str]] = None) -> bool:
|
| 134 |
+
"""
|
| 135 |
+
Check if a parameter should be compressed.
|
| 136 |
+
Currently, this only returns True for weight parameters.
|
| 137 |
+
|
| 138 |
+
:param name: name of the parameter
|
| 139 |
+
:param expanded_targets: set of layer prefixes to compress
|
| 140 |
+
:return: whether or not the parameter should be compressed
|
| 141 |
+
"""
|
| 142 |
+
if expanded_targets is None:
|
| 143 |
+
return name.endswith(".weight")
|
| 144 |
+
|
| 145 |
+
return (
|
| 146 |
+
name.endswith(".weight") and name[: -(len(".weight"))] in expanded_targets
|
| 147 |
+
)
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/dense.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Dict, Generator, Tuple
|
| 16 |
+
|
| 17 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 18 |
+
from compressed_tensors.config import CompressionFormat
|
| 19 |
+
from torch import Tensor
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@BaseCompressor.register(name=CompressionFormat.dense.value)
|
| 23 |
+
class DenseCompressor(BaseCompressor):
|
| 24 |
+
"""
|
| 25 |
+
Identity compressor for dense models, returns the original state_dict
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
@property
|
| 29 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 30 |
+
"""
|
| 31 |
+
Returns a tuple of compression parameter names introduced by
|
| 32 |
+
the compressor during compression
|
| 33 |
+
"""
|
| 34 |
+
return ()
|
| 35 |
+
|
| 36 |
+
def compress(self, model_state: Dict[str, Tensor], **kwargs) -> Dict[str, Tensor]:
|
| 37 |
+
return model_state
|
| 38 |
+
|
| 39 |
+
def decompress(
|
| 40 |
+
self, path_to_model_or_tensors: str, device: str = "cpu", **kwargs
|
| 41 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 42 |
+
return iter([])
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/sparse_24_bitmask.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from dataclasses import dataclass
|
| 16 |
+
from typing import Dict, List, Tuple, Union
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 20 |
+
from compressed_tensors.compressors.sparse_compressors.base import BaseSparseCompressor
|
| 21 |
+
from compressed_tensors.config import CompressionFormat, SparsityStructure
|
| 22 |
+
from compressed_tensors.quantization import FP8_DTYPE
|
| 23 |
+
from compressed_tensors.utils import merge_names, pack_bitmasks, unpack_bitmasks
|
| 24 |
+
from torch import Tensor
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
__all__ = [
|
| 28 |
+
"Sparse24BitMaskCompressor",
|
| 29 |
+
"Sparse24BitMaskTensor",
|
| 30 |
+
"sparse24_bitmask_compress",
|
| 31 |
+
"sparse24_bitmask_decompress",
|
| 32 |
+
"get_24_bytemasks",
|
| 33 |
+
]
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@BaseCompressor.register(name=CompressionFormat.sparse_24_bitmask.value)
|
| 37 |
+
class Sparse24BitMaskCompressor(BaseSparseCompressor):
|
| 38 |
+
"""
|
| 39 |
+
Compression for sparse models using bitmasks. Non-zero weights are stored in a 2d
|
| 40 |
+
values tensor, with their locations stored in a 2d bitmask
|
| 41 |
+
"""
|
| 42 |
+
|
| 43 |
+
@property
|
| 44 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 45 |
+
"""
|
| 46 |
+
Returns a tuple of compression parameter names introduced by
|
| 47 |
+
the compressor during compression
|
| 48 |
+
"""
|
| 49 |
+
return (
|
| 50 |
+
"shape",
|
| 51 |
+
"compressed",
|
| 52 |
+
"bitmask",
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
def compress_weight(self, name, value):
|
| 56 |
+
bitmask_tensor = Sparse24BitMaskTensor.from_dense(
|
| 57 |
+
value, self.config.sparsity_structure
|
| 58 |
+
)
|
| 59 |
+
bitmask_dict = bitmask_tensor.dict(name_prefix=name, device="cpu")
|
| 60 |
+
return bitmask_dict
|
| 61 |
+
|
| 62 |
+
def decompress_weight(self, weight_data):
|
| 63 |
+
data = Sparse24BitMaskTensor.from_compressed_data(**weight_data)
|
| 64 |
+
decompressed = data.decompress()
|
| 65 |
+
return decompressed
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@dataclass
|
| 69 |
+
class Sparse24BitMaskTensor:
|
| 70 |
+
"""
|
| 71 |
+
Owns compressions and decompression for a single 2:4 sparse
|
| 72 |
+
bitmask compressed tensor.
|
| 73 |
+
|
| 74 |
+
:param shape: shape of dense tensor
|
| 75 |
+
:param compressed: 2d tensor of non-zero values
|
| 76 |
+
:param bitmask: 2d bitmask of non-zero values
|
| 77 |
+
"""
|
| 78 |
+
|
| 79 |
+
shape: List[int]
|
| 80 |
+
compressed: Tensor
|
| 81 |
+
bitmask: Tensor
|
| 82 |
+
|
| 83 |
+
@staticmethod
|
| 84 |
+
def from_dense(
|
| 85 |
+
tensor: Tensor,
|
| 86 |
+
sparsity_structure: Union[SparsityStructure, str] = SparsityStructure.TWO_FOUR,
|
| 87 |
+
) -> "Sparse24BitMaskTensor":
|
| 88 |
+
"""
|
| 89 |
+
:param tensor: dense tensor to compress
|
| 90 |
+
:return: instantiated compressed tensor
|
| 91 |
+
"""
|
| 92 |
+
shape = list(tensor.shape)
|
| 93 |
+
compressed, bitmask = sparse24_bitmask_compress(
|
| 94 |
+
tensor.cpu(), sparsity_structure=sparsity_structure
|
| 95 |
+
)
|
| 96 |
+
return Sparse24BitMaskTensor(
|
| 97 |
+
shape=shape,
|
| 98 |
+
compressed=compressed,
|
| 99 |
+
bitmask=bitmask,
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
@staticmethod
|
| 103 |
+
def from_compressed_data(
|
| 104 |
+
shape: Union[List[int], Tensor], compressed: Tensor, bitmask: Tensor
|
| 105 |
+
) -> "Sparse24BitMaskTensor":
|
| 106 |
+
"""
|
| 107 |
+
:param shape: shape of the dense tensor (can be a list or a tensor)
|
| 108 |
+
:param compressed: 2d tensor of non-zero values
|
| 109 |
+
:param bitmask: 2d bitmask of non-zero values
|
| 110 |
+
:return: instantiated Sparse24BitMaskTensor
|
| 111 |
+
"""
|
| 112 |
+
if isinstance(shape, list):
|
| 113 |
+
shape = torch.tensor(shape)
|
| 114 |
+
if isinstance(shape, torch.Tensor):
|
| 115 |
+
shape = shape.flatten().tolist()
|
| 116 |
+
return Sparse24BitMaskTensor(
|
| 117 |
+
shape=shape, compressed=compressed, bitmask=bitmask
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
def decompress(self) -> Tensor:
|
| 121 |
+
"""
|
| 122 |
+
:return: reconstructed dense tensor
|
| 123 |
+
"""
|
| 124 |
+
return sparse24_bitmask_decompress(self.compressed, self.bitmask, self.shape)
|
| 125 |
+
|
| 126 |
+
def curr_memory_size_bytes(self) -> int:
|
| 127 |
+
"""
|
| 128 |
+
:return: size in bytes required to store compressed tensor on disk
|
| 129 |
+
"""
|
| 130 |
+
|
| 131 |
+
def sizeof_tensor(a: Tensor) -> int:
|
| 132 |
+
return a.element_size() * a.nelement()
|
| 133 |
+
|
| 134 |
+
return sizeof_tensor(self.compressed) + sizeof_tensor(self.bitmask)
|
| 135 |
+
|
| 136 |
+
def dict(self, name_prefix: str, device: str = "cpu") -> Dict[str, Tensor]:
|
| 137 |
+
"""
|
| 138 |
+
:param name_prefix: name of original tensor to store compressed weight as
|
| 139 |
+
:return: dict of compressed data for the stored weight
|
| 140 |
+
"""
|
| 141 |
+
if name_prefix.endswith(".weight"):
|
| 142 |
+
name_prefix = name_prefix[: -len(".weight")]
|
| 143 |
+
return {
|
| 144 |
+
merge_names(name_prefix, "shape"): torch.tensor(
|
| 145 |
+
self.shape, device=device
|
| 146 |
+
).reshape(-1, 1),
|
| 147 |
+
merge_names(name_prefix, "compressed"): self.compressed.to(device),
|
| 148 |
+
merge_names(name_prefix, "bitmask"): self.bitmask.to(device),
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
def __repr__(self) -> str:
|
| 152 |
+
return f"BitMaskTensor(shape={self.shape}, compressed=True)"
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def sparse24_bitmask_compress(
|
| 156 |
+
tensor: Tensor,
|
| 157 |
+
sparsity_structure: Union[SparsityStructure, str] = SparsityStructure.TWO_FOUR,
|
| 158 |
+
) -> Tuple[Tensor, Tensor, Tensor]:
|
| 159 |
+
"""
|
| 160 |
+
Compresses a dense tensor using bitmask compression
|
| 161 |
+
|
| 162 |
+
:param tensor: dense 2D tensor to compress
|
| 163 |
+
:param sparsity_structure: structure of sparsity in the tensor, defaults
|
| 164 |
+
to unstructured, can also be set to `2:4`
|
| 165 |
+
:return: tuple of compressed data representing tensor
|
| 166 |
+
"""
|
| 167 |
+
assert len(tensor.shape) == 2, "Only 2D tensors are supported"
|
| 168 |
+
assert (
|
| 169 |
+
SparsityStructure(sparsity_structure) == SparsityStructure.TWO_FOUR
|
| 170 |
+
), "Only 2:4 sparsity is supported"
|
| 171 |
+
|
| 172 |
+
bytemasks = get_24_bytemasks(tensor=tensor)
|
| 173 |
+
|
| 174 |
+
if tensor.dtype == FP8_DTYPE:
|
| 175 |
+
# acces raw bytes of the tensor
|
| 176 |
+
tensor_view = tensor.view(torch.int8)
|
| 177 |
+
values = tensor_view[bytemasks]
|
| 178 |
+
values = values.view(FP8_DTYPE)
|
| 179 |
+
else:
|
| 180 |
+
values = tensor[bytemasks]
|
| 181 |
+
|
| 182 |
+
num_rows, num_cols = tensor.shape
|
| 183 |
+
compressed_values = values.reshape(num_rows, num_cols // 2)
|
| 184 |
+
bitmasks_packed = pack_bitmasks(bytemasks)
|
| 185 |
+
return compressed_values, bitmasks_packed
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def sparse24_bitmask_decompress(
|
| 189 |
+
values: Tensor, bitmasks: Tensor, original_shape: torch.Size
|
| 190 |
+
) -> Tensor:
|
| 191 |
+
"""
|
| 192 |
+
Reconstructs a dense tensor from a compressed one
|
| 193 |
+
|
| 194 |
+
:param values: 1d tensor of non-zero values
|
| 195 |
+
:param bitmasks: 2d int8 tensor flagging locations of non-zero values in the
|
| 196 |
+
tensors original shape
|
| 197 |
+
:param original_shape: shape of the dense tensor
|
| 198 |
+
:return: decompressed dense tensor
|
| 199 |
+
"""
|
| 200 |
+
bytemasks_unpacked = unpack_bitmasks(bitmasks, original_shape)
|
| 201 |
+
|
| 202 |
+
decompressed_tensor = torch.zeros(original_shape, dtype=values.dtype)
|
| 203 |
+
decompressed_tensor = decompressed_tensor.to(values.device)
|
| 204 |
+
values = values.flatten()
|
| 205 |
+
if decompressed_tensor.dtype == FP8_DTYPE:
|
| 206 |
+
decompressed_tensor[bytemasks_unpacked] = values
|
| 207 |
+
decompressed_tensor = decompressed_tensor.cuda()
|
| 208 |
+
else:
|
| 209 |
+
decompressed_tensor[bytemasks_unpacked] = values
|
| 210 |
+
return decompressed_tensor
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def get_24_bytemasks(tensor):
|
| 214 |
+
"""
|
| 215 |
+
Generate a 2:4 sparsity mask for the given tensor.
|
| 216 |
+
|
| 217 |
+
This function creates a mask where exactly 2 out of every 4 elements are
|
| 218 |
+
preserved based on their magnitudes. The preserved elements are the ones
|
| 219 |
+
with the highest absolute values in each group of 4 elements.
|
| 220 |
+
|
| 221 |
+
:param tensor: The input tensor for which the 2:4 sparsity mask is to be created.
|
| 222 |
+
The tensor can be of any shape but its total number of elements
|
| 223 |
+
must be a multiple of 4.
|
| 224 |
+
:return: A boolean tensor of the same shape as the input tensor, where `True`
|
| 225 |
+
indicates the preserved elements and `False` indicates the pruned elements.
|
| 226 |
+
:raises ValueError: If the total number of elements in the tensor is not a
|
| 227 |
+
multiple of 4.
|
| 228 |
+
"""
|
| 229 |
+
original_dtype = tensor.dtype
|
| 230 |
+
if tensor.dtype == FP8_DTYPE:
|
| 231 |
+
tensor = tensor.view(torch.int8)
|
| 232 |
+
original_shape = tensor.shape
|
| 233 |
+
num_elements = tensor.numel()
|
| 234 |
+
|
| 235 |
+
if num_elements % 4 != 0:
|
| 236 |
+
raise ValueError("Tensor size must be a multiple of 4 for TWO_FOUR sparsity")
|
| 237 |
+
|
| 238 |
+
reshaped_tensor = tensor.view(-1, 4)
|
| 239 |
+
abs_tensor = reshaped_tensor.abs()
|
| 240 |
+
topk_indices = abs_tensor.topk(2, dim=1).indices
|
| 241 |
+
mask = torch.zeros_like(reshaped_tensor, dtype=torch.bool)
|
| 242 |
+
mask.scatter_(1, topk_indices, True)
|
| 243 |
+
mask = mask.view(original_shape)
|
| 244 |
+
tensor = tensor.view(original_dtype)
|
| 245 |
+
|
| 246 |
+
return mask
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_compressors/sparse_bitmask.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Dict, List, Tuple, Union
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 19 |
+
from compressed_tensors.compressors.sparse_compressors.base import BaseSparseCompressor
|
| 20 |
+
from compressed_tensors.config import CompressionFormat
|
| 21 |
+
from compressed_tensors.quantization import FP8_DTYPE
|
| 22 |
+
from compressed_tensors.utils import merge_names, pack_bitmasks, unpack_bitmasks
|
| 23 |
+
from torch import Tensor
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
__all__ = [
|
| 27 |
+
"BitmaskCompressor",
|
| 28 |
+
"BitmaskTensor",
|
| 29 |
+
"bitmask_compress",
|
| 30 |
+
"bitmask_decompress",
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
@BaseCompressor.register(name=CompressionFormat.sparse_bitmask.value)
|
| 35 |
+
class BitmaskCompressor(BaseSparseCompressor):
|
| 36 |
+
"""
|
| 37 |
+
Compression for sparse models using bitmasks. Non-zero weights are stored in a 1d
|
| 38 |
+
values tensor, with their locations stored in a 2d bitmask
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
@property
|
| 42 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 43 |
+
"""
|
| 44 |
+
Returns a tuple of compression parameter names introduced by
|
| 45 |
+
the compressor during compression
|
| 46 |
+
"""
|
| 47 |
+
return ("shape", "compressed", "bitmask", "row_offsets")
|
| 48 |
+
|
| 49 |
+
def compress_weight(self, name, value):
|
| 50 |
+
bitmask_tensor = BitmaskTensor.from_dense(value)
|
| 51 |
+
bitmask_dict = bitmask_tensor.dict(name_prefix=name, device="cpu")
|
| 52 |
+
return bitmask_dict
|
| 53 |
+
|
| 54 |
+
def decompress_weight(self, weight_data):
|
| 55 |
+
data = BitmaskTensor(**weight_data)
|
| 56 |
+
decompressed = data.decompress()
|
| 57 |
+
return decompressed
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class BitmaskTensor:
|
| 61 |
+
"""
|
| 62 |
+
Owns compressions and decompression for a single bitmask compressed tensor.
|
| 63 |
+
Adapted from: https://github.com/mgoin/torch_bitmask/tree/main
|
| 64 |
+
|
| 65 |
+
:param shape: shape of dense tensor
|
| 66 |
+
:compressed: flat tensor of non-zero values
|
| 67 |
+
:bitmask: 2d bitmask of non-zero values
|
| 68 |
+
:row_offsets: flat tensor indicating what index in values each dense row starts at
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
+
def __init__(
|
| 72 |
+
self,
|
| 73 |
+
shape: Union[torch.Size, List],
|
| 74 |
+
compressed: Tensor,
|
| 75 |
+
bitmask: Tensor,
|
| 76 |
+
row_offsets: Tensor,
|
| 77 |
+
):
|
| 78 |
+
self.shape = list(shape)
|
| 79 |
+
self.compressed = compressed
|
| 80 |
+
self.bitmask = bitmask
|
| 81 |
+
self.row_offsets = row_offsets
|
| 82 |
+
|
| 83 |
+
@staticmethod
|
| 84 |
+
def from_dense(tensor: Tensor) -> "BitmaskTensor":
|
| 85 |
+
"""
|
| 86 |
+
:param tensor: dense tensor to compress
|
| 87 |
+
:return: instantiated compressed tensor
|
| 88 |
+
"""
|
| 89 |
+
shape = tensor.shape
|
| 90 |
+
compressed, bitmask, row_offsets = bitmask_compress(tensor.cpu())
|
| 91 |
+
return BitmaskTensor(
|
| 92 |
+
shape=shape, compressed=compressed, bitmask=bitmask, row_offsets=row_offsets
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
def decompress(self) -> Tensor:
|
| 96 |
+
"""
|
| 97 |
+
:return: reconstructed dense tensor
|
| 98 |
+
"""
|
| 99 |
+
return bitmask_decompress(self.compressed, self.bitmask, self.shape)
|
| 100 |
+
|
| 101 |
+
def curr_memory_size_bytes(self):
|
| 102 |
+
"""
|
| 103 |
+
:return: size in bytes required to store compressed tensor on disk
|
| 104 |
+
"""
|
| 105 |
+
|
| 106 |
+
def sizeof_tensor(a):
|
| 107 |
+
return a.element_size() * a.nelement()
|
| 108 |
+
|
| 109 |
+
return (
|
| 110 |
+
sizeof_tensor(self.compressed)
|
| 111 |
+
+ sizeof_tensor(self.bitmask)
|
| 112 |
+
+ sizeof_tensor(self.row_offsets)
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
def dict(self, name_prefix: str, device: str = "cpu") -> Dict[str, Tensor]:
|
| 116 |
+
"""
|
| 117 |
+
:name_prefix: name of original tensor to store compressed weight as
|
| 118 |
+
:return: dict of compressed data for the stored weight
|
| 119 |
+
"""
|
| 120 |
+
return {
|
| 121 |
+
merge_names(name_prefix, "shape"): torch.tensor(self.shape, device=device),
|
| 122 |
+
merge_names(name_prefix, "compressed"): self.compressed.to(device),
|
| 123 |
+
merge_names(name_prefix, "bitmask"): self.bitmask.to(device),
|
| 124 |
+
merge_names(name_prefix, "row_offsets"): self.row_offsets.to(device),
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
def __repr__(self):
|
| 128 |
+
return f"BitmaskTensor(shape={self.shape}, compressed=True)"
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def bitmask_compress(tensor: Tensor) -> Tuple[Tensor, Tensor, Tensor]:
|
| 132 |
+
"""
|
| 133 |
+
Compresses a dense tensor using bitmask compression
|
| 134 |
+
|
| 135 |
+
:param tensor: dense tensor to compress
|
| 136 |
+
:return: tuple of compressed data representing tensor
|
| 137 |
+
"""
|
| 138 |
+
bytemasks = tensor != 0
|
| 139 |
+
row_counts = bytemasks.sum(dim=-1)
|
| 140 |
+
row_offsets = torch.cumsum(row_counts, 0) - row_counts
|
| 141 |
+
if tensor.dtype == FP8_DTYPE:
|
| 142 |
+
# acces raw bytes of the tensor
|
| 143 |
+
tensor_view = tensor.view(torch.int8)
|
| 144 |
+
values = tensor_view[bytemasks]
|
| 145 |
+
values = values.view(FP8_DTYPE)
|
| 146 |
+
else:
|
| 147 |
+
values = tensor[bytemasks]
|
| 148 |
+
bitmasks_packed = pack_bitmasks(bytemasks)
|
| 149 |
+
return values, bitmasks_packed, row_offsets
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def bitmask_decompress(
|
| 153 |
+
values: Tensor, bitmasks: Tensor, original_shape: torch.Size
|
| 154 |
+
) -> Tensor:
|
| 155 |
+
"""
|
| 156 |
+
Reconstructs a dense tensor from a compressed one
|
| 157 |
+
|
| 158 |
+
:param values: 1d tensor of non-zero values
|
| 159 |
+
:param bitmasks: 2d int8 tensor flagging locations of non-zero values in the
|
| 160 |
+
tensors original shape
|
| 161 |
+
:param original_shape: shape of the dense tensor
|
| 162 |
+
:return: decompressed dense tensor
|
| 163 |
+
"""
|
| 164 |
+
bytemasks_unpacked = unpack_bitmasks(bitmasks, original_shape)
|
| 165 |
+
|
| 166 |
+
decompressed_tensor = torch.zeros(original_shape, dtype=values.dtype)
|
| 167 |
+
decompressed_tensor[bytemasks_unpacked] = values
|
| 168 |
+
|
| 169 |
+
return decompressed_tensor
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
# flake8: noqa
|
| 15 |
+
|
| 16 |
+
from .marlin_24 import Marlin24Compressor
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (295 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/__pycache__/marlin_24.cpython-312.pyc
ADDED
|
Binary file (11 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/compressors/sparse_quantized_compressors/marlin_24.py
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import logging
|
| 16 |
+
from typing import Dict, Generator, Tuple
|
| 17 |
+
|
| 18 |
+
import numpy as np
|
| 19 |
+
import torch
|
| 20 |
+
from compressed_tensors.compressors.base import BaseCompressor
|
| 21 |
+
from compressed_tensors.config import CompressionFormat
|
| 22 |
+
from compressed_tensors.quantization import QuantizationArgs, QuantizationStrategy
|
| 23 |
+
from compressed_tensors.quantization.lifecycle.forward import quantize
|
| 24 |
+
from compressed_tensors.utils import (
|
| 25 |
+
get_permutations_24,
|
| 26 |
+
is_quantization_param,
|
| 27 |
+
merge_names,
|
| 28 |
+
sparse_semi_structured_from_dense_cutlass,
|
| 29 |
+
tensor_follows_mask_structure,
|
| 30 |
+
)
|
| 31 |
+
from torch import Tensor
|
| 32 |
+
from tqdm import tqdm
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@BaseCompressor.register(name=CompressionFormat.marlin_24.value)
|
| 39 |
+
class Marlin24Compressor(BaseCompressor):
|
| 40 |
+
"""
|
| 41 |
+
Compresses a quantized model with 2:4 sparsity structure for inference with the
|
| 42 |
+
Marlin24 kernel. Decompression is not implemented for this compressor.
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
@staticmethod
|
| 46 |
+
def validate_quant_compatability(
|
| 47 |
+
model_quant_args: Dict[str, QuantizationArgs]
|
| 48 |
+
) -> bool:
|
| 49 |
+
"""
|
| 50 |
+
Checks if every quantized module in the model is compatible with Marlin24
|
| 51 |
+
compression. Quantization must be channel or group strategy with group_size
|
| 52 |
+
of 128. Only symmetric quantization is supported
|
| 53 |
+
|
| 54 |
+
:param model_quant_args: dictionary of mapping module names to their
|
| 55 |
+
quantization configuration
|
| 56 |
+
:return: True if all modules are compatible with Marlin24 compression, raises
|
| 57 |
+
a ValueError otherwise
|
| 58 |
+
"""
|
| 59 |
+
for name, quant_args in model_quant_args.items():
|
| 60 |
+
strategy = quant_args.strategy
|
| 61 |
+
group_size = quant_args.group_size
|
| 62 |
+
symmetric = quant_args.symmetric
|
| 63 |
+
if (
|
| 64 |
+
strategy is not QuantizationStrategy.GROUP.value
|
| 65 |
+
and strategy is not QuantizationStrategy.CHANNEL.value
|
| 66 |
+
):
|
| 67 |
+
raise ValueError(
|
| 68 |
+
f"Marlin24 Compressor is only valid for group and channel "
|
| 69 |
+
f"quantization strategies, got {strategy} in {name}"
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
if group_size is not None and group_size != 128:
|
| 73 |
+
raise ValueError(
|
| 74 |
+
f"Marlin24 Compressor is only valid for group size 128, "
|
| 75 |
+
f"got {group_size} in {name}"
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
if not symmetric:
|
| 79 |
+
raise ValueError(
|
| 80 |
+
f"Marlin24 Compressor is only valid for symmetric quantzation, "
|
| 81 |
+
f"got symmetric={symmetric} in {name}"
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
return True
|
| 85 |
+
|
| 86 |
+
@staticmethod
|
| 87 |
+
def validate_sparsity_structure(name: str, weight: Tensor) -> bool:
|
| 88 |
+
"""
|
| 89 |
+
Checks if a tensor fits the required 2:4 sparsity structure
|
| 90 |
+
|
| 91 |
+
:param name: name of the tensor to check
|
| 92 |
+
:param weight: tensor to check for sparsity structure
|
| 93 |
+
:return: True if all rows match the 2:4 sparsity structure, raises
|
| 94 |
+
ValueError otherwise
|
| 95 |
+
"""
|
| 96 |
+
|
| 97 |
+
if not tensor_follows_mask_structure(weight):
|
| 98 |
+
raise ValueError(
|
| 99 |
+
"Marlin24 Compressor is only compatible with weights that have "
|
| 100 |
+
f"a 2:4 sparsity structure. Found segments in {name} "
|
| 101 |
+
"that do not match the expected structure."
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
return True
|
| 105 |
+
|
| 106 |
+
@property
|
| 107 |
+
def compression_param_names(self) -> Tuple[str]:
|
| 108 |
+
"""
|
| 109 |
+
Returns a tuple of compression parameter names introduced by
|
| 110 |
+
the compressor during compression
|
| 111 |
+
"""
|
| 112 |
+
return ("weight_packed", "scale_packed", "meta")
|
| 113 |
+
|
| 114 |
+
def compress(
|
| 115 |
+
self,
|
| 116 |
+
model_state: Dict[str, Tensor],
|
| 117 |
+
names_to_scheme: Dict[str, QuantizationArgs],
|
| 118 |
+
**kwargs,
|
| 119 |
+
) -> Dict[str, Tensor]:
|
| 120 |
+
"""
|
| 121 |
+
Compresses a quantized state_dict with 2:4 sparsity structure for inference
|
| 122 |
+
with the Marlin24 kernel
|
| 123 |
+
|
| 124 |
+
:param model_state: state dict of uncompressed model
|
| 125 |
+
:param names_to_scheme: quantization args for each quantized weight, needed for
|
| 126 |
+
quantize function to calculate bit depth
|
| 127 |
+
:return: compressed state dict
|
| 128 |
+
"""
|
| 129 |
+
self.validate_quant_compatability(names_to_scheme)
|
| 130 |
+
|
| 131 |
+
compressed_dict = {}
|
| 132 |
+
weight_suffix = ".weight"
|
| 133 |
+
_LOGGER.debug(
|
| 134 |
+
f"Compressing model with {len(model_state)} parameterized layers..."
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
for name, value in tqdm(model_state.items(), desc="Compressing model"):
|
| 138 |
+
if name.endswith(weight_suffix):
|
| 139 |
+
prefix = name[: -(len(weight_suffix))]
|
| 140 |
+
scale = model_state.get(merge_names(prefix, "weight_scale"), None)
|
| 141 |
+
zp = model_state.get(merge_names(prefix, "weight_zero_point"), None)
|
| 142 |
+
if scale is not None: # weight is quantized, compress it
|
| 143 |
+
|
| 144 |
+
# Marlin24 kernel requires float16 inputs
|
| 145 |
+
scale = scale.to(torch.float16)
|
| 146 |
+
value = value.to(torch.float16)
|
| 147 |
+
|
| 148 |
+
# quantize weight, keeping it as a float16 for now
|
| 149 |
+
quant_args = names_to_scheme[prefix]
|
| 150 |
+
value = quantize(
|
| 151 |
+
x=value, scale=scale, zero_point=zp, args=quant_args
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
# compress based on sparsity structure
|
| 155 |
+
self.validate_sparsity_structure(prefix, value)
|
| 156 |
+
value, meta = compress_weight_24(value)
|
| 157 |
+
meta = meta.cpu()
|
| 158 |
+
|
| 159 |
+
# Marlin24 kernel expects input dim first
|
| 160 |
+
value = value.t().contiguous().cpu()
|
| 161 |
+
scale = scale.t().contiguous().cpu()
|
| 162 |
+
og_weight_shape = value.shape
|
| 163 |
+
|
| 164 |
+
# Marlin24 kernel expects unsigned values, shift zero-point
|
| 165 |
+
value += (1 << quant_args.num_bits) // 2
|
| 166 |
+
|
| 167 |
+
# pack quantized weight and scale
|
| 168 |
+
value = pack_weight_24(value, quant_args)
|
| 169 |
+
packed_scale = pack_scales_24(scale, quant_args, og_weight_shape)
|
| 170 |
+
meta = meta.resize_(meta.shape[1] // 2, meta.shape[0] * 2)
|
| 171 |
+
|
| 172 |
+
# save compressed values
|
| 173 |
+
compressed_dict[merge_names(prefix, "scale_packed")] = packed_scale
|
| 174 |
+
compressed_dict[merge_names(prefix, "weight_packed")] = value
|
| 175 |
+
compressed_dict[merge_names(prefix, "meta")] = meta
|
| 176 |
+
continue
|
| 177 |
+
|
| 178 |
+
if not is_quantization_param(name):
|
| 179 |
+
# export unquantized parameters without modifying
|
| 180 |
+
compressed_dict[name] = value.to("cpu")
|
| 181 |
+
|
| 182 |
+
return compressed_dict
|
| 183 |
+
|
| 184 |
+
def decompress(
|
| 185 |
+
self, path_to_model_or_tensors: str, device: str = "cpu", **kwargs
|
| 186 |
+
) -> Generator[Tuple[str, Tensor], None, None]:
|
| 187 |
+
raise NotImplementedError(
|
| 188 |
+
"Decompression is not implemented for the Marlin24 Compressor."
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def compress_weight_24(weight: Tensor):
|
| 193 |
+
weight = weight.contiguous()
|
| 194 |
+
w_comp, meta = sparse_semi_structured_from_dense_cutlass(weight)
|
| 195 |
+
w_comp = w_comp.contiguous()
|
| 196 |
+
return w_comp, meta
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def marlin_permute_weights(q_w, size_k, size_n, perm, tile):
|
| 200 |
+
assert q_w.shape == (size_k, size_n)
|
| 201 |
+
assert size_k % tile == 0, f"size_k = {size_k}, tile = {tile}"
|
| 202 |
+
assert size_n % tile == 0, f"size_k = {size_n}, tile = {tile}"
|
| 203 |
+
|
| 204 |
+
# Permute weights to 16x64 marlin tiles
|
| 205 |
+
q_w = q_w.reshape((size_k // tile, tile, size_n // tile, tile))
|
| 206 |
+
q_w = q_w.permute((0, 2, 1, 3))
|
| 207 |
+
q_w = q_w.reshape((size_k // tile, size_n * tile))
|
| 208 |
+
|
| 209 |
+
q_w = q_w.reshape((-1, perm.numel()))[:, perm].reshape(q_w.shape)
|
| 210 |
+
|
| 211 |
+
return q_w
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def pack_weight_24(
|
| 215 |
+
weight: Tensor,
|
| 216 |
+
quantization_args: QuantizationArgs,
|
| 217 |
+
tile: int = 16,
|
| 218 |
+
):
|
| 219 |
+
size_k = weight.shape[0]
|
| 220 |
+
size_n = weight.shape[1]
|
| 221 |
+
num_bits = quantization_args.num_bits
|
| 222 |
+
pack_factor = 32 // num_bits
|
| 223 |
+
|
| 224 |
+
# Reshuffle to marlin_24 format
|
| 225 |
+
perm, _, _ = get_permutations_24(num_bits)
|
| 226 |
+
q_w = marlin_permute_weights(weight, size_k, size_n, perm, tile)
|
| 227 |
+
|
| 228 |
+
q_w = q_w.cpu().numpy().astype(np.uint32)
|
| 229 |
+
|
| 230 |
+
q_packed = np.zeros((q_w.shape[0], q_w.shape[1] // pack_factor), dtype=np.uint32)
|
| 231 |
+
for i in range(pack_factor):
|
| 232 |
+
q_packed |= q_w[:, i::pack_factor] << num_bits * i
|
| 233 |
+
|
| 234 |
+
q_packed = torch.from_numpy(q_packed.astype(np.int32))
|
| 235 |
+
|
| 236 |
+
return q_packed
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
def pack_scales_24(scales, quantization_args, w_shape):
|
| 240 |
+
size_k = w_shape[0]
|
| 241 |
+
size_n = w_shape[1]
|
| 242 |
+
num_bits = quantization_args.num_bits
|
| 243 |
+
|
| 244 |
+
_, scale_perm_2_4, scale_perm_single_2_4 = get_permutations_24(num_bits)
|
| 245 |
+
|
| 246 |
+
if (
|
| 247 |
+
quantization_args.strategy == QuantizationStrategy.GROUP
|
| 248 |
+
and quantization_args.group_size < size_k
|
| 249 |
+
):
|
| 250 |
+
scales = scales.reshape((-1, len(scale_perm_2_4)))[:, scale_perm_2_4]
|
| 251 |
+
else: # channelwise
|
| 252 |
+
scales = scales.reshape((-1, len(scale_perm_single_2_4)))[
|
| 253 |
+
:, scale_perm_single_2_4
|
| 254 |
+
]
|
| 255 |
+
scales = scales.reshape((-1, size_n)).contiguous()
|
| 256 |
+
|
| 257 |
+
return scales
|
lib/python3.12/site-packages/compressed_tensors/config/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# flake8: noqa
|
| 16 |
+
from .base import *
|
| 17 |
+
from .dense import *
|
| 18 |
+
from .sparse_24_bitmask import *
|
| 19 |
+
from .sparse_bitmask import *
|
lib/python3.12/site-packages/compressed_tensors/config/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (313 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/config/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (4 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/config/__pycache__/dense.cpython-312.pyc
ADDED
|
Binary file (1.29 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/config/__pycache__/sparse_24_bitmask.cpython-312.pyc
ADDED
|
Binary file (1.41 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/config/__pycache__/sparse_bitmask.cpython-312.pyc
ADDED
|
Binary file (1.28 kB). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/config/base.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from enum import Enum, unique
|
| 16 |
+
from typing import List, Optional
|
| 17 |
+
|
| 18 |
+
from compressed_tensors.registry import RegistryMixin
|
| 19 |
+
from pydantic import BaseModel
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
__all__ = ["SparsityCompressionConfig", "CompressionFormat", "SparsityStructure"]
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
@unique
|
| 26 |
+
class CompressionFormat(Enum):
|
| 27 |
+
dense = "dense"
|
| 28 |
+
sparse_bitmask = "sparse-bitmask"
|
| 29 |
+
sparse_24_bitmask = "sparse-24-bitmask"
|
| 30 |
+
int_quantized = "int-quantized"
|
| 31 |
+
float_quantized = "float-quantized"
|
| 32 |
+
naive_quantized = "naive-quantized"
|
| 33 |
+
pack_quantized = "pack-quantized"
|
| 34 |
+
marlin_24 = "marlin-24"
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
@unique
|
| 38 |
+
class SparsityStructure(Enum):
|
| 39 |
+
"""
|
| 40 |
+
An enumeration to represent different sparsity structures.
|
| 41 |
+
|
| 42 |
+
Attributes
|
| 43 |
+
----------
|
| 44 |
+
TWO_FOUR : str
|
| 45 |
+
Represents a 2:4 sparsity structure.
|
| 46 |
+
ZERO_ZERO : str
|
| 47 |
+
Represents a 0:0 sparsity structure.
|
| 48 |
+
UNSTRUCTURED : str
|
| 49 |
+
Represents an unstructured sparsity structure.
|
| 50 |
+
|
| 51 |
+
Examples
|
| 52 |
+
--------
|
| 53 |
+
>>> SparsityStructure('2:4')
|
| 54 |
+
<SparsityStructure.TWO_FOUR: '2:4'>
|
| 55 |
+
|
| 56 |
+
>>> SparsityStructure('unstructured')
|
| 57 |
+
<SparsityStructure.UNSTRUCTURED: 'unstructured'>
|
| 58 |
+
|
| 59 |
+
>>> SparsityStructure('2:4') == SparsityStructure.TWO_FOUR
|
| 60 |
+
True
|
| 61 |
+
|
| 62 |
+
>>> SparsityStructure('UNSTRUCTURED') == SparsityStructure.UNSTRUCTURED
|
| 63 |
+
True
|
| 64 |
+
|
| 65 |
+
>>> SparsityStructure(None) == SparsityStructure.UNSTRUCTURED
|
| 66 |
+
True
|
| 67 |
+
|
| 68 |
+
>>> SparsityStructure('invalid')
|
| 69 |
+
Traceback (most recent call last):
|
| 70 |
+
...
|
| 71 |
+
ValueError: invalid is not a valid SparsityStructure
|
| 72 |
+
"""
|
| 73 |
+
|
| 74 |
+
TWO_FOUR = "2:4"
|
| 75 |
+
UNSTRUCTURED = "unstructured"
|
| 76 |
+
ZERO_ZERO = "0:0"
|
| 77 |
+
|
| 78 |
+
def __new__(cls, value):
|
| 79 |
+
obj = object.__new__(cls)
|
| 80 |
+
obj._value_ = value.lower() if value is not None else value
|
| 81 |
+
return obj
|
| 82 |
+
|
| 83 |
+
@classmethod
|
| 84 |
+
def _missing_(cls, value):
|
| 85 |
+
# Handle None and case-insensitive values
|
| 86 |
+
if value is None:
|
| 87 |
+
return cls.UNSTRUCTURED
|
| 88 |
+
for member in cls:
|
| 89 |
+
if member.value == value.lower():
|
| 90 |
+
return member
|
| 91 |
+
raise ValueError(f"{value} is not a valid {cls.__name__}")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class SparsityCompressionConfig(RegistryMixin, BaseModel):
|
| 95 |
+
"""
|
| 96 |
+
Base data class for storing sparsity compression parameters
|
| 97 |
+
|
| 98 |
+
:param format: name of compression format
|
| 99 |
+
:param targets: List of layer names or layer types that aren't sparse and should
|
| 100 |
+
be ignored during compression. By default, assume all layers are targeted
|
| 101 |
+
:param ignore: List of layer names (unique) to ignore from targets. Defaults to None
|
| 102 |
+
:param global_sparsity: average sparsity of the entire model
|
| 103 |
+
:param sparsity_structure: structure of the sparsity, such as
|
| 104 |
+
"unstructured", "2:4", "8:16" etc
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
format: str
|
| 108 |
+
targets: Optional[List[str]] = None
|
| 109 |
+
ignore: Optional[List[str]] = None
|
| 110 |
+
global_sparsity: Optional[float] = 0.0
|
| 111 |
+
sparsity_structure: Optional[str] = "unstructured"
|
lib/python3.12/site-packages/compressed_tensors/config/dense.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Optional
|
| 16 |
+
|
| 17 |
+
from compressed_tensors.config import CompressionFormat, SparsityCompressionConfig
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
__all__ = ["DenseSparsityConfig"]
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@SparsityCompressionConfig.register(name=CompressionFormat.dense.value)
|
| 24 |
+
class DenseSparsityConfig(SparsityCompressionConfig):
|
| 25 |
+
"""
|
| 26 |
+
Identity configuration for storing a sparse model in
|
| 27 |
+
an uncompressed dense format
|
| 28 |
+
|
| 29 |
+
:param global_sparsity: average sparsity of the entire model
|
| 30 |
+
:param sparsity_structure: structure of the sparsity, such as
|
| 31 |
+
"unstructured", "2:4", "8:16" etc
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
format: str = CompressionFormat.dense.value
|
| 35 |
+
global_sparsity: Optional[float] = 0.0
|
| 36 |
+
sparsity_structure: Optional[str] = "unstructured"
|
lib/python3.12/site-packages/compressed_tensors/config/sparse_24_bitmask.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Optional
|
| 16 |
+
|
| 17 |
+
from compressed_tensors.config import (
|
| 18 |
+
CompressionFormat,
|
| 19 |
+
SparsityCompressionConfig,
|
| 20 |
+
SparsityStructure,
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
__all__ = ["Sparse24BitMaskConfig"]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@SparsityCompressionConfig.register(name=CompressionFormat.sparse_24_bitmask.value)
|
| 28 |
+
class Sparse24BitMaskConfig(SparsityCompressionConfig):
|
| 29 |
+
"""
|
| 30 |
+
Configuration for storing a 24 sparse model using
|
| 31 |
+
bytemask compression
|
| 32 |
+
|
| 33 |
+
:param global_sparsity: average sparsity of the entire model
|
| 34 |
+
:param sparsity_structure: structure of the sparsity, should always be
|
| 35 |
+
"2:4" for this compression format
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
format: str = CompressionFormat.sparse_24_bitmask.value
|
| 39 |
+
global_sparsity: Optional[float] = 0.0
|
| 40 |
+
sparsity_structure: Optional[str] = SparsityStructure.TWO_FOUR.value
|
lib/python3.12/site-packages/compressed_tensors/config/sparse_bitmask.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import Optional
|
| 16 |
+
|
| 17 |
+
from compressed_tensors.config import CompressionFormat, SparsityCompressionConfig
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
__all__ = ["BitmaskConfig"]
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
@SparsityCompressionConfig.register(name=CompressionFormat.sparse_bitmask.value)
|
| 24 |
+
class BitmaskConfig(SparsityCompressionConfig):
|
| 25 |
+
"""
|
| 26 |
+
Configuration for storing a sparse model using
|
| 27 |
+
bitmask compression
|
| 28 |
+
|
| 29 |
+
:param global_sparsity: average sparsity of the entire model
|
| 30 |
+
:param sparsity_structure: structure of the sparsity, such as
|
| 31 |
+
"unstructured", "2:4", "8:16" etc
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
format: str = CompressionFormat.sparse_bitmask.value
|
| 35 |
+
global_sparsity: Optional[float] = 0.0
|
| 36 |
+
sparsity_structure: Optional[str] = "unstructured"
|
lib/python3.12/site-packages/compressed_tensors/linear/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2021 - present / Neuralmagic, Inc. All Rights Reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing,
|
| 10 |
+
# software distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
lib/python3.12/site-packages/compressed_tensors/linear/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (204 Bytes). View file
|
|
|
lib/python3.12/site-packages/compressed_tensors/linear/__pycache__/compressed_linear.cpython-312.pyc
ADDED
|
Binary file (4.2 kB). View file
|
|
|