Quantize weights to per-tensor minimum signed integer dtype
Browse filesquantize.py loads a safetensors file (or a directory of them), normalizes
half-integer biases (e.g. arithmetic.asr8bit.bit*.bias = -0.5 floors to -1
without changing H semantics for binary inputs), and casts each tensor to
the smallest signed integer dtype that exactly represents its values.
Distribution of dtypes in a typical full build: ~71% of tensors fit int8
(weights of magnitude <= 1 or 2, biases up to about -16), ~29% need int16
(byte-level comparator weights of +-128 and the 16-bit single-layer
comparator), and a handful of wide single-layer comparators in the float
and 32-bit-divisor circuits stay at int32 or int64.
Tensor data shrinks 4x (34 MB -> 8.6 MB on the canonical 64KB build).
Total file size drops more modestly because the safetensors header is a
fixed-cost JSON entry per tensor; the smaller variants are header-bound.
Across the 18 prebuilt variants total disk drops from 340 MB to 242 MB.
The eval pipeline already calls .float() on load, so integer storage is
exact and transparent. All 18 quantized variants pass eval_all.py at
100% fitness; the CPU program suite still passes 7/7.
build_all.py runs quantize as a standard post-build step.
- README.md +13 -2
- build_all.py +24 -1
- neural_computer.safetensors +2 -2
- quantize.py +205 -0
- variants/neural_alu16.safetensors +2 -2
- variants/neural_alu32.safetensors +2 -2
- variants/neural_alu8.safetensors +2 -2
- variants/neural_computer16.safetensors +2 -2
- variants/neural_computer16_reduced.safetensors +2 -2
- variants/neural_computer16_registers.safetensors +2 -2
- variants/neural_computer16_scratchpad.safetensors +2 -2
- variants/neural_computer16_small.safetensors +2 -2
- variants/neural_computer32.safetensors +2 -2
- variants/neural_computer32_reduced.safetensors +2 -2
- variants/neural_computer32_registers.safetensors +2 -2
- variants/neural_computer32_scratchpad.safetensors +2 -2
- variants/neural_computer32_small.safetensors +2 -2
- variants/neural_computer8.safetensors +2 -2
- variants/neural_computer8_reduced.safetensors +2 -2
- variants/neural_computer8_registers.safetensors +2 -2
- variants/neural_computer8_scratchpad.safetensors +2 -2
- variants/neural_computer8_small.safetensors +2 -2
|
@@ -241,7 +241,17 @@ To regenerate every named variant in one pass:
|
|
| 241 |
python build_all.py
|
| 242 |
```
|
| 243 |
|
| 244 |
-
This populates `variants/` with all 18 builds and runs `eval.py` on each as a sanity check.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
---
|
| 247 |
|
|
@@ -437,7 +447,8 @@ Loss components: BCE on output bits, BCE on extracted A and B bits (2× weight),
|
|
| 437 |
neural_computer.safetensors canonical model (32-bit, 64 KB, ~8.47M params)
|
| 438 |
variants/ 18 prebuilt configurations
|
| 439 |
build.py generator (one safetensors per invocation)
|
| 440 |
-
build_all.py builds and verifies every named profile
|
|
|
|
| 441 |
eval.py gate-level fitness suite + reference CPU runtime
|
| 442 |
eval_all.py variant-agnostic gate-level harness
|
| 443 |
cpu_programs.py assembler + program suite for CPU-level validation
|
|
|
|
| 241 |
python build_all.py
|
| 242 |
```
|
| 243 |
|
| 244 |
+
This populates `variants/` with all 18 builds, quantizes each one to the smallest signed integer dtype that exactly represents its weights (~4× reduction in tensor data, with file size dominated by the safetensors header on the smaller profiles), and runs `eval.py` on each as a sanity check.
|
| 245 |
+
|
| 246 |
+
The quantizer is also available standalone:
|
| 247 |
+
|
| 248 |
+
```bash
|
| 249 |
+
python quantize.py path/to/file.safetensors # in-place
|
| 250 |
+
python quantize.py variants/ # whole directory
|
| 251 |
+
python quantize.py model.safetensors -o quantized.safetensors
|
| 252 |
+
```
|
| 253 |
+
|
| 254 |
+
Most tensors fit in `int8`; comparator weights and a few wide single-layer threshold gates use `int16` or `int32`. The eval pipeline promotes weights to `float32` on load, so integer storage is exact and transparent.
|
| 255 |
|
| 256 |
---
|
| 257 |
|
|
|
|
| 447 |
neural_computer.safetensors canonical model (32-bit, 64 KB, ~8.47M params)
|
| 448 |
variants/ 18 prebuilt configurations
|
| 449 |
build.py generator (one safetensors per invocation)
|
| 450 |
+
build_all.py builds, quantizes, and verifies every named profile
|
| 451 |
+
quantize.py casts each tensor to its minimum signed integer dtype
|
| 452 |
eval.py gate-level fitness suite + reference CPU runtime
|
| 453 |
eval_all.py variant-agnostic gate-level harness
|
| 454 |
cpu_programs.py assembler + program suite for CPU-level validation
|
|
@@ -63,6 +63,24 @@ def build_variant(bits: int, profile: str) -> Path:
|
|
| 63 |
return out
|
| 64 |
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
def measure_variant(path: Path) -> dict:
|
| 67 |
"""Read tensor count, params, manifest values from the variant."""
|
| 68 |
with safe_open(str(path), framework="pt") as f:
|
|
@@ -130,6 +148,9 @@ def main() -> None:
|
|
| 130 |
try:
|
| 131 |
path = build_variant(bits, profile)
|
| 132 |
bt = time.time() - t0
|
|
|
|
|
|
|
|
|
|
| 133 |
meta = measure_variant(path)
|
| 134 |
ev = eval_variant(path, device="cpu", timeout=900)
|
| 135 |
rows.append({
|
|
@@ -140,7 +161,9 @@ def main() -> None:
|
|
| 140 |
**{k: ev[k] for k in ("fitness", "total_tests", "status", "elapsed_s")},
|
| 141 |
"log_tail": ev["log_tail"] if ev["status"] != "PASS" else "",
|
| 142 |
})
|
| 143 |
-
|
|
|
|
|
|
|
| 144 |
f" params={meta['params']:,} tensors={meta['tensors']:,}")
|
| 145 |
print(f" eval: fitness={ev['fitness']} tests={ev['total_tests']}"
|
| 146 |
f" status={ev['status']} ({ev['elapsed_s']:.1f}s)")
|
|
|
|
| 63 |
return out
|
| 64 |
|
| 65 |
|
| 66 |
+
def quantize_variant(path: Path) -> tuple[int, int]:
|
| 67 |
+
"""Run quantize.py on a built variant. Returns (bytes_before, bytes_after)."""
|
| 68 |
+
rc, log = run([sys.executable, str(ROOT / "quantize.py"), str(path)], timeout=300)
|
| 69 |
+
if rc != 0:
|
| 70 |
+
raise RuntimeError(f"quantize failed for {path.name}:\n{log[-800:]}")
|
| 71 |
+
# parse the "file X.X MB -> Y.Y MB" line
|
| 72 |
+
for line in log.splitlines():
|
| 73 |
+
if "file" in line and "->" in line and path.name in line:
|
| 74 |
+
try:
|
| 75 |
+
parts = line.split("file")[1].split("->")
|
| 76 |
+
before = float(parts[0].strip().split()[0]) * 1e6
|
| 77 |
+
after = float(parts[1].strip().split()[0]) * 1e6
|
| 78 |
+
return int(before), int(after)
|
| 79 |
+
except Exception:
|
| 80 |
+
pass
|
| 81 |
+
return 0, 0
|
| 82 |
+
|
| 83 |
+
|
| 84 |
def measure_variant(path: Path) -> dict:
|
| 85 |
"""Read tensor count, params, manifest values from the variant."""
|
| 86 |
with safe_open(str(path), framework="pt") as f:
|
|
|
|
| 148 |
try:
|
| 149 |
path = build_variant(bits, profile)
|
| 150 |
bt = time.time() - t0
|
| 151 |
+
pre_q_meta = measure_variant(path)
|
| 152 |
+
# Quantize in-place; weights are integer-valued so this is exact.
|
| 153 |
+
qb, qa = quantize_variant(path)
|
| 154 |
meta = measure_variant(path)
|
| 155 |
ev = eval_variant(path, device="cpu", timeout=900)
|
| 156 |
rows.append({
|
|
|
|
| 161 |
**{k: ev[k] for k in ("fitness", "total_tests", "status", "elapsed_s")},
|
| 162 |
"log_tail": ev["log_tail"] if ev["status"] != "PASS" else "",
|
| 163 |
})
|
| 164 |
+
q_ratio = qb / qa if qa else 1.0
|
| 165 |
+
print(f" built in {bt:.1f}s size={pre_q_meta['size_mb']:.1f}MB -> "
|
| 166 |
+
f"{meta['size_mb']:.1f}MB after quant ({q_ratio:.2f}x)"
|
| 167 |
f" params={meta['params']:,} tensors={meta['tensors']:,}")
|
| 168 |
print(f" eval: fitness={ev['fitness']} tests={ev['total_tests']}"
|
| 169 |
f" status={ev['status']} ({ev['elapsed_s']:.1f}s)")
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c87e96ed650bf30fd25350714a75b9bdc84651077774b2900b69b9cf647a0748
|
| 3 |
+
size 21777922
|
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Quantize threshold-computer safetensors to the minimum signed integer
|
| 3 |
+
dtype that exactly represents each tensor.
|
| 4 |
+
|
| 5 |
+
Weights and biases in this library are integer-valued by construction,
|
| 6 |
+
with one historical exception: a handful of legacy buffer gates use a
|
| 7 |
+
bias of -0.5 (e.g. arithmetic.asr8bit.bit*.bias). For binary inputs,
|
| 8 |
+
H(x - 0.5) and H(x - 1) are identical, so those biases are floored to
|
| 9 |
+
-1 before casting.
|
| 10 |
+
|
| 11 |
+
This is a packaging optimization, not a precision change: the eval
|
| 12 |
+
pipeline already promotes weights to float32 on load, so integer
|
| 13 |
+
storage is exact.
|
| 14 |
+
|
| 15 |
+
Usage:
|
| 16 |
+
python quantize.py path/to/file.safetensors # in-place
|
| 17 |
+
python quantize.py path/to/file.safetensors -o out.safetensors # to new file
|
| 18 |
+
python quantize.py variants/ # whole directory in place
|
| 19 |
+
python quantize.py variants/ -o variants_int/ # whole directory to new dir
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
from __future__ import annotations
|
| 23 |
+
|
| 24 |
+
import argparse
|
| 25 |
+
import sys
|
| 26 |
+
from pathlib import Path
|
| 27 |
+
from typing import Dict, Tuple
|
| 28 |
+
|
| 29 |
+
import torch
|
| 30 |
+
from safetensors import safe_open
|
| 31 |
+
from safetensors.torch import save_file
|
| 32 |
+
|
| 33 |
+
DTYPES = [
|
| 34 |
+
(torch.int8, -(1 << 7), (1 << 7) - 1),
|
| 35 |
+
(torch.int16, -(1 << 15), (1 << 15) - 1),
|
| 36 |
+
(torch.int32, -(1 << 31), (1 << 31) - 1),
|
| 37 |
+
(torch.int64, None, None), # always fits
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def _normalize_to_int(tensor: torch.Tensor) -> torch.Tensor:
|
| 42 |
+
"""Return a tensor with strictly integer values, floored from any
|
| 43 |
+
half-integer values. Floor (not round) because a -0.5 bias must
|
| 44 |
+
become -1 (not 0) to preserve H(x + bias) for binary x."""
|
| 45 |
+
if not tensor.dtype.is_floating_point:
|
| 46 |
+
return tensor.to(torch.float64) # promote for range checks
|
| 47 |
+
tf = tensor.to(torch.float64)
|
| 48 |
+
rounded = tf.round()
|
| 49 |
+
if torch.equal(rounded, tf):
|
| 50 |
+
return tf
|
| 51 |
+
doubled = tf * 2.0
|
| 52 |
+
if torch.equal(doubled.round(), doubled):
|
| 53 |
+
return torch.floor(tf)
|
| 54 |
+
raise ValueError(
|
| 55 |
+
f"tensor has non-half-integer values; range "
|
| 56 |
+
f"[{tf.min().item()}, {tf.max().item()}]"
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def _min_signed_int_dtype(tensor: torch.Tensor) -> torch.dtype:
|
| 61 |
+
if tensor.numel() == 0:
|
| 62 |
+
return torch.int8
|
| 63 |
+
lo = int(tensor.min().item())
|
| 64 |
+
hi = int(tensor.max().item())
|
| 65 |
+
for dtype, lo_lim, hi_lim in DTYPES:
|
| 66 |
+
if lo_lim is None or (lo_lim <= lo and hi <= hi_lim):
|
| 67 |
+
return dtype
|
| 68 |
+
return torch.int64
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def quantize_tensors(
|
| 72 |
+
tensors: Dict[str, torch.Tensor]
|
| 73 |
+
) -> Tuple[Dict[str, torch.Tensor], Dict[str, int], Tuple[int, int]]:
|
| 74 |
+
"""Quantize a dict of tensors. Returns (new_tensors, dtype_counts, (bytes_before, bytes_after))."""
|
| 75 |
+
new_tensors: Dict[str, torch.Tensor] = {}
|
| 76 |
+
counts: Dict[str, int] = {"int8": 0, "int16": 0, "int32": 0, "int64": 0,
|
| 77 |
+
"manifest_kept": 0, "skipped": 0}
|
| 78 |
+
bytes_before = 0
|
| 79 |
+
bytes_after = 0
|
| 80 |
+
|
| 81 |
+
for name, t in tensors.items():
|
| 82 |
+
bytes_before += t.numel() * t.element_size()
|
| 83 |
+
|
| 84 |
+
if name.startswith("manifest."):
|
| 85 |
+
new_tensors[name] = t
|
| 86 |
+
counts["manifest_kept"] += 1
|
| 87 |
+
bytes_after += t.numel() * t.element_size()
|
| 88 |
+
continue
|
| 89 |
+
|
| 90 |
+
try:
|
| 91 |
+
normalized = _normalize_to_int(t)
|
| 92 |
+
except ValueError:
|
| 93 |
+
new_tensors[name] = t
|
| 94 |
+
counts["skipped"] += 1
|
| 95 |
+
bytes_after += t.numel() * t.element_size()
|
| 96 |
+
continue
|
| 97 |
+
|
| 98 |
+
target = _min_signed_int_dtype(normalized)
|
| 99 |
+
cast = normalized.to(target)
|
| 100 |
+
new_tensors[name] = cast
|
| 101 |
+
bytes_after += cast.numel() * cast.element_size()
|
| 102 |
+
counts[str(target).replace("torch.", "")] += 1
|
| 103 |
+
|
| 104 |
+
return new_tensors, counts, (bytes_before, bytes_after)
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def quantize_file(in_path: Path, out_path: Path, verbose: bool = False) -> Dict:
|
| 108 |
+
file_before = in_path.stat().st_size
|
| 109 |
+
tensors: Dict[str, torch.Tensor] = {}
|
| 110 |
+
metadata: Dict[str, str] = {}
|
| 111 |
+
with safe_open(str(in_path), framework="pt") as f:
|
| 112 |
+
meta = f.metadata()
|
| 113 |
+
if meta:
|
| 114 |
+
metadata = dict(meta)
|
| 115 |
+
for name in f.keys():
|
| 116 |
+
# clone so the source mmap can be released before we write
|
| 117 |
+
tensors[name] = f.get_tensor(name).clone()
|
| 118 |
+
|
| 119 |
+
new_tensors, counts, (before, after) = quantize_tensors(tensors)
|
| 120 |
+
# Drop the original mmap-backed tensors before writing in-place.
|
| 121 |
+
del tensors
|
| 122 |
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 123 |
+
save_file(new_tensors, str(out_path), metadata=metadata or None)
|
| 124 |
+
|
| 125 |
+
file_after = out_path.stat().st_size
|
| 126 |
+
return {
|
| 127 |
+
"in_path": str(in_path),
|
| 128 |
+
"out_path": str(out_path),
|
| 129 |
+
"tensor_counts": counts,
|
| 130 |
+
"tensor_bytes_before": before,
|
| 131 |
+
"tensor_bytes_after": after,
|
| 132 |
+
"file_size_before": file_before,
|
| 133 |
+
"file_size_after": file_after,
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def _print_summary(label: str, info: Dict) -> None:
|
| 138 |
+
cb = info["tensor_bytes_before"]
|
| 139 |
+
ca = info["tensor_bytes_after"]
|
| 140 |
+
fb = info["file_size_before"]
|
| 141 |
+
fa = info["file_size_after"]
|
| 142 |
+
counts = info["tensor_counts"]
|
| 143 |
+
bucket_str = " ".join(f"{k}={v}" for k, v in counts.items() if v)
|
| 144 |
+
ratio_t = cb / ca if ca else 1.0
|
| 145 |
+
ratio_f = fb / fa if fa else 1.0
|
| 146 |
+
print(
|
| 147 |
+
f" {label}: file {fb / 1e6:6.1f} MB -> {fa / 1e6:6.1f} MB "
|
| 148 |
+
f"({ratio_f:.2f}x); tensor data {cb / 1e6:6.1f} MB -> {ca / 1e6:6.1f} MB "
|
| 149 |
+
f"({ratio_t:.2f}x)"
|
| 150 |
+
)
|
| 151 |
+
print(f" {bucket_str}")
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def main() -> int:
|
| 155 |
+
parser = argparse.ArgumentParser(description="Quantize safetensors to min signed int dtype")
|
| 156 |
+
parser.add_argument("input", type=Path, help=".safetensors file or directory of files")
|
| 157 |
+
parser.add_argument("-o", "--output", type=Path, default=None,
|
| 158 |
+
help="output file or directory (default: in-place)")
|
| 159 |
+
parser.add_argument("-v", "--verbose", action="store_true")
|
| 160 |
+
args = parser.parse_args()
|
| 161 |
+
|
| 162 |
+
inputs = []
|
| 163 |
+
if args.input.is_dir():
|
| 164 |
+
inputs = sorted(p for p in args.input.glob("*.safetensors"))
|
| 165 |
+
elif args.input.is_file():
|
| 166 |
+
inputs = [args.input]
|
| 167 |
+
else:
|
| 168 |
+
print(f"not found: {args.input}", file=sys.stderr)
|
| 169 |
+
return 2
|
| 170 |
+
|
| 171 |
+
if not inputs:
|
| 172 |
+
print(f"no .safetensors files under {args.input}", file=sys.stderr)
|
| 173 |
+
return 2
|
| 174 |
+
|
| 175 |
+
if args.output is None:
|
| 176 |
+
outputs = inputs # in-place
|
| 177 |
+
elif args.output.suffix == ".safetensors":
|
| 178 |
+
if len(inputs) != 1:
|
| 179 |
+
print("output is a single file but input is a directory; pass a directory output", file=sys.stderr)
|
| 180 |
+
return 2
|
| 181 |
+
outputs = [args.output]
|
| 182 |
+
else:
|
| 183 |
+
args.output.mkdir(parents=True, exist_ok=True)
|
| 184 |
+
outputs = [args.output / p.name for p in inputs]
|
| 185 |
+
|
| 186 |
+
total_before = 0
|
| 187 |
+
total_after = 0
|
| 188 |
+
print(f"Quantizing {len(inputs)} file(s)\n")
|
| 189 |
+
for src, dst in zip(inputs, outputs):
|
| 190 |
+
info = quantize_file(src, dst, verbose=args.verbose)
|
| 191 |
+
_print_summary(src.name, info)
|
| 192 |
+
total_before += info["file_size_before"]
|
| 193 |
+
total_after += info["file_size_after"]
|
| 194 |
+
|
| 195 |
+
print()
|
| 196 |
+
print("=" * 76)
|
| 197 |
+
print(
|
| 198 |
+
f"Total: {total_before / 1e6:.1f} MB -> {total_after / 1e6:.1f} MB "
|
| 199 |
+
f"({total_before / max(total_after, 1):.2f}x reduction)"
|
| 200 |
+
)
|
| 201 |
+
return 0
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
if __name__ == "__main__":
|
| 205 |
+
sys.exit(main())
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:424b192a426ea3ccb96d753dcebc032814e01e3d0b15ae8633d832608bdcf7ef
|
| 3 |
+
size 11473981
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aa26c2943200c5ed07358bf0cff09da1ecf9f3058786681790458b829a95e663
|
| 3 |
+
size 13258620
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:706d0c80f76613b0a9c72f5e3f8bc526bf5d638e9f0e73dd046b769db0d37cf7
|
| 3 |
+
size 10688461
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9debd616a7493699a87fe6640ac9a9cc15c4658eae2b167fb8d6e10c61668b27
|
| 3 |
+
size 19974859
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4e52801828ef7434aa24fe039aa8ef0b4d739efe93fc32235d59a0e8b8fc0d58
|
| 3 |
+
size 12163595
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b4f76c0b906a0beeb27b4ecae262690c53a7ad61c48bd5bb18cd3a531435ae73
|
| 3 |
+
size 11560755
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:12ef91ad2cb1490a96563ff3cc103b0bf92641bc19d987bfd66539a26c6a75c1
|
| 3 |
+
size 11641459
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7d6f48f1c10f67c9292be41ea575e4ce1302d0e0fd16c8e9071dfb19d204ea1c
|
| 3 |
+
size 11760299
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c87e96ed650bf30fd25350714a75b9bdc84651077774b2900b69b9cf647a0748
|
| 3 |
+
size 21777922
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5569a85aa93c0f7e2ffd67e9ccb5cfb5cdea9b8b881780e1c2d8566f1aef6455
|
| 3 |
+
size 13966650
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9d5adaf93705e72be7ceb91fe241a7a4c5d0e456b93322022a8e5697c2838828
|
| 3 |
+
size 13363818
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5b6713adeab730ba5f605507a6e65320bc71d221146d57da4af8faa29c807d5e
|
| 3 |
+
size 13444514
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:57d3c29a466a38c9f03e60d223b5f1c4543dd6a2c0b9607183952bfd0a283b21
|
| 3 |
+
size 13563370
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a225796853866f88d04d1568a81324526a53b6eda6c373cef101f99a3cae162f
|
| 3 |
+
size 19180163
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:10b2a79f5347593bc1c6d8a850308b0e6f37e316427ea546ff77aa1ccc6a8118
|
| 3 |
+
size 11368899
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4715734c39b883d6af2ddbcbd848df11e39e4e3fab9913b91afaf8709b8ac88c
|
| 3 |
+
size 10766059
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8d32afb2aed1fa557d1579b9be351fbfd4d7eab8370a26d5181359dfbd75ab64
|
| 3 |
+
size 10846763
|
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5374476d6c8fed45da1249488865b3ec03ae76289272a1eb28c30d6855001f71
|
| 3 |
+
size 10965603
|