weftcodec 1.2.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.
- weftcodec/__init__.py +62 -0
- weftcodec/__main__.py +6 -0
- weftcodec/ai_modes.py +3360 -0
- weftcodec/cli.py +252 -0
- weftcodec/crc32c.py +33 -0
- weftcodec/dcp.py +2108 -0
- weftcodec/dependency.py +224 -0
- weftcodec/errors.py +119 -0
- weftcodec/frame.py +455 -0
- weftcodec/hashing.py +56 -0
- weftcodec/huffman.py +212 -0
- weftcodec/identity.py +141 -0
- weftcodec/limits.py +58 -0
- weftcodec/modes.py +718 -0
- weftcodec/orbax.py +1734 -0
- weftcodec/service.py +959 -0
- weftcodec/torch.py +94 -0
- weftcodec/varint.py +88 -0
- weftcodec/wcb.py +310 -0
- weftcodec-1.2.0.dist-info/METADATA +257 -0
- weftcodec-1.2.0.dist-info/RECORD +24 -0
- weftcodec-1.2.0.dist-info/WHEEL +5 -0
- weftcodec-1.2.0.dist-info/entry_points.txt +2 -0
- weftcodec-1.2.0.dist-info/top_level.txt +1 -0
weftcodec/modes.py
ADDED
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
"""Payload-mode decoders (WEFTCODEC-FORMAT §3–§6, WEFT-AI-CODEC §2–§17).
|
|
2
|
+
|
|
3
|
+
Implemented modes: RAW (0), ZSTD (1), REFERENCE (2), DELTA (3), DICTIONARY (4),
|
|
4
|
+
STRUCTURED (5), TENSOR (6), TOKEN_SEQUENCE (7), QUANTIZED_TENSOR (8),
|
|
5
|
+
FLOAT_TENSOR (9), TENSOR_SHARDED (10), WEIGHT_DELTA (11), KV_CACHE (12),
|
|
6
|
+
ACTIVATION_STREAM (13), SEMANTIC_DELTA (14), TENSOR_TILED (15), and
|
|
7
|
+
SPARSE_DELTA (16).
|
|
8
|
+
|
|
9
|
+
No allocated mode raises :class:`weftcodec.errors.UnsupportedMode`; reserved
|
|
10
|
+
and experimental mode bytes are rejected by :mod:`weftcodec.frame`. There is no
|
|
11
|
+
approximate or lossy fallback anywhere in this module.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import io
|
|
17
|
+
import math
|
|
18
|
+
import struct
|
|
19
|
+
|
|
20
|
+
import zstandard
|
|
21
|
+
|
|
22
|
+
from . import ai_modes, varint, wcb
|
|
23
|
+
from .dependency import Resolver, resolve_dependency
|
|
24
|
+
from .errors import (
|
|
25
|
+
Corrupt,
|
|
26
|
+
LimitExceeded,
|
|
27
|
+
Malformed,
|
|
28
|
+
UnsupportedMode,
|
|
29
|
+
)
|
|
30
|
+
from .frame import Frame, MODE_NAMES
|
|
31
|
+
from .hashing import (
|
|
32
|
+
DOMAIN_CHUNK,
|
|
33
|
+
DOMAIN_QUANTIZED_TENSOR_PAYLOAD,
|
|
34
|
+
DOMAIN_TENSOR_PAYLOAD,
|
|
35
|
+
DOMAIN_TOKENS_PAYLOAD,
|
|
36
|
+
content_root,
|
|
37
|
+
hash_domain,
|
|
38
|
+
)
|
|
39
|
+
from .limits import Limits
|
|
40
|
+
|
|
41
|
+
TOKEN_ENCODING = "u64-zigzag-delta-leb128"
|
|
42
|
+
TENSOR_SCHEMA = "weft.tensor.v1"
|
|
43
|
+
TOKENS_SCHEMA = "weft.tokens.v1"
|
|
44
|
+
QUANTIZED_TENSOR_SCHEMA = "weft.quantized-tensor.v1"
|
|
45
|
+
QUANTIZED_TENSOR_QUANTIZATION = "affine-asymmetric-per-tensor"
|
|
46
|
+
|
|
47
|
+
TENSOR_DTYPE_SIZES = {
|
|
48
|
+
"f16": 2,
|
|
49
|
+
"bf16": 2,
|
|
50
|
+
"f32": 4,
|
|
51
|
+
"f64": 8,
|
|
52
|
+
"i8": 1,
|
|
53
|
+
"u8": 1,
|
|
54
|
+
"i16": 2,
|
|
55
|
+
"i32": 4,
|
|
56
|
+
"i64": 8,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
U64_MAX = (1 << 64) - 1
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# Frame decoding
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def decode_bytes(
|
|
68
|
+
data: bytes,
|
|
69
|
+
resolver: "Resolver | None" = None,
|
|
70
|
+
limits: "Limits | None" = None,
|
|
71
|
+
base_frame: "bytes | None" = None,
|
|
72
|
+
) -> bytes:
|
|
73
|
+
"""Parse and decode a complete frame."""
|
|
74
|
+
from .frame import parse
|
|
75
|
+
|
|
76
|
+
return decode_frame(parse(data, limits), resolver, limits, base_frame)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def decode_frame(
|
|
80
|
+
frame: Frame,
|
|
81
|
+
resolver: "Resolver | None" = None,
|
|
82
|
+
limits: "Limits | None" = None,
|
|
83
|
+
base_frame: "bytes | None" = None,
|
|
84
|
+
) -> bytes:
|
|
85
|
+
"""Decode a parsed frame and verify its content hash."""
|
|
86
|
+
limits = limits or Limits()
|
|
87
|
+
header = frame.header
|
|
88
|
+
mode = header.mode
|
|
89
|
+
|
|
90
|
+
if mode == 0: # RAW
|
|
91
|
+
plaintext = _decode_chunks(frame, limits) if header.is_chunked else frame.body
|
|
92
|
+
elif mode == 1: # ZSTD
|
|
93
|
+
plaintext = (
|
|
94
|
+
_decode_chunks(frame, limits)
|
|
95
|
+
if header.is_chunked
|
|
96
|
+
else _decompress(frame.body, header.decoded_len)
|
|
97
|
+
)
|
|
98
|
+
elif mode == 2: # REFERENCE
|
|
99
|
+
plaintext = resolve_dependency(frame.dependencies[0], resolver)
|
|
100
|
+
elif mode == 3: # DELTA
|
|
101
|
+
base = resolve_dependency(frame.dependencies[0], resolver)
|
|
102
|
+
plaintext = _decode_delta(frame.body, base, header.decoded_len, limits)
|
|
103
|
+
elif mode == 4: # DICTIONARY
|
|
104
|
+
dictionary = resolve_dependency(frame.dependencies[0], resolver)
|
|
105
|
+
plaintext = _decompress(frame.body, header.decoded_len, dictionary)
|
|
106
|
+
elif mode == 5: # STRUCTURED
|
|
107
|
+
wcb.decode(frame.body, limits)
|
|
108
|
+
plaintext = frame.body
|
|
109
|
+
elif mode == 6: # TENSOR
|
|
110
|
+
_, plaintext = _parse_tensor_body(frame, limits)
|
|
111
|
+
elif mode == 7: # TOKEN_SEQUENCE
|
|
112
|
+
_, plaintext = _parse_token_body(frame, limits)
|
|
113
|
+
elif mode == 8: # QUANTIZED_TENSOR
|
|
114
|
+
_, plaintext = _parse_quantized_body(frame, limits)
|
|
115
|
+
elif mode == 9: # FLOAT_TENSOR
|
|
116
|
+
plaintext = ai_modes.decode_float_tensor(frame, limits)
|
|
117
|
+
elif mode == 10: # TENSOR_SHARDED
|
|
118
|
+
plaintext = ai_modes.decode_tensor_sharded(frame, limits).planes
|
|
119
|
+
elif mode == 11: # WEIGHT_DELTA
|
|
120
|
+
plaintext = ai_modes.decode_weight_delta(
|
|
121
|
+
frame, resolver, limits, base_frame
|
|
122
|
+
)
|
|
123
|
+
elif mode == 12: # KV_CACHE
|
|
124
|
+
plaintext = ai_modes.decode_kv_cache(frame, limits)
|
|
125
|
+
elif mode == 13: # ACTIVATION_STREAM
|
|
126
|
+
plaintext = ai_modes.decode_activation_stream(frame, limits)
|
|
127
|
+
elif mode == 14: # SEMANTIC_DELTA
|
|
128
|
+
plaintext = ai_modes.decode_semantic_delta(
|
|
129
|
+
frame, resolver, limits, base_frame
|
|
130
|
+
)
|
|
131
|
+
elif mode == 15: # TENSOR_TILED
|
|
132
|
+
plaintext = ai_modes.decode_tensor_tiled(frame, limits)
|
|
133
|
+
elif mode == 16: # SPARSE_DELTA
|
|
134
|
+
plaintext = ai_modes.decode_sparse_delta(
|
|
135
|
+
frame, resolver, limits, base_frame
|
|
136
|
+
)
|
|
137
|
+
elif mode == 17: # FLOAT_TILED
|
|
138
|
+
plaintext = ai_modes.decode_float_tiled(frame, limits)
|
|
139
|
+
elif mode == 18: # FLOAT_TILED_STREAMS
|
|
140
|
+
plaintext = ai_modes.decode_float_tiled_streams(frame, limits)
|
|
141
|
+
else:
|
|
142
|
+
raise UnsupportedMode(
|
|
143
|
+
"mode %d (%s) is allocated but not implemented by the Python reader"
|
|
144
|
+
% (mode, MODE_NAMES.get(mode, "unknown"))
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if len(plaintext) != header.decoded_len:
|
|
148
|
+
raise Corrupt(
|
|
149
|
+
"decoded length %d differs from declared %d"
|
|
150
|
+
% (len(plaintext), header.decoded_len)
|
|
151
|
+
)
|
|
152
|
+
if content_root(plaintext) != header.content_hash:
|
|
153
|
+
raise Corrupt("content hash mismatch")
|
|
154
|
+
return bytes(plaintext)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _decode_chunks(frame: Frame, limits: Limits) -> bytes:
|
|
158
|
+
out = bytearray()
|
|
159
|
+
for index in range(len(frame.chunks)):
|
|
160
|
+
out.extend(_decode_chunk(frame, index))
|
|
161
|
+
if len(out) > limits.max_decoded_bytes:
|
|
162
|
+
raise LimitExceeded(
|
|
163
|
+
"decoded data length %d exceeds limit %d"
|
|
164
|
+
% (len(out), limits.max_decoded_bytes)
|
|
165
|
+
)
|
|
166
|
+
return bytes(out)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _decode_chunk(frame: Frame, index: int) -> bytes:
|
|
170
|
+
if index < 0 or index >= len(frame.chunks):
|
|
171
|
+
raise Malformed("chunk index %d out of range" % index)
|
|
172
|
+
chunk = frame.chunks[index]
|
|
173
|
+
start = chunk.encoded_off
|
|
174
|
+
end = start + chunk.encoded_len
|
|
175
|
+
if start > len(frame.body) or end > len(frame.body):
|
|
176
|
+
raise Malformed("chunk %d extends past body" % index)
|
|
177
|
+
encoded = frame.body[start:end]
|
|
178
|
+
|
|
179
|
+
if frame.header.mode == 0:
|
|
180
|
+
if len(encoded) != chunk.decoded_len:
|
|
181
|
+
raise Malformed(
|
|
182
|
+
"RAW chunk %d encoded_len does not equal decoded_len" % index
|
|
183
|
+
)
|
|
184
|
+
decoded = encoded
|
|
185
|
+
elif frame.header.mode == 1:
|
|
186
|
+
decoded = _decompress(encoded, chunk.decoded_len)
|
|
187
|
+
else:
|
|
188
|
+
raise Malformed("chunk table is only valid for RAW and ZSTD frames")
|
|
189
|
+
|
|
190
|
+
if len(decoded) != chunk.decoded_len:
|
|
191
|
+
raise Corrupt(
|
|
192
|
+
"chunk %d decoded length %d differs from declared %d"
|
|
193
|
+
% (index, len(decoded), chunk.decoded_len)
|
|
194
|
+
)
|
|
195
|
+
if content_root(decoded) != chunk.hash:
|
|
196
|
+
raise Corrupt("chunk %d hash mismatch" % index)
|
|
197
|
+
return decoded
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
# Zstandard
|
|
202
|
+
# ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _check_zstd_preamble(body: bytes, declared_len: int) -> None:
|
|
206
|
+
if not body:
|
|
207
|
+
raise Malformed("zstd payload is empty; a zstd frame is never zero bytes")
|
|
208
|
+
try:
|
|
209
|
+
frame_len = zstandard.frame_content_size(body)
|
|
210
|
+
except zstandard.ZstdError:
|
|
211
|
+
return
|
|
212
|
+
unknown = getattr(zstandard, "CONTENTSIZE_UNKNOWN", -1)
|
|
213
|
+
error = getattr(zstandard, "CONTENTSIZE_ERROR", -2)
|
|
214
|
+
if frame_len not in (unknown, error) and frame_len != declared_len:
|
|
215
|
+
raise Corrupt(
|
|
216
|
+
"zstd frame declares content size %d, Weft header declares %d"
|
|
217
|
+
% (frame_len, declared_len)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _decompress(body: bytes, declared_len: int, dictionary: "bytes | None" = None) -> bytes:
|
|
222
|
+
_check_zstd_preamble(body, declared_len)
|
|
223
|
+
if dictionary is None:
|
|
224
|
+
context = zstandard.ZstdDecompressor()
|
|
225
|
+
else:
|
|
226
|
+
raw_dict = zstandard.ZstdCompressionDict(
|
|
227
|
+
bytes(dictionary), dict_type=zstandard.DICT_TYPE_RAWCONTENT
|
|
228
|
+
)
|
|
229
|
+
context = zstandard.ZstdDecompressor(dict_data=raw_dict)
|
|
230
|
+
|
|
231
|
+
out = bytearray()
|
|
232
|
+
limit = declared_len + 1
|
|
233
|
+
try:
|
|
234
|
+
with context.stream_reader(io.BytesIO(body)) as reader:
|
|
235
|
+
while len(out) < limit:
|
|
236
|
+
piece = reader.read(min(limit - len(out), 1 << 20))
|
|
237
|
+
if not piece:
|
|
238
|
+
break
|
|
239
|
+
out.extend(piece)
|
|
240
|
+
except zstandard.ZstdError as exc:
|
|
241
|
+
raise Corrupt("zstd decompression failed: %s" % exc)
|
|
242
|
+
if len(out) != declared_len:
|
|
243
|
+
raise Corrupt(
|
|
244
|
+
"zstd output length %d differs from declared %d" % (len(out), declared_len)
|
|
245
|
+
)
|
|
246
|
+
return bytes(out)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ---------------------------------------------------------------------------
|
|
250
|
+
# DELTA (mode 3)
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _decode_delta(body: bytes, base: bytes, expected_len: int, limits: Limits) -> bytes:
|
|
255
|
+
if expected_len > limits.max_decoded_bytes:
|
|
256
|
+
raise LimitExceeded(
|
|
257
|
+
"decoded data length %d exceeds limit %d"
|
|
258
|
+
% (expected_len, limits.max_decoded_bytes)
|
|
259
|
+
)
|
|
260
|
+
out = bytearray()
|
|
261
|
+
pos = 0
|
|
262
|
+
ops = 0
|
|
263
|
+
|
|
264
|
+
while pos < len(body):
|
|
265
|
+
ops += 1
|
|
266
|
+
if ops > limits.max_delta_ops:
|
|
267
|
+
raise LimitExceeded(
|
|
268
|
+
"delta op count %d exceeds limit %d" % (ops, limits.max_delta_ops)
|
|
269
|
+
)
|
|
270
|
+
opcode = body[pos]
|
|
271
|
+
pos += 1
|
|
272
|
+
if opcode == 0x00: # COPY
|
|
273
|
+
offset, pos = varint.decode(body, pos)
|
|
274
|
+
length, pos = varint.decode(body, pos)
|
|
275
|
+
if length == 0:
|
|
276
|
+
raise Malformed("delta COPY has zero length")
|
|
277
|
+
end = offset + length
|
|
278
|
+
if end > len(base):
|
|
279
|
+
raise Malformed(
|
|
280
|
+
"delta COPY range %d..%d exceeds base length %d"
|
|
281
|
+
% (offset, end, len(base))
|
|
282
|
+
)
|
|
283
|
+
if len(out) + length > expected_len:
|
|
284
|
+
raise Corrupt("delta emits more bytes than declared decoded_len")
|
|
285
|
+
out.extend(base[offset:end])
|
|
286
|
+
elif opcode == 0x01: # INSERT
|
|
287
|
+
length, pos = varint.decode(body, pos)
|
|
288
|
+
if length == 0:
|
|
289
|
+
raise Malformed("delta INSERT has zero length")
|
|
290
|
+
end = pos + length
|
|
291
|
+
if end > len(body):
|
|
292
|
+
raise Malformed("delta INSERT extends past body")
|
|
293
|
+
if len(out) + length > expected_len:
|
|
294
|
+
raise Corrupt("delta emits more bytes than declared decoded_len")
|
|
295
|
+
out.extend(body[pos:end])
|
|
296
|
+
pos = end
|
|
297
|
+
else:
|
|
298
|
+
raise Malformed("unknown delta opcode 0x%02x" % opcode)
|
|
299
|
+
|
|
300
|
+
if len(out) != expected_len:
|
|
301
|
+
raise Corrupt(
|
|
302
|
+
"delta produced %d bytes but decoded_len is %d" % (len(out), expected_len)
|
|
303
|
+
)
|
|
304
|
+
return bytes(out)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
# ---------------------------------------------------------------------------
|
|
308
|
+
# Shared AI-mode helpers
|
|
309
|
+
# ---------------------------------------------------------------------------
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _split_ai_body(body: bytes, decoded_len: int) -> "tuple[bytes, bytes]":
|
|
313
|
+
if len(body) < 4:
|
|
314
|
+
raise Malformed("AI body is shorter than its 4-byte metadata length")
|
|
315
|
+
meta_len = int.from_bytes(body[0:4], "little")
|
|
316
|
+
meta_end = 4 + meta_len
|
|
317
|
+
if meta_end > len(body):
|
|
318
|
+
raise Malformed("AI metadata extends past the frame body")
|
|
319
|
+
payload = body[meta_end:]
|
|
320
|
+
if len(payload) != decoded_len:
|
|
321
|
+
raise Malformed(
|
|
322
|
+
"AI payload length %d differs from decoded_len %d"
|
|
323
|
+
% (len(payload), decoded_len)
|
|
324
|
+
)
|
|
325
|
+
return body[4:meta_end], payload
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _ai_map(value, what: str) -> dict:
|
|
329
|
+
if not isinstance(value, dict):
|
|
330
|
+
raise Malformed("%s metadata must be a WCB map" % what)
|
|
331
|
+
return value
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _check_exact_keys(map_value: dict, expected: "tuple[str, ...]", what: str) -> None:
|
|
335
|
+
for key in map_value:
|
|
336
|
+
if key not in expected:
|
|
337
|
+
raise Malformed("%s metadata has unknown key `%s`" % (what, key))
|
|
338
|
+
for key in expected:
|
|
339
|
+
if key not in map_value:
|
|
340
|
+
raise Malformed("%s metadata is missing key `%s`" % (what, key))
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _meta_text(map_value: dict, key: str) -> str:
|
|
344
|
+
value = map_value.get(key)
|
|
345
|
+
if not isinstance(value, str):
|
|
346
|
+
raise Malformed("metadata `%s` must be text" % key)
|
|
347
|
+
return value
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _meta_u64(map_value: dict, key: str) -> int:
|
|
351
|
+
value = map_value.get(key)
|
|
352
|
+
if not isinstance(value, wcb.U64):
|
|
353
|
+
raise Malformed("metadata `%s` must be u64" % key)
|
|
354
|
+
return value.value
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def _meta_i64(map_value: dict, key: str) -> int:
|
|
358
|
+
value = map_value.get(key)
|
|
359
|
+
if not isinstance(value, wcb.I64):
|
|
360
|
+
raise Malformed("metadata `%s` must be i64" % key)
|
|
361
|
+
return value.value
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _meta_bytes(map_value: dict, key: str) -> bytes:
|
|
365
|
+
value = map_value.get(key)
|
|
366
|
+
if not isinstance(value, (bytes, bytearray)):
|
|
367
|
+
raise Malformed("metadata `%s` must be bytes" % key)
|
|
368
|
+
return bytes(value)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _meta_shape(map_value: dict) -> "list[int]":
|
|
372
|
+
value = map_value.get("shape")
|
|
373
|
+
if not isinstance(value, list):
|
|
374
|
+
raise Malformed("metadata `shape` must be an array")
|
|
375
|
+
shape = []
|
|
376
|
+
for item in value:
|
|
377
|
+
if not isinstance(item, wcb.U64):
|
|
378
|
+
raise Malformed("metadata `shape` elements must be u64")
|
|
379
|
+
shape.append(item.value)
|
|
380
|
+
return shape
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _tensor_product(shape: "list[int]", limits: Limits) -> int:
|
|
384
|
+
if len(shape) > limits.max_tensor_rank:
|
|
385
|
+
raise LimitExceeded(
|
|
386
|
+
"tensor rank %d exceeds limit %d" % (len(shape), limits.max_tensor_rank)
|
|
387
|
+
)
|
|
388
|
+
product = 1
|
|
389
|
+
for dim in shape:
|
|
390
|
+
product *= dim
|
|
391
|
+
if product > U64_MAX:
|
|
392
|
+
raise LimitExceeded("tensor shape product overflows u64")
|
|
393
|
+
if product > limits.max_tensor_elements:
|
|
394
|
+
raise LimitExceeded(
|
|
395
|
+
"tensor element count %d exceeds limit %d"
|
|
396
|
+
% (product, limits.max_tensor_elements)
|
|
397
|
+
)
|
|
398
|
+
return product
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _descriptor(body: bytes, decoded_len: int, limits: Limits, what: str):
|
|
402
|
+
descriptor_bytes, payload = _split_ai_body(body, decoded_len)
|
|
403
|
+
value = wcb.decode(descriptor_bytes, limits)
|
|
404
|
+
return _ai_map(value, what), payload
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# ---------------------------------------------------------------------------
|
|
408
|
+
# TENSOR (mode 6)
|
|
409
|
+
# ---------------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
_TENSOR_KEYS = (
|
|
412
|
+
"schema",
|
|
413
|
+
"dtype",
|
|
414
|
+
"shape",
|
|
415
|
+
"layout",
|
|
416
|
+
"endianness",
|
|
417
|
+
"element_count",
|
|
418
|
+
"payload_bytes",
|
|
419
|
+
"payload_hash",
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
def _parse_tensor_body(frame: Frame, limits: Limits):
|
|
424
|
+
map_value, payload = _descriptor(
|
|
425
|
+
frame.body, frame.header.decoded_len, limits, "tensor"
|
|
426
|
+
)
|
|
427
|
+
_check_exact_keys(map_value, _TENSOR_KEYS, "tensor")
|
|
428
|
+
schema = _meta_text(map_value, "schema")
|
|
429
|
+
if schema != TENSOR_SCHEMA:
|
|
430
|
+
raise Malformed("unsupported tensor schema `%s`" % schema)
|
|
431
|
+
dtype = _meta_text(map_value, "dtype")
|
|
432
|
+
if dtype not in TENSOR_DTYPE_SIZES:
|
|
433
|
+
raise Malformed(
|
|
434
|
+
"unknown tensor dtype `%s` (v1 allows f16, bf16, f32, f64, i8, u8, "
|
|
435
|
+
"i16, i32, i64)" % dtype
|
|
436
|
+
)
|
|
437
|
+
layout = _meta_text(map_value, "layout")
|
|
438
|
+
if layout != "row_major":
|
|
439
|
+
raise Malformed(
|
|
440
|
+
"tensor layout `%s` is specified but not implemented in v1 (only row_major)"
|
|
441
|
+
% layout
|
|
442
|
+
)
|
|
443
|
+
endianness = _meta_text(map_value, "endianness")
|
|
444
|
+
if endianness != "little":
|
|
445
|
+
raise Malformed(
|
|
446
|
+
"tensor endianness `%s` is specified but not implemented in v1 (only little)"
|
|
447
|
+
% endianness
|
|
448
|
+
)
|
|
449
|
+
shape = _meta_shape(map_value)
|
|
450
|
+
declared_count = _meta_u64(map_value, "element_count")
|
|
451
|
+
declared_bytes = _meta_u64(map_value, "payload_bytes")
|
|
452
|
+
expected_count = _tensor_product(shape, limits)
|
|
453
|
+
if declared_count != expected_count:
|
|
454
|
+
raise Malformed(
|
|
455
|
+
"tensor element_count %d does not match shape product %d"
|
|
456
|
+
% (declared_count, expected_count)
|
|
457
|
+
)
|
|
458
|
+
expected_bytes = declared_count * TENSOR_DTYPE_SIZES[dtype]
|
|
459
|
+
if expected_bytes > U64_MAX:
|
|
460
|
+
raise LimitExceeded("tensor payload byte count overflows u64")
|
|
461
|
+
if declared_bytes != expected_bytes:
|
|
462
|
+
raise Malformed(
|
|
463
|
+
"tensor payload_bytes %d does not match element_count x element_size %d"
|
|
464
|
+
% (declared_bytes, expected_bytes)
|
|
465
|
+
)
|
|
466
|
+
if declared_bytes != len(payload):
|
|
467
|
+
raise Malformed(
|
|
468
|
+
"tensor payload is %d bytes but metadata declares %d"
|
|
469
|
+
% (len(payload), declared_bytes)
|
|
470
|
+
)
|
|
471
|
+
declared_hash = _meta_bytes(map_value, "payload_hash")
|
|
472
|
+
if len(declared_hash) != 32:
|
|
473
|
+
raise Malformed(
|
|
474
|
+
"tensor payload_hash must be 32 bytes, got %d" % len(declared_hash)
|
|
475
|
+
)
|
|
476
|
+
if declared_hash != hash_domain(DOMAIN_TENSOR_PAYLOAD, payload):
|
|
477
|
+
raise Corrupt("tensor payload_hash mismatch")
|
|
478
|
+
meta = {
|
|
479
|
+
"schema": schema,
|
|
480
|
+
"dtype": dtype,
|
|
481
|
+
"shape": shape,
|
|
482
|
+
"layout": layout,
|
|
483
|
+
"endianness": endianness,
|
|
484
|
+
"element_count": declared_count,
|
|
485
|
+
"payload_bytes": declared_bytes,
|
|
486
|
+
}
|
|
487
|
+
return meta, payload
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def tensor_metadata(frame: Frame, limits: "Limits | None" = None) -> dict:
|
|
491
|
+
meta, _ = _parse_tensor_body(frame, limits or Limits())
|
|
492
|
+
return meta
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
# ---------------------------------------------------------------------------
|
|
496
|
+
# TOKEN_SEQUENCE (mode 7)
|
|
497
|
+
# ---------------------------------------------------------------------------
|
|
498
|
+
|
|
499
|
+
_TOKEN_KEYS = (
|
|
500
|
+
"schema",
|
|
501
|
+
"vocab_schema",
|
|
502
|
+
"encoding",
|
|
503
|
+
"token_count",
|
|
504
|
+
"payload_bytes",
|
|
505
|
+
"payload_hash",
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def _parse_token_body(frame: Frame, limits: Limits):
|
|
510
|
+
map_value, payload = _descriptor(
|
|
511
|
+
frame.body, frame.header.decoded_len, limits, "token"
|
|
512
|
+
)
|
|
513
|
+
_check_exact_keys(map_value, _TOKEN_KEYS, "token")
|
|
514
|
+
schema = _meta_text(map_value, "schema")
|
|
515
|
+
if schema != TOKENS_SCHEMA:
|
|
516
|
+
raise Malformed("unsupported token schema `%s`" % schema)
|
|
517
|
+
vocab_schema = _meta_text(map_value, "vocab_schema")
|
|
518
|
+
if not vocab_schema:
|
|
519
|
+
raise Malformed("token vocab_schema must not be empty")
|
|
520
|
+
encoding = _meta_text(map_value, "encoding")
|
|
521
|
+
if encoding != TOKEN_ENCODING:
|
|
522
|
+
raise Malformed(
|
|
523
|
+
"token encoding `%s` is specified but not implemented in v1 (only %s)"
|
|
524
|
+
% (encoding, TOKEN_ENCODING)
|
|
525
|
+
)
|
|
526
|
+
token_count = _meta_u64(map_value, "token_count")
|
|
527
|
+
if token_count > limits.max_tokens:
|
|
528
|
+
raise LimitExceeded(
|
|
529
|
+
"token count %d exceeds limit %d" % (token_count, limits.max_tokens)
|
|
530
|
+
)
|
|
531
|
+
declared_bytes = _meta_u64(map_value, "payload_bytes")
|
|
532
|
+
if declared_bytes != len(payload):
|
|
533
|
+
raise Malformed(
|
|
534
|
+
"token payload is %d bytes but metadata declares %d"
|
|
535
|
+
% (len(payload), declared_bytes)
|
|
536
|
+
)
|
|
537
|
+
declared_hash = _meta_bytes(map_value, "payload_hash")
|
|
538
|
+
if len(declared_hash) != 32:
|
|
539
|
+
raise Malformed(
|
|
540
|
+
"token payload_hash must be 32 bytes, got %d" % len(declared_hash)
|
|
541
|
+
)
|
|
542
|
+
if declared_hash != hash_domain(DOMAIN_TOKENS_PAYLOAD, payload):
|
|
543
|
+
raise Corrupt("token payload_hash mismatch")
|
|
544
|
+
_validate_token_payload(payload, token_count, limits)
|
|
545
|
+
meta = {
|
|
546
|
+
"schema": schema,
|
|
547
|
+
"vocab_schema": vocab_schema,
|
|
548
|
+
"encoding": encoding,
|
|
549
|
+
"token_count": token_count,
|
|
550
|
+
"payload_bytes": declared_bytes,
|
|
551
|
+
}
|
|
552
|
+
return meta, payload
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def _validate_token_payload(payload: bytes, token_count: int, limits: Limits) -> None:
|
|
556
|
+
if token_count > limits.max_tokens:
|
|
557
|
+
raise LimitExceeded(
|
|
558
|
+
"token count %d exceeds limit %d" % (token_count, limits.max_tokens)
|
|
559
|
+
)
|
|
560
|
+
if token_count > len(payload):
|
|
561
|
+
raise Malformed(
|
|
562
|
+
"token count %d cannot fit in a %d-byte payload"
|
|
563
|
+
% (token_count, len(payload))
|
|
564
|
+
)
|
|
565
|
+
pos = 0
|
|
566
|
+
previous = 0
|
|
567
|
+
for index in range(token_count):
|
|
568
|
+
raw, pos = varint.decode(payload, pos)
|
|
569
|
+
if index == 0:
|
|
570
|
+
previous = raw
|
|
571
|
+
else:
|
|
572
|
+
previous = (previous + varint.zigzag_decode(raw)) & U64_MAX
|
|
573
|
+
if pos != len(payload):
|
|
574
|
+
raise Malformed(
|
|
575
|
+
"token payload has %d trailing bytes" % (len(payload) - pos)
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def token_metadata(frame: Frame, limits: "Limits | None" = None) -> dict:
|
|
580
|
+
meta, _ = _parse_token_body(frame, limits or Limits())
|
|
581
|
+
return meta
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def decode_token_payload(payload: bytes, token_count: int, limits: "Limits | None" = None):
|
|
585
|
+
"""Return token ids from an encoded token payload (exact inverse)."""
|
|
586
|
+
limits = limits or Limits()
|
|
587
|
+
_validate_token_payload(payload, token_count, limits)
|
|
588
|
+
ids = []
|
|
589
|
+
pos = 0
|
|
590
|
+
previous = 0
|
|
591
|
+
for index in range(token_count):
|
|
592
|
+
raw, pos = varint.decode(payload, pos)
|
|
593
|
+
if index == 0:
|
|
594
|
+
previous = raw
|
|
595
|
+
else:
|
|
596
|
+
previous = (previous + varint.zigzag_decode(raw)) & U64_MAX
|
|
597
|
+
ids.append(previous)
|
|
598
|
+
return ids
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
# ---------------------------------------------------------------------------
|
|
602
|
+
# QUANTIZED_TENSOR (mode 8)
|
|
603
|
+
# ---------------------------------------------------------------------------
|
|
604
|
+
|
|
605
|
+
_QUANT_KEYS = (
|
|
606
|
+
"schema",
|
|
607
|
+
"dtype",
|
|
608
|
+
"shape",
|
|
609
|
+
"layout",
|
|
610
|
+
"quantization",
|
|
611
|
+
"scale_bits_le",
|
|
612
|
+
"zero_point",
|
|
613
|
+
"element_count",
|
|
614
|
+
"payload_bytes",
|
|
615
|
+
"payload_hash",
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
def _validate_quantized_scale(scale: float) -> None:
|
|
620
|
+
if not math.isfinite(scale):
|
|
621
|
+
raise Malformed("quantized tensor scale must be finite (no NaN or infinity)")
|
|
622
|
+
if scale <= 0.0:
|
|
623
|
+
raise Malformed("quantized tensor scale must be greater than zero")
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def _validate_zero_point(dtype: str, zero_point: int) -> None:
|
|
627
|
+
if dtype == "i8":
|
|
628
|
+
low, high = -128, 127
|
|
629
|
+
elif dtype == "u8":
|
|
630
|
+
low, high = 0, 255
|
|
631
|
+
else:
|
|
632
|
+
raise Malformed("quantized tensor dtype must be i8 or u8")
|
|
633
|
+
if zero_point < low or zero_point > high:
|
|
634
|
+
raise Malformed(
|
|
635
|
+
"quantized tensor zero_point %d is outside %s range %d..=%d"
|
|
636
|
+
% (zero_point, dtype, low, high)
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
def _parse_quantized_body(frame: Frame, limits: Limits):
|
|
641
|
+
map_value, payload = _descriptor(
|
|
642
|
+
frame.body, frame.header.decoded_len, limits, "quantized tensor"
|
|
643
|
+
)
|
|
644
|
+
_check_exact_keys(map_value, _QUANT_KEYS, "quantized tensor")
|
|
645
|
+
schema = _meta_text(map_value, "schema")
|
|
646
|
+
if schema != QUANTIZED_TENSOR_SCHEMA:
|
|
647
|
+
raise Malformed("unsupported quantized tensor schema `%s`" % schema)
|
|
648
|
+
dtype = _meta_text(map_value, "dtype")
|
|
649
|
+
if dtype not in ("i8", "u8"):
|
|
650
|
+
raise Malformed(
|
|
651
|
+
"quantized tensor dtype `%s` is specified but not implemented in v1 "
|
|
652
|
+
"(only i8, u8)" % dtype
|
|
653
|
+
)
|
|
654
|
+
layout = _meta_text(map_value, "layout")
|
|
655
|
+
if layout != "row_major":
|
|
656
|
+
raise Malformed(
|
|
657
|
+
"quantized tensor layout `%s` is specified but not implemented in v1 "
|
|
658
|
+
"(only row_major)" % layout
|
|
659
|
+
)
|
|
660
|
+
quantization = _meta_text(map_value, "quantization")
|
|
661
|
+
if quantization != QUANTIZED_TENSOR_QUANTIZATION:
|
|
662
|
+
raise Malformed(
|
|
663
|
+
"quantized tensor quantization `%s` is specified but not implemented in v1"
|
|
664
|
+
% quantization
|
|
665
|
+
)
|
|
666
|
+
scale_bits = _meta_bytes(map_value, "scale_bits_le")
|
|
667
|
+
if len(scale_bits) != 8:
|
|
668
|
+
raise Malformed(
|
|
669
|
+
"quantized tensor scale_bits_le must be 8 bytes, got %d" % len(scale_bits)
|
|
670
|
+
)
|
|
671
|
+
scale = struct.unpack("<d", scale_bits)[0]
|
|
672
|
+
_validate_quantized_scale(scale)
|
|
673
|
+
zero_point = _meta_i64(map_value, "zero_point")
|
|
674
|
+
_validate_zero_point(dtype, zero_point)
|
|
675
|
+
shape = _meta_shape(map_value)
|
|
676
|
+
declared_count = _meta_u64(map_value, "element_count")
|
|
677
|
+
declared_bytes = _meta_u64(map_value, "payload_bytes")
|
|
678
|
+
expected_count = _tensor_product(shape, limits)
|
|
679
|
+
if declared_count != expected_count:
|
|
680
|
+
raise Malformed(
|
|
681
|
+
"quantized tensor element_count %d does not match shape product %d"
|
|
682
|
+
% (declared_count, expected_count)
|
|
683
|
+
)
|
|
684
|
+
if declared_bytes != declared_count:
|
|
685
|
+
raise Malformed(
|
|
686
|
+
"quantized tensor payload_bytes %d does not match element_count %d "
|
|
687
|
+
"for one-byte elements" % (declared_bytes, declared_count)
|
|
688
|
+
)
|
|
689
|
+
if declared_bytes != len(payload):
|
|
690
|
+
raise Malformed(
|
|
691
|
+
"quantized tensor payload is %d bytes but metadata declares %d"
|
|
692
|
+
% (len(payload), declared_bytes)
|
|
693
|
+
)
|
|
694
|
+
declared_hash = _meta_bytes(map_value, "payload_hash")
|
|
695
|
+
if len(declared_hash) != 32:
|
|
696
|
+
raise Malformed(
|
|
697
|
+
"quantized tensor payload_hash must be 32 bytes, got %d"
|
|
698
|
+
% len(declared_hash)
|
|
699
|
+
)
|
|
700
|
+
if declared_hash != hash_domain(DOMAIN_QUANTIZED_TENSOR_PAYLOAD, payload):
|
|
701
|
+
raise Corrupt("quantized tensor payload_hash mismatch")
|
|
702
|
+
meta = {
|
|
703
|
+
"schema": schema,
|
|
704
|
+
"dtype": dtype,
|
|
705
|
+
"shape": shape,
|
|
706
|
+
"layout": layout,
|
|
707
|
+
"quantization": quantization,
|
|
708
|
+
"scale": scale,
|
|
709
|
+
"zero_point": zero_point,
|
|
710
|
+
"element_count": declared_count,
|
|
711
|
+
"payload_bytes": declared_bytes,
|
|
712
|
+
}
|
|
713
|
+
return meta, payload
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def quantized_tensor_metadata(frame: Frame, limits: "Limits | None" = None) -> dict:
|
|
717
|
+
meta, _ = _parse_quantized_body(frame, limits or Limits())
|
|
718
|
+
return meta
|