cache-dit 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cache-dit might be problematic. Click here for more details.
- cache_dit/__init__.py +3 -0
- cache_dit/_version.py +2 -2
- cache_dit/cache_factory/__init__.py +7 -0
- cache_dit/cache_factory/block_adapters/block_adapters.py +16 -6
- cache_dit/cache_factory/cache_adapters/__init__.py +2 -0
- cache_dit/cache_factory/{cache_adapters.py → cache_adapters/cache_adapter.py} +6 -6
- cache_dit/cache_factory/cache_adapters/v2/__init__.py +3 -0
- cache_dit/cache_factory/cache_adapters/v2/cache_adapter_v2.py +524 -0
- cache_dit/cache_factory/cache_contexts/__init__.py +7 -0
- cache_dit/cache_factory/cache_contexts/v2/__init__.py +13 -0
- cache_dit/cache_factory/cache_contexts/v2/cache_context_v2.py +288 -0
- cache_dit/cache_factory/cache_contexts/v2/cache_manager_v2.py +799 -0
- cache_dit/cache_factory/cache_contexts/v2/calibrators/__init__.py +81 -0
- cache_dit/cache_factory/cache_contexts/v2/calibrators/base.py +27 -0
- cache_dit/cache_factory/cache_contexts/v2/calibrators/foca.py +26 -0
- cache_dit/cache_factory/cache_contexts/v2/calibrators/taylorseer.py +105 -0
- cache_dit/cache_factory/cache_interface.py +39 -12
- cache_dit/utils.py +17 -7
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/METADATA +38 -29
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/RECORD +24 -14
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/WHEEL +0 -0
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/entry_points.txt +0 -0
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {cache_dit-0.3.0.dist-info → cache_dit-0.3.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from cache_dit.cache_factory.cache_contexts.v2.calibrators.base import (
|
|
2
|
+
CalibratorBase,
|
|
3
|
+
)
|
|
4
|
+
from cache_dit.cache_factory.cache_contexts.v2.calibrators.taylorseer import (
|
|
5
|
+
TaylorSeerCalibrator,
|
|
6
|
+
)
|
|
7
|
+
from cache_dit.cache_factory.cache_contexts.v2.calibrators.foca import (
|
|
8
|
+
FoCaCalibrator,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
import dataclasses
|
|
12
|
+
from typing import Any, Dict
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from cache_dit.logger import init_logger
|
|
16
|
+
|
|
17
|
+
logger = init_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclasses.dataclass
|
|
21
|
+
class CalibratorConfig: # no V1
|
|
22
|
+
enable_calibrator: bool = False
|
|
23
|
+
enable_encoder_calibrator: bool = False
|
|
24
|
+
calibrator_type: str = "taylorseer" # taylorseer or foca, etc.
|
|
25
|
+
calibrator_cache_type: str = "residual" # residual or hidden_states
|
|
26
|
+
calibrator_kwargs: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
|
27
|
+
|
|
28
|
+
def strify(self) -> str:
|
|
29
|
+
return "CalibratorBase"
|
|
30
|
+
|
|
31
|
+
def to_kwargs(self) -> Dict:
|
|
32
|
+
return self.calibrator_kwargs.copy()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclasses.dataclass
|
|
36
|
+
class TaylorSeerCalibratorConfig(CalibratorConfig):
|
|
37
|
+
enable_calibrator: bool = True
|
|
38
|
+
enable_encoder_calibrator: bool = True
|
|
39
|
+
calibrator_type: str = "taylorseer"
|
|
40
|
+
taylorseer_order: int = 1
|
|
41
|
+
|
|
42
|
+
def strify(self) -> str:
|
|
43
|
+
if self.taylorseer_order:
|
|
44
|
+
return f"TaylorSeer_O({self.taylorseer_order})"
|
|
45
|
+
return "TaylorSeer_O(0)"
|
|
46
|
+
|
|
47
|
+
def to_kwargs(self) -> Dict:
|
|
48
|
+
kwargs = self.calibrator_kwargs.copy()
|
|
49
|
+
kwargs["n_derivatives"] = self.taylorseer_order
|
|
50
|
+
return kwargs
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclasses.dataclass
|
|
54
|
+
class FoCaCalibratorConfig(CalibratorConfig):
|
|
55
|
+
enable_calibrator: bool = True
|
|
56
|
+
enable_encoder_calibrator: bool = True
|
|
57
|
+
calibrator_type: str = "foca"
|
|
58
|
+
|
|
59
|
+
def strify(self) -> str:
|
|
60
|
+
return "FoCa"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class Calibrator:
|
|
64
|
+
_supported_calibrators = [
|
|
65
|
+
"taylorseer",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
def __new__(
|
|
69
|
+
cls,
|
|
70
|
+
calibrator_config: CalibratorConfig,
|
|
71
|
+
) -> CalibratorBase:
|
|
72
|
+
assert (
|
|
73
|
+
calibrator_config.calibrator_type in cls._supported_calibrators
|
|
74
|
+
), f"Calibrator {calibrator_config.calibrator_type} is not supported now!"
|
|
75
|
+
|
|
76
|
+
if calibrator_config.calibrator_type.lower() == "taylorseer":
|
|
77
|
+
return TaylorSeerCalibrator(**calibrator_config.to_kwargs())
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
f"Calibrator {calibrator_config.calibrator_type} is not supported now!"
|
|
81
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from cache_dit.logger import init_logger
|
|
4
|
+
|
|
5
|
+
logger = init_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CalibratorBase:
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def reset_cache(self, *args, **kwargs):
|
|
12
|
+
raise NotImplementedError("reset_cache method is not implemented.")
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def approximate(self, *args, **kwargs):
|
|
16
|
+
raise NotImplementedError("approximate method is not implemented.")
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def mark_step_begin(self, *args, **kwargs):
|
|
20
|
+
raise NotImplementedError("mark_step_begin method is not implemented.")
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def update(self, *args, **kwargs):
|
|
24
|
+
raise NotImplementedError("update method is not implemented.")
|
|
25
|
+
|
|
26
|
+
def __repr__(self):
|
|
27
|
+
return "CalibratorBase"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from cache_dit.cache_factory.cache_contexts.v2.calibrators.base import (
|
|
2
|
+
CalibratorBase,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FoCaCalibrator(CalibratorBase):
|
|
7
|
+
# TODO: Support FoCa, Forecast then Calibrate: Feature Caching as ODE for
|
|
8
|
+
# Efficient Diffusion Transformers, https://arxiv.org/pdf/2508.16211
|
|
9
|
+
|
|
10
|
+
def __init__(self, *args, **kwargs):
|
|
11
|
+
super().__init__()
|
|
12
|
+
|
|
13
|
+
def reset_cache(self, *args, **kwargs):
|
|
14
|
+
raise NotImplementedError("reset_cache method is not implemented.")
|
|
15
|
+
|
|
16
|
+
def approximate(self, *args, **kwargs):
|
|
17
|
+
raise NotImplementedError("approximate method is not implemented.")
|
|
18
|
+
|
|
19
|
+
def mark_step_begin(self, *args, **kwargs):
|
|
20
|
+
raise NotImplementedError("mark_step_begin method is not implemented.")
|
|
21
|
+
|
|
22
|
+
def update(self, *args, **kwargs):
|
|
23
|
+
raise NotImplementedError("update method is not implemented.")
|
|
24
|
+
|
|
25
|
+
def __repr__(self):
|
|
26
|
+
return "FoCaCalibrator"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import torch
|
|
3
|
+
from typing import List, Dict
|
|
4
|
+
from cache_dit.cache_factory.cache_contexts.v2.calibrators.base import (
|
|
5
|
+
CalibratorBase,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from cache_dit.logger import init_logger
|
|
9
|
+
|
|
10
|
+
logger = init_logger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TaylorSeerCalibrator(CalibratorBase):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
n_derivatives=1,
|
|
17
|
+
max_warmup_steps=1,
|
|
18
|
+
skip_interval_steps=1,
|
|
19
|
+
**kwargs,
|
|
20
|
+
):
|
|
21
|
+
self.n_derivatives = n_derivatives
|
|
22
|
+
self.order = n_derivatives + 1
|
|
23
|
+
self.max_warmup_steps = max_warmup_steps
|
|
24
|
+
self.skip_interval_steps = skip_interval_steps
|
|
25
|
+
self.reset_cache()
|
|
26
|
+
logger.info(f"Created {self.__repr__()}_{id(self)}")
|
|
27
|
+
|
|
28
|
+
def reset_cache(self): # NEED
|
|
29
|
+
self.state: Dict[str, List[torch.Tensor]] = {
|
|
30
|
+
"dY_prev": [None] * self.order,
|
|
31
|
+
"dY_current": [None] * self.order,
|
|
32
|
+
}
|
|
33
|
+
self.current_step = -1
|
|
34
|
+
self.last_non_approximated_step = -1
|
|
35
|
+
|
|
36
|
+
def should_compute(self, step=None):
|
|
37
|
+
step = self.current_step if step is None else step
|
|
38
|
+
if (
|
|
39
|
+
step < self.max_warmup_steps
|
|
40
|
+
or (step - self.max_warmup_steps + 1) % self.skip_interval_steps
|
|
41
|
+
== 0
|
|
42
|
+
):
|
|
43
|
+
return True
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
def derivative(self, Y: torch.Tensor) -> List[torch.Tensor]:
|
|
47
|
+
# Y(t) = Y(0) + dY(0)/dt * t + d^2Y(0)/dt^2 * t^2 / 2!
|
|
48
|
+
# + ... + d^nY(0)/dt^n * t^n / n!
|
|
49
|
+
dY_current: List[torch.Tensor] = [None] * self.order
|
|
50
|
+
dY_current[0] = Y
|
|
51
|
+
window = self.current_step - self.last_non_approximated_step
|
|
52
|
+
if self.state["dY_prev"][0] is not None:
|
|
53
|
+
if dY_current[0].shape != self.state["dY_prev"][0].shape:
|
|
54
|
+
self.reset_cache()
|
|
55
|
+
|
|
56
|
+
for i in range(self.n_derivatives):
|
|
57
|
+
if self.state["dY_prev"][i] is not None and self.current_step > 1:
|
|
58
|
+
dY_current[i + 1] = (
|
|
59
|
+
dY_current[i] - self.state["dY_prev"][i]
|
|
60
|
+
) / window
|
|
61
|
+
else:
|
|
62
|
+
break
|
|
63
|
+
return dY_current
|
|
64
|
+
|
|
65
|
+
def approximate(self) -> torch.Tensor: # NEED
|
|
66
|
+
elapsed = self.current_step - self.last_non_approximated_step
|
|
67
|
+
output = 0
|
|
68
|
+
for i, derivative in enumerate(self.state["dY_current"]):
|
|
69
|
+
if derivative is not None:
|
|
70
|
+
output += (1 / math.factorial(i)) * derivative * (elapsed**i)
|
|
71
|
+
else:
|
|
72
|
+
break
|
|
73
|
+
return output
|
|
74
|
+
|
|
75
|
+
def mark_step_begin(self): # NEED
|
|
76
|
+
self.current_step += 1
|
|
77
|
+
|
|
78
|
+
def update(self, Y: torch.Tensor): # NEED
|
|
79
|
+
# Directly call this method will ingnore the warmup
|
|
80
|
+
# policy and force full computation.
|
|
81
|
+
# Assume warmup steps is 3, and n_derivatives is 3.
|
|
82
|
+
# step 0: dY_prev = [None, None, None, None ]
|
|
83
|
+
# dY_current = [Y0, None, None, None ]
|
|
84
|
+
# step 1: dY_prev = [Y0, None, None, None ]
|
|
85
|
+
# dY_current = [Y1, dY1, None, None ]
|
|
86
|
+
# step 2: dY_prev = [Y1, dY1, None, None ]
|
|
87
|
+
# dY_current = [Y2, dY2/Y1, dY2/dY1, None ]
|
|
88
|
+
# step 3: dY_prev = [Y2, dY2/Y1, dY2/dY1, None ],
|
|
89
|
+
# dY_current = [Y3, dY3/Y2, dY3/dY2, dY3/dY1]
|
|
90
|
+
# step 4: dY_prev = [Y3, dY3/Y2, dY3/dY2, dY3/dY1]
|
|
91
|
+
# dY_current = [Y4, dY4/Y3, dY4/dY3, dY4/dY2]
|
|
92
|
+
self.state["dY_prev"] = self.state["dY_current"]
|
|
93
|
+
self.state["dY_current"] = self.derivative(Y)
|
|
94
|
+
self.last_non_approximated_step = self.current_step
|
|
95
|
+
|
|
96
|
+
def step(self, Y: torch.Tensor):
|
|
97
|
+
self.mark_step_begin()
|
|
98
|
+
if self.should_compute():
|
|
99
|
+
self.update(Y)
|
|
100
|
+
return Y
|
|
101
|
+
else:
|
|
102
|
+
return self.approximate()
|
|
103
|
+
|
|
104
|
+
def __repr__(self):
|
|
105
|
+
return f"TaylorSeerCalibrator_O({self.n_derivatives})"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from typing import Any, Tuple, List, Union
|
|
1
|
+
from typing import Any, Tuple, List, Union, Optional
|
|
2
2
|
from diffusers import DiffusionPipeline
|
|
3
3
|
from cache_dit.cache_factory.cache_types import CacheType
|
|
4
4
|
from cache_dit.cache_factory.block_adapters import BlockAdapter
|
|
5
5
|
from cache_dit.cache_factory.block_adapters import BlockAdapterRegistry
|
|
6
6
|
from cache_dit.cache_factory.cache_adapters import CachedAdapter
|
|
7
|
+
from cache_dit.cache_factory.cache_adapters import CachedAdapterV2
|
|
8
|
+
from cache_dit.cache_factory.cache_contexts import CalibratorConfig
|
|
7
9
|
|
|
8
10
|
from cache_dit.logger import init_logger
|
|
9
11
|
|
|
@@ -32,6 +34,8 @@ def enable_cache(
|
|
|
32
34
|
enable_encoder_taylorseer: bool = False,
|
|
33
35
|
taylorseer_cache_type: str = "residual",
|
|
34
36
|
taylorseer_order: int = 1,
|
|
37
|
+
# New param only for v2 API
|
|
38
|
+
calibrator_config: Optional[CalibratorConfig] = None,
|
|
35
39
|
**other_cache_context_kwargs,
|
|
36
40
|
) -> Union[
|
|
37
41
|
DiffusionPipeline,
|
|
@@ -94,6 +98,9 @@ def enable_cache(
|
|
|
94
98
|
taylorseer_order (`int`, *required*, defaults to 1):
|
|
95
99
|
The order of taylorseer, higher values of n_derivatives will lead to longer computation time,
|
|
96
100
|
the recommended value is 1 or 2.
|
|
101
|
+
calibrator_config (`CalibratorConfig`, *optional*, defaults to None):
|
|
102
|
+
# config for calibrator, if calibrator_config is not None, means that user want to use CachedAdapterV2
|
|
103
|
+
# with specific calibrator, such as taylorseer, foca, and so on.
|
|
97
104
|
other_cache_context_kwargs: (`dict`, *optional*, defaults to {})
|
|
98
105
|
Other cache context kwargs, please check https://github.com/vipshop/cache-dit/blob/main/src/cache_dit/cache_factory/cache_contexts/cache_context.py
|
|
99
106
|
for more details.
|
|
@@ -128,18 +135,32 @@ def enable_cache(
|
|
|
128
135
|
cache_context_kwargs["cfg_diff_compute_separate"] = (
|
|
129
136
|
cfg_diff_compute_separate
|
|
130
137
|
)
|
|
131
|
-
cache_context_kwargs["enable_taylorseer"] = enable_taylorseer
|
|
132
|
-
cache_context_kwargs["enable_encoder_taylorseer"] = (
|
|
133
|
-
enable_encoder_taylorseer
|
|
134
|
-
)
|
|
135
|
-
cache_context_kwargs["taylorseer_cache_type"] = taylorseer_cache_type
|
|
136
|
-
cache_context_kwargs["taylorseer_order"] = taylorseer_order
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
# V1 only supports the Taylorseer calibrator. We have decided to
|
|
140
|
+
# keep this code for API compatibility reasons.
|
|
141
|
+
if calibrator_config is None:
|
|
142
|
+
cache_context_kwargs["enable_taylorseer"] = enable_taylorseer
|
|
143
|
+
cache_context_kwargs["enable_encoder_taylorseer"] = (
|
|
144
|
+
enable_encoder_taylorseer
|
|
142
145
|
)
|
|
146
|
+
cache_context_kwargs["taylorseer_cache_type"] = taylorseer_cache_type
|
|
147
|
+
cache_context_kwargs["taylorseer_order"] = taylorseer_order
|
|
148
|
+
else:
|
|
149
|
+
cache_context_kwargs["calibrator_config"] = calibrator_config
|
|
150
|
+
|
|
151
|
+
if isinstance(pipe_or_adapter, (DiffusionPipeline, BlockAdapter)):
|
|
152
|
+
if calibrator_config is None:
|
|
153
|
+
return CachedAdapter.apply(
|
|
154
|
+
pipe_or_adapter,
|
|
155
|
+
**cache_context_kwargs,
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
logger.warning("You are using the un-stable V2 API!")
|
|
159
|
+
pipe_or_adapter._is_v2_api = True
|
|
160
|
+
return CachedAdapterV2.apply(
|
|
161
|
+
pipe_or_adapter,
|
|
162
|
+
**cache_context_kwargs,
|
|
163
|
+
)
|
|
143
164
|
else:
|
|
144
165
|
raise ValueError(
|
|
145
166
|
f"type: {type(pipe_or_adapter)} is not valid, "
|
|
@@ -154,7 +175,13 @@ def disable_cache(
|
|
|
154
175
|
BlockAdapter,
|
|
155
176
|
],
|
|
156
177
|
):
|
|
157
|
-
|
|
178
|
+
if getattr(pipe_or_adapter, "_is_v2_api", False):
|
|
179
|
+
logger.warning("You are using the un-stable V2 API!")
|
|
180
|
+
CachedAdapterV2.maybe_release_hooks(pipe_or_adapter)
|
|
181
|
+
del pipe_or_adapter._is_v2_api
|
|
182
|
+
else:
|
|
183
|
+
CachedAdapter.maybe_release_hooks(pipe_or_adapter)
|
|
184
|
+
|
|
158
185
|
logger.warning(
|
|
159
186
|
f"Cache Acceleration is disabled for: "
|
|
160
187
|
f"{pipe_or_adapter.__class__.__name__}."
|
cache_dit/utils.py
CHANGED
|
@@ -10,6 +10,7 @@ from diffusers import DiffusionPipeline
|
|
|
10
10
|
|
|
11
11
|
from typing import Dict, Any, List, Union
|
|
12
12
|
from cache_dit.cache_factory import BlockAdapter
|
|
13
|
+
from cache_dit.cache_factory import CalibratorConfig
|
|
13
14
|
from cache_dit.logger import init_logger
|
|
14
15
|
|
|
15
16
|
|
|
@@ -179,11 +180,21 @@ def strify(
|
|
|
179
180
|
if not cache_options:
|
|
180
181
|
return "NONE"
|
|
181
182
|
|
|
182
|
-
def
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
taylorseer_order
|
|
186
|
-
|
|
183
|
+
def calibrator_str():
|
|
184
|
+
if not getattr(adapter_or_others, "_is_v2_api", False):
|
|
185
|
+
taylorseer_order = 0
|
|
186
|
+
if "taylorseer_order" in cache_options:
|
|
187
|
+
taylorseer_order = cache_options["taylorseer_order"]
|
|
188
|
+
return (
|
|
189
|
+
f"T{int(cache_options.get('enable_taylorseer', False))}"
|
|
190
|
+
f"O{taylorseer_order}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
calibrator_config: CalibratorConfig = cache_options.get(
|
|
194
|
+
"calibrator_config", None
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
return calibrator_config.strify() if calibrator_config else "NONE"
|
|
187
198
|
|
|
188
199
|
cache_type_str = (
|
|
189
200
|
f"DBCACHE_F{cache_options.get('Fn_compute_blocks', 1)}"
|
|
@@ -191,8 +202,7 @@ def strify(
|
|
|
191
202
|
f"W{cache_options.get('max_warmup_steps', 0)}"
|
|
192
203
|
f"M{max(0, cache_options.get('max_cached_steps', -1))}"
|
|
193
204
|
f"MC{max(0, cache_options.get('max_continuous_cached_steps', -1))}_"
|
|
194
|
-
f"
|
|
195
|
-
f"O{get_taylorseer_order()}_"
|
|
205
|
+
f"{calibrator_str()}_"
|
|
196
206
|
f"R{cache_options.get('residual_diff_threshold', 0.08)}"
|
|
197
207
|
)
|
|
198
208
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cache_dit
|
|
3
|
-
Version: 0.3.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: A Unified, Flexible and Training-free Cache Acceleration Framework for 🤗Diffusers.
|
|
5
5
|
Author: DefTruth, vipshop.com, etc.
|
|
6
6
|
Maintainer: DefTruth, vipshop.com, etc
|
|
7
7
|
Project-URL: Repository, https://github.com/vipshop/cache-dit.git
|
|
@@ -49,8 +49,8 @@ Dynamic: requires-python
|
|
|
49
49
|
<img src=https://github.com/vipshop/cache-dit/raw/main/assets/cache-dit-logo.png height="120">
|
|
50
50
|
|
|
51
51
|
<p align="center">
|
|
52
|
-
A <b>Unified</b
|
|
53
|
-
♥️
|
|
52
|
+
A <b>Unified</b>, Flexible and Training-free <b>Cache Acceleration</b> Framework for <b>🤗Diffusers</b> <br>
|
|
53
|
+
♥️ Cache Acceleration with <b>One-line</b> Code ~ ♥️
|
|
54
54
|
</p>
|
|
55
55
|
<div align='center'>
|
|
56
56
|
<img src=https://img.shields.io/badge/Language-Python-brightgreen.svg >
|
|
@@ -62,11 +62,11 @@ Dynamic: requires-python
|
|
|
62
62
|
</div>
|
|
63
63
|
<p align="center">
|
|
64
64
|
<b><a href="#unified">📚Unified Cache APIs</a></b> | <a href="#forward-pattern-matching">📚Forward Pattern Matching</a> | <a href="#automatic-block-adapter">📚Automatic Block Adapter</a><br>
|
|
65
|
-
<a href="#hybird-forward-pattern">📚Hybrid Forward Pattern</a> | <a href="#dbcache">📚DBCache</a> | <a href="#taylorseer">📚
|
|
65
|
+
<a href="#hybird-forward-pattern">📚Hybrid Forward Pattern</a> | <a href="#dbcache">📚DBCache</a> | <a href="#taylorseer">📚TaylorSeer Calibrator</a> | <a href="#cfg">📚Cache CFG</a><br>
|
|
66
66
|
<a href="#benchmarks">📚Text2Image DrawBench</a> | <a href="#benchmarks">📚Text2Image Distillation DrawBench</a>
|
|
67
67
|
</p>
|
|
68
68
|
<p align="center">
|
|
69
|
-
🎉Now, <b>cache-dit</b> covers <b>
|
|
69
|
+
🎉Now, <b>cache-dit</b> covers almost <b>All</b> Diffusers' <b>DiT</b> Pipelines🎉<br>
|
|
70
70
|
🔥<a href="#supported">Qwen-Image</a> | <a href="#supported">FLUX.1</a> | <a href="#supported">Qwen-Image-Lightning</a> | <a href="#supported"> Wan 2.1 </a> | <a href="#supported"> Wan 2.2 </a>🔥<br>
|
|
71
71
|
🔥<a href="#supported">HunyuanImage-2.1</a> | <a href="#supported">HunyuanVideo</a> | <a href="#supported">HunyuanDiT</a> | <a href="#supported">HiDream</a> | <a href="#supported">AuraFlow</a>🔥<br>
|
|
72
72
|
🔥<a href="#supported">CogView3Plus</a> | <a href="#supported">CogView4</a> | <a href="#supported">LTXVideo</a> | <a href="#supported">CogVideoX</a> | <a href="#supported">CogVideoX 1.5</a> | <a href="#supported">ConsisID</a>🔥<br>
|
|
@@ -197,7 +197,7 @@ Dynamic: requires-python
|
|
|
197
197
|
- [📚Implement Patch Functor](#implement-patch-functor)
|
|
198
198
|
- [🤖Cache Acceleration Stats](#cache-acceleration-stats-summary)
|
|
199
199
|
- [⚡️Dual Block Cache](#dbcache)
|
|
200
|
-
- [🔥
|
|
200
|
+
- [🔥TaylorSeer Calibrator](#taylorseer)
|
|
201
201
|
- [⚡️Hybrid Cache CFG](#cfg)
|
|
202
202
|
- [⚙️Torch Compile](#compile)
|
|
203
203
|
- [🛠Metrics CLI](#metrics)
|
|
@@ -302,12 +302,14 @@ The comparison between **cache-dit: DBCache** and algorithms such as Δ-DiT, Chi
|
|
|
302
302
|
| Δ-DiT(N=3) | 1686.76 | 2.21× | 0.8721 | 32.102 |
|
|
303
303
|
| [**FLUX.1**-dev]: 34% steps | 1264.63 | 3.13× | 0.9453 | 32.114 |
|
|
304
304
|
| Chipmunk | 1505.87 | 2.47× | 0.9936 | 32.776 |
|
|
305
|
-
| FORA
|
|
306
|
-
| **[DBCache(F=4,B=0,W=4,MC=4)](https://github.com/vipshop/cache-dit)** |
|
|
305
|
+
| FORA(N=3) | 1320.07 | 2.82× | 0.9776 | 32.266 |
|
|
306
|
+
| **[DBCache(F=4,B=0,W=4,MC=4)](https://github.com/vipshop/cache-dit)** | 1400.08 | **2.66×** | **1.0065** | 32.838 |
|
|
307
|
+
| **[DBCache+TaylorSeer(F=1,B=0,O=1)](https://github.com/vipshop/cache-dit)** | 1153.05 | **3.23×** | **1.0221** | 32.819 |
|
|
307
308
|
| DuCa(N=5) | 978.76 | 3.80× | 0.9955 | 32.241 |
|
|
308
309
|
| TaylorSeer(N=4,O=2) | 1042.27 | 3.57× | 0.9857 | 32.413 |
|
|
309
|
-
| **[DBCache
|
|
310
|
-
| **[
|
|
310
|
+
| **[DBCache(F=1,B=0,W=4,MC=6)](https://github.com/vipshop/cache-dit)** | 944.75 | **3.94×** | 0.9997 | 32.849 |
|
|
311
|
+
| **[DBCache+TaylorSeer(F=1,B=0,O=1)](https://github.com/vipshop/cache-dit)** | 944.75 | **3.94×** | **1.0107** | 32.865 |
|
|
312
|
+
| **[FoCa(N=5): arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** | 893.54 | **4.16×** | **1.0029** | **32.948** |
|
|
311
313
|
|
|
312
314
|
<details>
|
|
313
315
|
<summary> Show all comparison </summary>
|
|
@@ -320,12 +322,14 @@ The comparison between **cache-dit: DBCache** and algorithms such as Δ-DiT, Chi
|
|
|
320
322
|
| Δ-DiT(N=3) | 1686.76 | 2.21× | 0.8721 | 32.102 |
|
|
321
323
|
| [**FLUX.1**-dev]: 34% steps | 1264.63 | 3.13× | 0.9453 | 32.114 |
|
|
322
324
|
| Chipmunk | 1505.87 | 2.47× | 0.9936 | 32.776 |
|
|
323
|
-
| FORA
|
|
324
|
-
| **[DBCache(F=4,B=0,W=4,MC=4)](https://github.com/vipshop/cache-dit)** |
|
|
325
|
+
| FORA(N=3) | 1320.07 | 2.82× | 0.9776 | 32.266 |
|
|
326
|
+
| **[DBCache(F=4,B=0,W=4,MC=4)](https://github.com/vipshop/cache-dit)** | 1400.08 | **2.66×** | **1.0065** | 32.838 |
|
|
325
327
|
| DuCa(N=5) | 978.76 | 3.80× | 0.9955 | 32.241 |
|
|
326
328
|
| TaylorSeer(N=4,O=2) | 1042.27 | 3.57× | 0.9857 | 32.413 |
|
|
327
|
-
| **[DBCache+TaylorSeer(F=1,B=0,O=1)](https://github.com/vipshop/cache-dit)** |
|
|
328
|
-
| **[
|
|
329
|
+
| **[DBCache+TaylorSeer(F=1,B=0,O=1)](https://github.com/vipshop/cache-dit)** | 1153.05 | **3.23×** | **1.0221** | 32.819 |
|
|
330
|
+
| **[DBCache(F=1,B=0,W=4,MC=6)](https://github.com/vipshop/cache-dit)** | 944.75 | **3.94×** | 0.9997 | 32.849 |
|
|
331
|
+
| **[DBCache+TaylorSeer(F=1,B=0,O=1)](https://github.com/vipshop/cache-dit)** | 944.75 | **3.94×** | **1.0107** | 32.865 |
|
|
332
|
+
| **[FoCa(N=5): arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** | 893.54 | **4.16×** | **1.0029** | **32.948** |
|
|
329
333
|
| [**FLUX.1**-dev]: 22% steps | 818.29 | 4.55× | 0.8183 | 31.772 |
|
|
330
334
|
| FORA(N=4) | 967.91 | 3.84× | 0.9730 | 32.142 |
|
|
331
335
|
| ToCa(N=8) | 784.54 | 4.74× | 0.9451 | 31.993 |
|
|
@@ -333,14 +337,14 @@ The comparison between **cache-dit: DBCache** and algorithms such as Δ-DiT, Chi
|
|
|
333
337
|
| TeaCache(l=0.8) | 892.35 | 4.17× | 0.8683 | 31.704 |
|
|
334
338
|
| **[DBCache(F=4,B=0,W=4,MC=10)](https://github.com/vipshop/cache-dit)** | 816.65 | 4.56x | 0.8245 | 32.191 |
|
|
335
339
|
| TaylorSeer(N=5,O=2) | 893.54 | 4.16× | 0.9768 | 32.467 |
|
|
336
|
-
| **[FoCa(N=7) arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** |
|
|
340
|
+
| **[FoCa(N=7): arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** | 670.44 | **5.54×** | **0.9891** | **32.920** |
|
|
337
341
|
| FORA(N=7) | 670.14 | 5.55× | 0.7418 | 31.519 |
|
|
338
342
|
| ToCa(N=12) | 644.70 | 5.77× | 0.7155 | 31.808 |
|
|
339
343
|
| DuCa(N=10) | 606.91 | 6.13× | 0.8382 | 31.759 |
|
|
340
344
|
| TeaCache(l=1.2) | 669.27 | 5.56× | 0.7394 | 31.704 |
|
|
341
|
-
| **[DBCache(F=1,B=0,W=4,MC=10)](https://github.com/vipshop/cache-dit)** |
|
|
345
|
+
| **[DBCache(F=1,B=0,W=4,MC=10)](https://github.com/vipshop/cache-dit)** | 651.90 | **5.72x** | 0.8796 | **32.318** |
|
|
342
346
|
| TaylorSeer(N=7,O=2) | 670.44 | 5.54× | 0.9128 | 32.128 |
|
|
343
|
-
| **[FoCa(N=8) arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** |
|
|
347
|
+
| **[FoCa(N=8): arxiv.2508.16211](https://arxiv.org/pdf/2508.16211)** | 596.07 | **6.24×** | **0.9502** | **32.706** |
|
|
344
348
|
|
|
345
349
|
NOTE: Except for DBCache, other performance data are referenced from the paper [FoCa, arxiv.2508.16211](https://arxiv.org/pdf/2508.16211).
|
|
346
350
|
|
|
@@ -575,7 +579,7 @@ cache_dit.enable_cache(
|
|
|
575
579
|
|24.85s|15.59s|8.58s|15.41s|15.11s|17.74s|
|
|
576
580
|
|<img src=https://github.com/vipshop/cache-dit/raw/main/assets/NONE_R0.08_S0.png width=105px>|<img src=https://github.com/vipshop/cache-dit/raw/main/assets/DBCACHE_F1B0S1_R0.08_S11.png width=105px> | <img src=https://github.com/vipshop/cache-dit/raw/main/assets/DBCACHE_F1B0S1_R0.2_S19.png width=105px>|<img src=https://github.com/vipshop/cache-dit/raw/main/assets/DBCACHE_F8B8S1_R0.15_S15.png width=105px>|<img src=https://github.com/vipshop/cache-dit/raw/main/assets/DBCACHE_F12B12S4_R0.2_S16.png width=105px>|<img src=https://github.com/vipshop/cache-dit/raw/main/assets/DBCACHE_F16B16S4_R0.2_S13.png width=105px>|
|
|
577
581
|
|
|
578
|
-
## 🔥
|
|
582
|
+
## 🔥TaylorSeer Calibrator
|
|
579
583
|
|
|
580
584
|
<div id="taylorseer"></div>
|
|
581
585
|
|
|
@@ -588,17 +592,22 @@ $$
|
|
|
588
592
|
**TaylorSeer** employs a differential method to approximate the higher-order derivatives of features and predict features in future timesteps with Taylor series expansion. The TaylorSeer implemented in cache-dit supports both hidden states and residual cache types. That is $\mathcal{F}\_{\text {pred }, m}\left(x_{t-k}^l\right)$ can be a residual cache or a hidden-state cache.
|
|
589
593
|
|
|
590
594
|
```python
|
|
595
|
+
from cache_dit import TaylorSeerCalibratorConfig
|
|
596
|
+
|
|
591
597
|
cache_dit.enable_cache(
|
|
592
598
|
pipe,
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
#
|
|
596
|
-
|
|
597
|
-
#
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
599
|
+
# Basic DBCache w/ FnBn configurations
|
|
600
|
+
max_warmup_steps=8, # steps do not cache
|
|
601
|
+
max_cached_steps=-1, # -1 means no limit
|
|
602
|
+
Fn_compute_blocks=8, # Fn, F8, etc.
|
|
603
|
+
Bn_compute_blocks=8, # Bn, B8, etc.
|
|
604
|
+
residual_diff_threshold=0.12,
|
|
605
|
+
# Then, you can use the TaylorSeer Calibrator to approximate
|
|
606
|
+
# the values in cached steps, taylorseer_order default is 1.
|
|
607
|
+
calibrator_config=TaylorSeerCalibratorConfig(
|
|
608
|
+
taylorseer_order=1,
|
|
609
|
+
),
|
|
610
|
+
)
|
|
602
611
|
```
|
|
603
612
|
|
|
604
613
|
> [!Important]
|
|
@@ -721,7 +730,7 @@ The **cache-dit** codebase is adapted from FBCache. Over time its codebase diver
|
|
|
721
730
|
|
|
722
731
|
```BibTeX
|
|
723
732
|
@misc{cache-dit@2025,
|
|
724
|
-
title={cache-dit: A Unified and Training-free Cache Acceleration
|
|
733
|
+
title={cache-dit: A Unified, Flexible and Training-free Cache Acceleration Framework for 🤗Diffusers.},
|
|
725
734
|
url={https://github.com/vipshop/cache-dit.git},
|
|
726
735
|
note={Open-source software available at https://github.com/vipshop/cache-dit.git},
|
|
727
736
|
author={vipshop.com},
|
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
cache_dit/__init__.py,sha256=
|
|
2
|
-
cache_dit/_version.py,sha256=
|
|
1
|
+
cache_dit/__init__.py,sha256=Nd4a609z8PLFMSO8J0sUe2xRaFDIYK8778ff8yBU7uQ,1457
|
|
2
|
+
cache_dit/_version.py,sha256=gGLpQUQx-ty9SEy9PYw9OgJWWzJLBnCpfJOfzL7SjlI,704
|
|
3
3
|
cache_dit/logger.py,sha256=0zsu42hN-3-rgGC_C29ms1IvVpV4_b4_SwJCKSenxBE,4304
|
|
4
|
-
cache_dit/utils.py,sha256=
|
|
4
|
+
cache_dit/utils.py,sha256=bERXpCaCpOPThXB8Rkk52yAjjLrvxbt12ntpzpWdfUQ,11131
|
|
5
5
|
cache_dit/cache_factory/.gitignore,sha256=5Cb-qT9wsTUoMJ7vACDF7ZcLpAXhi5v-xdcWSRit988,23
|
|
6
|
-
cache_dit/cache_factory/__init__.py,sha256=
|
|
7
|
-
cache_dit/cache_factory/
|
|
8
|
-
cache_dit/cache_factory/cache_interface.py,sha256=tHQv7i8Hp6nfbjZWHwDx3nEvCfxLeBw26aMYjyu6nMw,8541
|
|
6
|
+
cache_dit/cache_factory/__init__.py,sha256=Jj_Op6ACV35XilFPax3HEEsf_hOomjmogmNyWWteq_4,1539
|
|
7
|
+
cache_dit/cache_factory/cache_interface.py,sha256=xpC-CWZDBfMb5BfnXnVW25xJhV8cYMRns-LKcPDksPU,9846
|
|
9
8
|
cache_dit/cache_factory/cache_types.py,sha256=ooukxQRG55uTLmaZ0SKw6gIeY6SQHhMxkbv55uj2Sqk,991
|
|
10
9
|
cache_dit/cache_factory/forward_pattern.py,sha256=FumlCuZ-TSmSYH0hGBHctSJ-oGLCftdZjLygqhsmdR4,2258
|
|
11
10
|
cache_dit/cache_factory/utils.py,sha256=XkVM9AXcB9zYq8-S8QKAsGz80r3tA6U3lBNGDGeHOe4,1871
|
|
12
11
|
cache_dit/cache_factory/block_adapters/__init__.py,sha256=33geXMz56TxFWMp0c-H4__MY5SGRzKMKj3TXnUYOMlc,17512
|
|
13
|
-
cache_dit/cache_factory/block_adapters/block_adapters.py,sha256=
|
|
12
|
+
cache_dit/cache_factory/block_adapters/block_adapters.py,sha256=HlmStNIny0rZiRBYw-xdYYViVk9AEt0XlquoacEGr1U,24203
|
|
14
13
|
cache_dit/cache_factory/block_adapters/block_registers.py,sha256=2L7QeM4ygnaKQpC9PoJod0QRYyxidUKU2AYpysDCUwE,2572
|
|
14
|
+
cache_dit/cache_factory/cache_adapters/__init__.py,sha256=qB4bu1m3LgotOeNKluIkbQIf72PXpZWQMaSn1MOFEmY,149
|
|
15
|
+
cache_dit/cache_factory/cache_adapters/cache_adapter.py,sha256=6WArUrTmtkZg147_Qef5jfzMVRg2hfYwvSB9Cvpf_HA,18297
|
|
16
|
+
cache_dit/cache_factory/cache_adapters/v2/__init__.py,sha256=9PAH5YwpG_m0feE5eFQ7d2450nQR_Ctq8cd9Xu1Ldtk,96
|
|
17
|
+
cache_dit/cache_factory/cache_adapters/v2/cache_adapter_v2.py,sha256=ove_pDh2QC3vjXWIYtrb8anc-NOmPIrDZN7hu16fjwU,18309
|
|
15
18
|
cache_dit/cache_factory/cache_blocks/__init__.py,sha256=08Ox7kD05lkRKCOsVTdEZeKAWBheqpxfrAT1Nz7eclI,2916
|
|
16
19
|
cache_dit/cache_factory/cache_blocks/pattern_0_1_2.py,sha256=ElMps6_7uI74tSF9GDR_dEI0bZEhdzcepM29xFWnYo8,428
|
|
17
20
|
cache_dit/cache_factory/cache_blocks/pattern_3_4_5.py,sha256=Bv56qETXhsREvCrNvnZpSqDIIHsi6Ze3FJW4Yk2x3uI,8597
|
|
18
21
|
cache_dit/cache_factory/cache_blocks/pattern_base.py,sha256=d4H9kEB0AgnVMT8aF0Y54SUMUQUxw5HQ8gRkoCuTQ_A,14577
|
|
19
22
|
cache_dit/cache_factory/cache_blocks/utils.py,sha256=dGOC1tMMOvcbvEgx44eTESKn_jsv-0RZ3tRHPa3wmQ4,1315
|
|
20
|
-
cache_dit/cache_factory/cache_contexts/__init__.py,sha256=
|
|
23
|
+
cache_dit/cache_factory/cache_contexts/__init__.py,sha256=MQRxis-5gMhdJ6ZXIVN2nZEGPZoRLy59gSLniTYrWGY,437
|
|
21
24
|
cache_dit/cache_factory/cache_contexts/cache_context.py,sha256=FWdgInClWY8VZBsZIevtYk--rX-RL8c3QfNOJtqR8a4,11855
|
|
22
25
|
cache_dit/cache_factory/cache_contexts/cache_manager.py,sha256=Ig5VKoQ46iG3lKmsaMulYxd2vCm__2rY8NBvERwexwM,32719
|
|
23
26
|
cache_dit/cache_factory/cache_contexts/taylorseer.py,sha256=4nxgSEZvDy-w-7XuJYzsyzdtF1_uFrDwlF06XBDFVKQ,3922
|
|
27
|
+
cache_dit/cache_factory/cache_contexts/v2/__init__.py,sha256=GVafOd9BUa-Tyv7FZbTSkd4bGJPpMonb1AZv78qLeHU,385
|
|
28
|
+
cache_dit/cache_factory/cache_contexts/v2/cache_context_v2.py,sha256=JkMJSm-zme9ayonSFq6Y6esCb6RMuGLvhVINM-LFj2Y,11776
|
|
29
|
+
cache_dit/cache_factory/cache_contexts/v2/cache_manager_v2.py,sha256=ZRTl0M7jIPTIBS9lXoSh_pY6-hNu3JJ94WShv2CPWkk,32788
|
|
30
|
+
cache_dit/cache_factory/cache_contexts/v2/calibrators/__init__.py,sha256=BLCV0EtOcu30iytErL_IK6J9ZwmpE6P9ffNt4OL-IaU,2343
|
|
31
|
+
cache_dit/cache_factory/cache_contexts/v2/calibrators/base.py,sha256=mn6ZBkChGpGwN5csrHTUGMoX6BBPvqHXSLbIExiW-EU,748
|
|
32
|
+
cache_dit/cache_factory/cache_contexts/v2/calibrators/foca.py,sha256=jrEkoiLgDR2fiX_scIpaLIDT0pTMc9stg6L9HBkgsZw,894
|
|
33
|
+
cache_dit/cache_factory/cache_contexts/v2/calibrators/taylorseer.py,sha256=q5xBmT4EmpF_b3KPAjMIangTBvovE_c8ZfFjIN_E9tg,3834
|
|
24
34
|
cache_dit/cache_factory/patch_functors/__init__.py,sha256=oI6F3N9ezahRHaFUOZ1GfrAw1qFdKrxFXXmlwwehHj4,530
|
|
25
35
|
cache_dit/cache_factory/patch_functors/functor_base.py,sha256=Ahk0fTfrHgNdEl-9JSkACvfyyv9G-Ei5OSz7XBIlX5o,357
|
|
26
36
|
cache_dit/cache_factory/patch_functors/functor_chroma.py,sha256=xD0Q96VArp1vYBLQ0pcjRIyFB1i_Y7muZ2q07Hz8Oqs,13430
|
|
@@ -43,9 +53,9 @@ cache_dit/metrics/metrics.py,sha256=7UV-H2NRbhfr6dvrXEzU97Zy-BSQ5zEfm9CKtaK4ldg,
|
|
|
43
53
|
cache_dit/quantize/__init__.py,sha256=kWYoMAyZgBXu9BJlZjTQ0dRffW9GqeeY9_iTkXrb70A,59
|
|
44
54
|
cache_dit/quantize/quantize_ao.py,sha256=Fx1KW4l3gdEkdrcAYtPoDW7WKBJWrs3glOHiEwW_TgE,6160
|
|
45
55
|
cache_dit/quantize/quantize_interface.py,sha256=2s_R7xPSKuJeFpEGeLwRxnq_CqJcBG3a3lzyW5wh-UM,1241
|
|
46
|
-
cache_dit-0.3.
|
|
47
|
-
cache_dit-0.3.
|
|
48
|
-
cache_dit-0.3.
|
|
49
|
-
cache_dit-0.3.
|
|
50
|
-
cache_dit-0.3.
|
|
51
|
-
cache_dit-0.3.
|
|
56
|
+
cache_dit-0.3.1.dist-info/licenses/LICENSE,sha256=Dqb07Ik2dV41s9nIdMUbiRWEfDqo7-dQeRiY7kPO8PE,3769
|
|
57
|
+
cache_dit-0.3.1.dist-info/METADATA,sha256=I3gHe9m40_Ja0VurS7CDBYx_x_4rpra8zN245gBKv-A,46536
|
|
58
|
+
cache_dit-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
59
|
+
cache_dit-0.3.1.dist-info/entry_points.txt,sha256=FX2gysXaZx6NeK1iCLMcIdP8Q4_qikkIHtEmi3oWn8o,65
|
|
60
|
+
cache_dit-0.3.1.dist-info/top_level.txt,sha256=ZJDydonLEhujzz0FOkVbO-BqfzO9d_VqRHmZU-3MOZo,10
|
|
61
|
+
cache_dit-0.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|