flashmap 0.1.0__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.
- flashmap/__init__.py +14 -0
- flashmap/configuration_flashmap.py +105 -0
- flashmap/modeling_flashmap.py +556 -0
- flashmap/sglang/__init__.py +78 -0
- flashmap/sglang/jump_bank.py +203 -0
- flashmap/sglang/kernels.py +457 -0
- flashmap/sglang/model.py +1076 -0
- flashmap/sglang/sampler.py +188 -0
- flashmap/sglang/tree.py +78 -0
- flashmap/sglang/tree_worker.py +396 -0
- flashmap/sglang/verify_attention.py +474 -0
- flashmap/vllm/__init__.py +268 -0
- flashmap/vllm/fold.py +128 -0
- flashmap/vllm/kernels.py +443 -0
- flashmap/vllm/model.py +881 -0
- flashmap/vllm/speculator.py +235 -0
- flashmap-0.1.0.dist-info/METADATA +152 -0
- flashmap-0.1.0.dist-info/RECORD +22 -0
- flashmap-0.1.0.dist-info/WHEEL +5 -0
- flashmap-0.1.0.dist-info/entry_points.txt +5 -0
- flashmap-0.1.0.dist-info/licenses/LICENSE +21 -0
- flashmap-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""FlashMap drafting in vLLM, as a vLLM general plugin (``pip install flashmap[vllm]``).
|
|
2
|
+
|
|
3
|
+
Installing flashmap registers ``register`` under the ``vllm.general_plugins`` entry
|
|
4
|
+
point, which vLLM calls in every process before it parses a model. It teaches vLLM,
|
|
5
|
+
without patching its source:
|
|
6
|
+
|
|
7
|
+
* to read a FlashMap release folder (``model_type: "flashmap"`` with
|
|
8
|
+
``speculators_model_type: "flashmap"`` in its config.json) as a draft model on
|
|
9
|
+
vLLM's DFlash runtime (``method="dflash"``) with the ``FlashMapDraftModel``
|
|
10
|
+
architecture; speculators-format FlashMap checkpoints load the same way;
|
|
11
|
+
* the ``FlashMapDraftModel`` architecture (model.py);
|
|
12
|
+
* the speculator that drives it on the V2 model runner (speculator.py), chosen by
|
|
13
|
+
architecture the way vLLM chooses its DFlash2 speculator.
|
|
14
|
+
|
|
15
|
+
Every hook delegates to vLLM's own code unless a FlashMap checkpoint is in use. The
|
|
16
|
+
plugin supports vLLM 0.31.x; on other versions, or if registering fails, it logs a
|
|
17
|
+
warning and leaves vLLM untouched.
|
|
18
|
+
|
|
19
|
+
Serve with ``vllm serve <target> --speculative-config '{"model": "<FlashMap folder or
|
|
20
|
+
Hub id>", "num_speculative_tokens": 16}'``; the plugin fills in ``"method": "dflash"``.
|
|
21
|
+
|
|
22
|
+
The speculators fork trains FlashMap drafters and converts them to the release format;
|
|
23
|
+
it has no serving code of its own.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
__all__ = ["FLASHMAP_ARCHITECTURE", "SUPPORTED_VLLM", "register", "update_flashmap"]
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
FLASHMAP_ARCHITECTURE = "FlashMapDraftModel"
|
|
34
|
+
# vLLM (major, minor) versions whose internals the plugin hooks into.
|
|
35
|
+
SUPPORTED_VLLM = ((0, 31),)
|
|
36
|
+
|
|
37
|
+
# Speculators config fields the vLLM draft config carries over.
|
|
38
|
+
_FLASHMAP_FIELDS = (
|
|
39
|
+
"target_hidden_size",
|
|
40
|
+
"draft_vocab_size",
|
|
41
|
+
"block_size",
|
|
42
|
+
"timestep_embed_dim",
|
|
43
|
+
"timestep_frequency_dim",
|
|
44
|
+
"time_scale",
|
|
45
|
+
"qk_norm_eps",
|
|
46
|
+
"adaln_eps",
|
|
47
|
+
"noise_gate",
|
|
48
|
+
"time_schedule",
|
|
49
|
+
"num_steps",
|
|
50
|
+
"time_grids",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# A released FlashMap config holds the DiT's dimensions at its top level; vLLM's
|
|
55
|
+
# draft config reads them under the transformer_layer_config names.
|
|
56
|
+
_RELEASE_DIT_FIELDS = (
|
|
57
|
+
"hidden_size",
|
|
58
|
+
"num_hidden_layers",
|
|
59
|
+
"num_attention_heads",
|
|
60
|
+
"intermediate_size",
|
|
61
|
+
"vocab_size",
|
|
62
|
+
"rms_norm_eps",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def release_config_fields(config_dict: dict) -> dict:
|
|
67
|
+
"""The speculators-config view of a released FlashMap config.json
|
|
68
|
+
(``model_type: "flashmap"``, served as it is): its DiT dimensions, the aux
|
|
69
|
+
layers vLLM captures (DeepSpec's ``target_layer_ids`` + 1) and its field
|
|
70
|
+
names mapped onto this plugin's."""
|
|
71
|
+
dim, heads = config_dict["hidden_size"], config_dict["num_attention_heads"]
|
|
72
|
+
grids = config_dict.get("jump_grids") or {}
|
|
73
|
+
fields = {key: config_dict[key] for key in _RELEASE_DIT_FIELDS}
|
|
74
|
+
fields.update(
|
|
75
|
+
num_key_value_heads=heads,
|
|
76
|
+
head_dim=dim // heads,
|
|
77
|
+
hidden_act="gelu",
|
|
78
|
+
tie_word_embeddings=False,
|
|
79
|
+
max_position_embeddings=config_dict.get("max_position_embeddings", 131072),
|
|
80
|
+
rope_parameters={
|
|
81
|
+
"rope_type": "default",
|
|
82
|
+
"rope_theta": float(config_dict.get("rope_theta", 10000.0)),
|
|
83
|
+
},
|
|
84
|
+
aux_hidden_state_layer_ids=[i + 1 for i in config_dict["target_layer_ids"]],
|
|
85
|
+
timestep_embed_dim=config_dict.get("cond_dim", 256),
|
|
86
|
+
timestep_frequency_dim=config_dict.get("time_embed_dim"),
|
|
87
|
+
adaln_eps=config_dict.get("layer_norm_eps", 1e-6),
|
|
88
|
+
time_grids=[grids[str(n)] for n in range(1, len(grids) + 1)] or None,
|
|
89
|
+
)
|
|
90
|
+
return fields
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def update_flashmap(config_dict: dict, pre_trained_config: dict) -> None:
|
|
94
|
+
"""Map a ``flashmap`` speculators config, or a released FlashMap config
|
|
95
|
+
with ``speculators_model_type: "flashmap"``, onto the dict vLLM builds the
|
|
96
|
+
draft model's config from (cf. vLLM's ``update_dflash``)."""
|
|
97
|
+
if "aux_hidden_state_layer_ids" not in config_dict:
|
|
98
|
+
released = release_config_fields(config_dict)
|
|
99
|
+
config_dict = {**config_dict, **released}
|
|
100
|
+
pre_trained_config.update(
|
|
101
|
+
{
|
|
102
|
+
key: released[key]
|
|
103
|
+
for key in (
|
|
104
|
+
*_RELEASE_DIT_FIELDS,
|
|
105
|
+
"num_key_value_heads",
|
|
106
|
+
"head_dim",
|
|
107
|
+
"hidden_act",
|
|
108
|
+
"tie_word_embeddings",
|
|
109
|
+
"max_position_embeddings",
|
|
110
|
+
"rope_parameters",
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
if config_dict.get("flow_map") is False:
|
|
115
|
+
raise ValueError(
|
|
116
|
+
"This FlashMap checkpoint is a stage-1 flow (flow_map: false), which "
|
|
117
|
+
"drafts only by integrating over many steps; serve the flow map "
|
|
118
|
+
"distilled from it."
|
|
119
|
+
)
|
|
120
|
+
pre_trained_config["architectures"] = [FLASHMAP_ARCHITECTURE]
|
|
121
|
+
aux_layer_ids = config_dict["aux_hidden_state_layer_ids"]
|
|
122
|
+
pre_trained_config["eagle_aux_hidden_state_layer_ids"] = aux_layer_ids
|
|
123
|
+
pre_trained_config["dflash_config"] = {
|
|
124
|
+
# FlashMap's slots are not embedded token ids; any valid id fills them.
|
|
125
|
+
"mask_token_id": config_dict.get("mask_token_id") or 0,
|
|
126
|
+
"target_layer_ids": [i - 1 for i in aux_layer_ids],
|
|
127
|
+
"causal": False,
|
|
128
|
+
}
|
|
129
|
+
for key in _FLASHMAP_FIELDS:
|
|
130
|
+
if config_dict.get(key) is not None:
|
|
131
|
+
pre_trained_config[key] = config_dict[key]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _init_speculator(init_speculator):
|
|
135
|
+
def init_flashmap_or_other(vllm_config, device):
|
|
136
|
+
spec = vllm_config.speculative_config
|
|
137
|
+
if (
|
|
138
|
+
spec is not None
|
|
139
|
+
and spec.method == "dflash"
|
|
140
|
+
and FLASHMAP_ARCHITECTURE in (spec.draft_model_config.architectures or [])
|
|
141
|
+
):
|
|
142
|
+
from flashmap.vllm.speculator import ( # noqa: PLC0415
|
|
143
|
+
FlashMapSpeculator,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return FlashMapSpeculator(vllm_config, device)
|
|
147
|
+
return init_speculator(vllm_config, device)
|
|
148
|
+
|
|
149
|
+
init_flashmap_or_other.flashmap = True # type: ignore[attr-defined]
|
|
150
|
+
return init_flashmap_or_other
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _flashmap_config(model: object, revision: str | None) -> dict | None:
|
|
154
|
+
"""The config.json of ``model`` if it is a FlashMap drafter vLLM can serve."""
|
|
155
|
+
if not isinstance(model, str) or model in ("ngram", "[ngram]"):
|
|
156
|
+
return None
|
|
157
|
+
try:
|
|
158
|
+
from transformers import PretrainedConfig # noqa: PLC0415
|
|
159
|
+
|
|
160
|
+
config_dict, _ = PretrainedConfig.get_config_dict(model, revision=revision)
|
|
161
|
+
except Exception: # noqa: BLE001
|
|
162
|
+
return None
|
|
163
|
+
if config_dict.get("speculators_model_type") != "flashmap":
|
|
164
|
+
return None
|
|
165
|
+
return config_dict
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _post_init(post_init):
|
|
169
|
+
"""Let ``--speculative-config '{"model": <FlashMap>}'`` leave out ``method``
|
|
170
|
+
(FlashMap runs on vLLM's DFlash runtime) and ``num_speculative_tokens`` (the
|
|
171
|
+
drafter's block size)."""
|
|
172
|
+
|
|
173
|
+
def post_init_flashmap(self):
|
|
174
|
+
if self.method is None and not self._is_custom_proposer_path(self.model):
|
|
175
|
+
config_dict = _flashmap_config(self.model, self.revision)
|
|
176
|
+
if config_dict is not None:
|
|
177
|
+
self.method = "dflash"
|
|
178
|
+
if self.num_speculative_tokens is None:
|
|
179
|
+
self.num_speculative_tokens = int(config_dict["block_size"])
|
|
180
|
+
post_init(self)
|
|
181
|
+
|
|
182
|
+
post_init_flashmap.flashmap = True # type: ignore[attr-defined]
|
|
183
|
+
return post_init_flashmap
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _vllm_version() -> tuple[int, int] | None:
|
|
187
|
+
from vllm import __version__ # noqa: PLC0415
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
major, minor = __version__.split(".")[:2]
|
|
191
|
+
return int(major), int(minor)
|
|
192
|
+
except ValueError:
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def register() -> None:
|
|
197
|
+
"""vLLM general plugin entry point (idempotent, never raises)."""
|
|
198
|
+
try:
|
|
199
|
+
version = _vllm_version()
|
|
200
|
+
if version not in SUPPORTED_VLLM:
|
|
201
|
+
logger.warning(
|
|
202
|
+
"FlashMap's vLLM plugin supports vLLM %s, not %s; FlashMap "
|
|
203
|
+
"checkpoints will not load.",
|
|
204
|
+
" / ".join(f"{a}.{b}.x" for a, b in SUPPORTED_VLLM),
|
|
205
|
+
version,
|
|
206
|
+
)
|
|
207
|
+
return
|
|
208
|
+
_register()
|
|
209
|
+
except Exception: # noqa: BLE001
|
|
210
|
+
logger.warning(
|
|
211
|
+
"FlashMap's vLLM plugin failed to register; FlashMap checkpoints will "
|
|
212
|
+
"not load.",
|
|
213
|
+
exc_info=True,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _register() -> None:
|
|
218
|
+
from vllm import ModelRegistry # noqa: PLC0415
|
|
219
|
+
from vllm.transformers_utils.configs.speculators import ( # noqa: PLC0415
|
|
220
|
+
algos,
|
|
221
|
+
base,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
algos.SUPPORTED_SPECULATORS_TYPES["flashmap"] = update_flashmap
|
|
225
|
+
|
|
226
|
+
from vllm.transformers_utils import config as config_utils # noqa: PLC0415
|
|
227
|
+
|
|
228
|
+
# vLLM reads a config.json as a speculators checkpoint only when it has no
|
|
229
|
+
# model_type; a release folder's is "flashmap" (for transformers), so route
|
|
230
|
+
# that model_type the same way: SpeculatorsConfig, through update_flashmap.
|
|
231
|
+
config_utils._CONFIG_REGISTRY.setdefault("flashmap", "SpeculatorsConfig") # noqa: SLF001
|
|
232
|
+
config_utils._SPECULATIVE_DECODING_CONFIGS.add("flashmap") # noqa: SLF001
|
|
233
|
+
|
|
234
|
+
build = base.SpeculatorsConfig.build_vllm_speculative_config
|
|
235
|
+
if not getattr(build, "flashmap", False):
|
|
236
|
+
# FlashMap runs on vLLM's DFlash runtime.
|
|
237
|
+
def build_vllm_speculative_config(cls, config_dict):
|
|
238
|
+
result = build.__func__(cls, config_dict)
|
|
239
|
+
if result["method"] == "flashmap":
|
|
240
|
+
result["method"] = "dflash"
|
|
241
|
+
return result
|
|
242
|
+
|
|
243
|
+
build_vllm_speculative_config.flashmap = True # type: ignore[attr-defined]
|
|
244
|
+
base.SpeculatorsConfig.build_vllm_speculative_config = classmethod( # type: ignore[method-assign]
|
|
245
|
+
build_vllm_speculative_config
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
from vllm.config.speculative import SpeculativeConfig # noqa: PLC0415
|
|
249
|
+
|
|
250
|
+
if not getattr(SpeculativeConfig.__post_init__, "flashmap", False):
|
|
251
|
+
SpeculativeConfig.__post_init__ = _post_init( # type: ignore[method-assign]
|
|
252
|
+
SpeculativeConfig.__post_init__
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
if FLASHMAP_ARCHITECTURE not in ModelRegistry.get_supported_archs():
|
|
256
|
+
ModelRegistry.register_model(
|
|
257
|
+
FLASHMAP_ARCHITECTURE,
|
|
258
|
+
"flashmap.vllm.model:FlashMapDraftModel",
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
from vllm.v1.worker.gpu import spec_decode # noqa: PLC0415
|
|
262
|
+
|
|
263
|
+
if not getattr(spec_decode.init_speculator, "flashmap", False):
|
|
264
|
+
spec_decode.init_speculator = _init_speculator(spec_decode.init_speculator)
|
|
265
|
+
# The model runner binds init_speculator at import.
|
|
266
|
+
runner = sys.modules.get("vllm.v1.worker.gpu.model_runner")
|
|
267
|
+
if runner is not None and not getattr(runner.init_speculator, "flashmap", False):
|
|
268
|
+
runner.init_speculator = spec_decode.init_speculator
|
flashmap/vllm/fold.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Load-time folds of FlashMap's one-jump draft (pure PyTorch, no vLLM).
|
|
2
|
+
|
|
3
|
+
``fold_noise``: a one-jump draft embeds its starting noise ``x0 ~ N(0, I_V)`` as
|
|
4
|
+
``x_embed(noise_norm(x0 @ E))`` (plus a constant). ``x0 @ E`` is Gaussian with
|
|
5
|
+
covariance ``E^T E = Q Lambda Q^T``, so it is drawn as ``z @ A`` from
|
|
6
|
+
``z ~ N(0, I_H)`` with ``A = sqrt(Lambda) Q^T``; since ``A A^T = Lambda`` the
|
|
7
|
+
noise norm's mean square is ``sum(lambda z^2) / H``, elementwise in ``z``, and
|
|
8
|
+
``A``, the noise norm's weight and ``x_embed``'s weight fold into one matrix:
|
|
9
|
+
|
|
10
|
+
x_embed(noise_norm(z @ A)) = rsqrt(z^2 @ lambda / H + eps) * (z @ M^T) + b,
|
|
11
|
+
M = W_x diag(w) A^T.
|
|
12
|
+
|
|
13
|
+
``fold_head``: the DiT's output head (``D -> H`` with bias) and the target's LM
|
|
14
|
+
head (``H -> V``) have no nonlinearity between them, so the draft reads one
|
|
15
|
+
``(V, D)`` matrix and bias instead of both.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import math
|
|
19
|
+
|
|
20
|
+
import torch
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"fold_head",
|
|
24
|
+
"fold_noise",
|
|
25
|
+
"noise_factor",
|
|
26
|
+
"quantize_fp8_per_channel",
|
|
27
|
+
"split_argmax",
|
|
28
|
+
"timestep_embedding",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def timestep_embedding(t: torch.Tensor, dim: int, max_period: float = 10000.0):
|
|
33
|
+
"""Sinusoidal embedding of ``t``: ``cat([cos(t f), sin(t f)])`` in float32."""
|
|
34
|
+
half = dim // 2
|
|
35
|
+
freqs = torch.exp(
|
|
36
|
+
-math.log(max_period)
|
|
37
|
+
* torch.arange(half, dtype=torch.float32, device=t.device)
|
|
38
|
+
/ half
|
|
39
|
+
)
|
|
40
|
+
args = t.float()[..., None] * freqs
|
|
41
|
+
return torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@torch.no_grad()
|
|
45
|
+
def noise_factor(
|
|
46
|
+
embedding: torch.Tensor, chunk: int = 16384
|
|
47
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
48
|
+
"""``(A, lambda)`` in float64 for ``embedding (V, H)``: ``A = sqrt(Lambda)
|
|
49
|
+
Q^T`` with ``E^T E = Q Lambda Q^T``, so ``A^T A = E^T E`` and ``A A^T =
|
|
50
|
+
Lambda``."""
|
|
51
|
+
hidden = embedding.shape[1]
|
|
52
|
+
gram = torch.zeros(hidden, hidden, device=embedding.device, dtype=torch.float32)
|
|
53
|
+
for rows in embedding.split(chunk):
|
|
54
|
+
gram += rows.float().T @ rows.float()
|
|
55
|
+
eigvals, eigvecs = torch.linalg.eigh(gram.double())
|
|
56
|
+
eigvals = eigvals.clamp_min(0)
|
|
57
|
+
return eigvals.sqrt()[:, None] * eigvecs.T, eigvals
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@torch.no_grad()
|
|
61
|
+
def fold_noise(
|
|
62
|
+
embedding: torch.Tensor,
|
|
63
|
+
noise_norm_weight: torch.Tensor,
|
|
64
|
+
x_embed_weight: torch.Tensor,
|
|
65
|
+
chunk: int = 16384,
|
|
66
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
67
|
+
"""``(M, lambda / H)`` for ``embedding (V, H)``: ``M (D, H)`` in the
|
|
68
|
+
embedding's dtype, as ``F.linear`` takes it, and ``lambda / H (H,)`` in
|
|
69
|
+
float32 (see the module docstring)."""
|
|
70
|
+
factor, eigvals = noise_factor(embedding, chunk)
|
|
71
|
+
weight = noise_norm_weight.double()
|
|
72
|
+
folded = x_embed_weight.double() @ (factor * weight[None, :]).T
|
|
73
|
+
return folded.to(embedding.dtype), (eigvals / embedding.shape[1]).float()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@torch.no_grad()
|
|
77
|
+
def fold_head(
|
|
78
|
+
lm_head: torch.Tensor,
|
|
79
|
+
head_weight: torch.Tensor,
|
|
80
|
+
head_bias: torch.Tensor,
|
|
81
|
+
rows: torch.Tensor | None = None,
|
|
82
|
+
chunk: int = 8192,
|
|
83
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
84
|
+
"""``lm_head[rows] @ head`` as one ``(len(rows), D)`` weight and bias in the
|
|
85
|
+
LM head's dtype, folded ``chunk`` rows at a time in float32."""
|
|
86
|
+
count = lm_head.shape[0] if rows is None else rows.numel()
|
|
87
|
+
weight = torch.empty(
|
|
88
|
+
count, head_weight.shape[1], dtype=lm_head.dtype, device=lm_head.device
|
|
89
|
+
)
|
|
90
|
+
bias = torch.empty(count, dtype=lm_head.dtype, device=lm_head.device)
|
|
91
|
+
head_weight, head_bias = head_weight.float(), head_bias.float()
|
|
92
|
+
for start in range(0, count, chunk):
|
|
93
|
+
part = (
|
|
94
|
+
lm_head[start : start + chunk]
|
|
95
|
+
if rows is None
|
|
96
|
+
else lm_head[rows[start : start + chunk]]
|
|
97
|
+
).float()
|
|
98
|
+
weight[start : start + chunk] = (part @ head_weight).to(lm_head.dtype)
|
|
99
|
+
bias[start : start + chunk] = (part @ head_bias).to(lm_head.dtype)
|
|
100
|
+
return weight, bias
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@torch.no_grad()
|
|
104
|
+
def quantize_fp8_per_channel(
|
|
105
|
+
weight: torch.Tensor, dtype: torch.dtype = torch.float8_e4m3fn
|
|
106
|
+
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
107
|
+
"""``(w_q, scale)`` for a ``(N, K)`` weight: ``w_q (K, N)`` in ``dtype`` (a
|
|
108
|
+
column-major view, as scaled-mm kernels take it) and ``scale (N, 1)`` in
|
|
109
|
+
float32 with ``weight ~= (w_q.T * scale)``, one scale per output channel."""
|
|
110
|
+
finfo = torch.finfo(dtype)
|
|
111
|
+
w = weight.float()
|
|
112
|
+
scale = w.abs().amax(dim=1, keepdim=True).clamp_min(1e-12) / finfo.max
|
|
113
|
+
w_q = (w / scale).clamp(finfo.min, finfo.max).to(dtype)
|
|
114
|
+
return w_q.t(), scale.contiguous()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def split_argmax(logits: torch.Tensor, chunks: int = 128) -> torch.Tensor:
|
|
118
|
+
"""``logits.argmax(-1)`` for ``(rows, vocab)`` logits, reduced over vocabulary
|
|
119
|
+
chunks first so that a few rows still fill the GPU. Ties resolve to the
|
|
120
|
+
first index, as ``argmax`` does."""
|
|
121
|
+
rows, vocab = logits.shape
|
|
122
|
+
while chunks > 1 and vocab % chunks:
|
|
123
|
+
chunks //= 2
|
|
124
|
+
if chunks == 1:
|
|
125
|
+
return logits.argmax(dim=-1)
|
|
126
|
+
values, index = logits.view(rows, chunks, vocab // chunks).max(dim=-1)
|
|
127
|
+
best = values.argmax(dim=-1, keepdim=True)
|
|
128
|
+
return (best * (vocab // chunks) + index.gather(1, best)).squeeze(1)
|