Add --ternary flag to quantize.py; rewrite buffer gates as +/-1 weights
Browse filesquantize.py --ternary rewrites single-input weight=+/-2 identity buffers
(SHL/SHR/ROL/ROR bit gates, stack data buffers, RET address buffers,
flag buffers) as weight=+/-1 with bias adjusted to preserve the
heaviside output for binary inputs. H(2x - 1) and H(x - 1) are equal
on x in {0, 1}, so the rewrite is exact.
After the pass on the canonical 32-bit/64KB build, 174 buffer gates
become ternary; 183 weight tensors remain non-ternary, all positional
comparators (8/16-bit single-layer, byte-level cascade gates,
division-stage comparators) and a handful of hand-constructed modular
arithmetic gates. Fully ternarizing those requires bit-cascading them
in build.py rather than at quantization time.
The metadata field weight_quantization records 'ternary' (no
violations) or 'ternary_partial' (some remain). --strict makes the
quantizer fail when any weight is still non-ternary.
All 18 prebuilt variants and the canonical have been re-quantized with
--ternary. eval_all.py reports 100% fitness across all 18; the CPU
program suite still passes 7/7.
- README.md +4 -0
- neural_computer.safetensors +2 -2
- quantize.py +130 -8
- 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
|
@@ -249,10 +249,14 @@ The quantizer is also available standalone:
|
|
| 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 |
|
| 258 |
## Verification
|
|
|
|
| 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 |
+
python quantize.py file.safetensors --ternary # push toward {-1, 0, 1} weights
|
| 253 |
+
python quantize.py file.safetensors --ternary --strict # error if any weight is non-ternary
|
| 254 |
```
|
| 255 |
|
| 256 |
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.
|
| 257 |
|
| 258 |
+
**Ternary mode.** With `--ternary`, the quantizer also rewrites single-input `weight=±2` identity buffers (SHL/SHR/ROL/ROR bit gates, stack data buffers, RET address buffers, flag buffers) as `weight=±1` with bias adjusted to preserve the heaviside output for binary inputs (`H(2x - 1) ≡ H(x - 1)` etc.). After this pass the canonical model has 174 buffer gates rewritten and 183 weight tensors remaining non-ternary, all of which are positional comparators (8/16-bit single-layer, byte-level cascade gates, division-stage comparators) and a handful of hand-constructed modular arithmetic gates. Fully ternarizing those requires bit-cascading them in `build.py`, which is a structural change rather than a quantization pass. The metadata field `weight_quantization` records `ternary` (clean) or `ternary_partial` (some violations remain).
|
| 259 |
+
|
| 260 |
---
|
| 261 |
|
| 262 |
## Verification
|
|
@@ -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:e9c7424d5643c17ac22bee3930d85976e68b395ae45b146f2bb61318aff38c9f
|
| 3 |
+
size 21777962
|
|
@@ -12,11 +12,22 @@ 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
|
|
@@ -68,10 +79,74 @@ def _min_signed_int_dtype(tensor: torch.Tensor) -> torch.dtype:
|
|
| 68 |
return torch.int64
|
| 69 |
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
def quantize_tensors(
|
| 72 |
-
tensors: Dict[str, torch.Tensor]
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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}
|
|
@@ -101,10 +176,11 @@ def quantize_tensors(
|
|
| 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
|
|
|
|
| 108 |
file_before = in_path.stat().st_size
|
| 109 |
tensors: Dict[str, torch.Tensor] = {}
|
| 110 |
metadata: Dict[str, str] = {}
|
|
@@ -116,10 +192,36 @@ def quantize_file(in_path: Path, out_path: Path, verbose: bool = False) -> Dict:
|
|
| 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
|
|
@@ -131,6 +233,8 @@ def quantize_file(in_path: Path, out_path: Path, verbose: bool = False) -> Dict:
|
|
| 131 |
"tensor_bytes_after": after,
|
| 132 |
"file_size_before": file_before,
|
| 133 |
"file_size_after": file_after,
|
|
|
|
|
|
|
| 134 |
}
|
| 135 |
|
| 136 |
|
|
@@ -149,6 +253,11 @@ def _print_summary(label: str, info: Dict) -> None:
|
|
| 149 |
f"({ratio_t:.2f}x)"
|
| 150 |
)
|
| 151 |
print(f" {bucket_str}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
|
| 154 |
def main() -> int:
|
|
@@ -157,6 +266,13 @@ def main() -> int:
|
|
| 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 = []
|
|
@@ -185,10 +301,16 @@ def main() -> int:
|
|
| 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 |
|
|
|
|
| 12 |
pipeline already promotes weights to float32 on load, so integer
|
| 13 |
storage is exact.
|
| 14 |
|
| 15 |
+
The --ternary flag also rewrites single-input weight=+/-2 identity
|
| 16 |
+
buffers (SHL/SHR/ROL/ROR bit gates, stack data buffers, RET address
|
| 17 |
+
buffers, flag buffers) to weight=+/-1 with bias adjusted as needed to
|
| 18 |
+
preserve heaviside output for binary inputs. After this pass every
|
| 19 |
+
weight tensor in the file lies in {-1, 0, 1} except for positional
|
| 20 |
+
comparators and a few hand-constructed modular arithmetic circuits
|
| 21 |
+
(see the violation report); fully ternarizing those requires bit-
|
| 22 |
+
cascading in build.py.
|
| 23 |
+
|
| 24 |
Usage:
|
| 25 |
python quantize.py path/to/file.safetensors # in-place
|
| 26 |
python quantize.py path/to/file.safetensors -o out.safetensors # to new file
|
| 27 |
python quantize.py variants/ # whole directory in place
|
| 28 |
python quantize.py variants/ -o variants_int/ # whole directory to new dir
|
| 29 |
+
python quantize.py file.safetensors --ternary # try ternary weights
|
| 30 |
+
python quantize.py file.safetensors --ternary --strict # error if any weight non-ternary
|
| 31 |
"""
|
| 32 |
|
| 33 |
from __future__ import annotations
|
|
|
|
| 79 |
return torch.int64
|
| 80 |
|
| 81 |
|
| 82 |
+
def _ternarize_buffers(
|
| 83 |
+
tensors: Dict[str, torch.Tensor],
|
| 84 |
+
) -> Tuple[Dict[str, torch.Tensor], Dict]:
|
| 85 |
+
"""Rewrite single-input weight=+-2 identity buffers as weight=+-1 with
|
| 86 |
+
bias adjusted to preserve heaviside output for binary inputs.
|
| 87 |
+
|
| 88 |
+
For a single-input gate H(w*x + b) with x in {0, 1}, the only thing
|
| 89 |
+
that matters is the pair (H(b), H(w + b)). Pick the smallest integer
|
| 90 |
+
bias b' such that (H(b'), H(sgn + b')) matches, with sgn = sign(w).
|
| 91 |
+
|
| 92 |
+
Returns (new_tensors, stats). stats has 'fixed', 'failed', 'failed_names'.
|
| 93 |
+
"""
|
| 94 |
+
new_tensors = dict(tensors)
|
| 95 |
+
fixed = 0
|
| 96 |
+
failed_names = []
|
| 97 |
+
|
| 98 |
+
weight_keys = [k for k in tensors if k.endswith(".weight")]
|
| 99 |
+
for wkey in weight_keys:
|
| 100 |
+
w = tensors[wkey]
|
| 101 |
+
wf = w.float() if w.dtype.is_floating_point else w.to(torch.float64).float()
|
| 102 |
+
if (wf.abs() <= 1.0).all():
|
| 103 |
+
continue # already ternary
|
| 104 |
+
|
| 105 |
+
gate = wkey[: -len(".weight")]
|
| 106 |
+
bkey = gate + ".bias"
|
| 107 |
+
|
| 108 |
+
# Single-input weight=+-2 buffer with single bias
|
| 109 |
+
if (
|
| 110 |
+
wf.numel() == 1
|
| 111 |
+
and abs(wf.item()) == 2.0
|
| 112 |
+
and bkey in tensors
|
| 113 |
+
and tensors[bkey].numel() == 1
|
| 114 |
+
):
|
| 115 |
+
w_val = wf.item()
|
| 116 |
+
b_val = float(tensors[bkey].float().item())
|
| 117 |
+
sgn = 1.0 if w_val > 0 else -1.0
|
| 118 |
+
x0_target = 1 if b_val >= 0 else 0
|
| 119 |
+
x1_target = 1 if (w_val + b_val) >= 0 else 0
|
| 120 |
+
chosen = None
|
| 121 |
+
# Prefer keeping the bias unchanged when possible
|
| 122 |
+
for b_new in [int(b_val), int(b_val) - 1, -1, 0, -2, 1, -3, 2]:
|
| 123 |
+
x0 = 1 if b_new >= 0 else 0
|
| 124 |
+
x1 = 1 if (sgn + b_new) >= 0 else 0
|
| 125 |
+
if x0 == x0_target and x1 == x1_target:
|
| 126 |
+
chosen = b_new
|
| 127 |
+
break
|
| 128 |
+
if chosen is not None:
|
| 129 |
+
new_tensors[wkey] = torch.tensor([sgn], dtype=torch.float64)
|
| 130 |
+
new_tensors[bkey] = torch.tensor([float(chosen)], dtype=torch.float64)
|
| 131 |
+
fixed += 1
|
| 132 |
+
continue
|
| 133 |
+
|
| 134 |
+
failed_names.append(wkey)
|
| 135 |
+
|
| 136 |
+
return new_tensors, {"fixed": fixed, "failed_names": failed_names}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
def quantize_tensors(
|
| 140 |
+
tensors: Dict[str, torch.Tensor],
|
| 141 |
+
ternary: bool = False,
|
| 142 |
+
) -> Tuple[Dict[str, torch.Tensor], Dict[str, int], Tuple[int, int], Dict]:
|
| 143 |
+
"""Quantize a dict of tensors. Returns
|
| 144 |
+
(new_tensors, dtype_counts, (bytes_before, bytes_after), ternary_stats)."""
|
| 145 |
+
ternary_stats: Dict = {"applied": False, "fixed": 0, "failed_names": []}
|
| 146 |
+
if ternary:
|
| 147 |
+
tensors, ternary_stats = _ternarize_buffers(tensors)
|
| 148 |
+
ternary_stats["applied"] = True
|
| 149 |
+
|
| 150 |
new_tensors: Dict[str, torch.Tensor] = {}
|
| 151 |
counts: Dict[str, int] = {"int8": 0, "int16": 0, "int32": 0, "int64": 0,
|
| 152 |
"manifest_kept": 0, "skipped": 0}
|
|
|
|
| 176 |
bytes_after += cast.numel() * cast.element_size()
|
| 177 |
counts[str(target).replace("torch.", "")] += 1
|
| 178 |
|
| 179 |
+
return new_tensors, counts, (bytes_before, bytes_after), ternary_stats
|
| 180 |
|
| 181 |
|
| 182 |
+
def quantize_file(in_path: Path, out_path: Path, verbose: bool = False,
|
| 183 |
+
ternary: bool = False, strict_ternary: bool = False) -> Dict:
|
| 184 |
file_before = in_path.stat().st_size
|
| 185 |
tensors: Dict[str, torch.Tensor] = {}
|
| 186 |
metadata: Dict[str, str] = {}
|
|
|
|
| 192 |
# clone so the source mmap can be released before we write
|
| 193 |
tensors[name] = f.get_tensor(name).clone()
|
| 194 |
|
| 195 |
+
new_tensors, counts, (before, after), tstats = quantize_tensors(tensors, ternary=ternary)
|
| 196 |
+
|
| 197 |
+
# Audit final ternary status (count of weight tensors with |w| > 1)
|
| 198 |
+
final_nonternary = []
|
| 199 |
+
for k, v in new_tensors.items():
|
| 200 |
+
if not k.endswith(".weight"):
|
| 201 |
+
continue
|
| 202 |
+
if k.startswith("manifest."):
|
| 203 |
+
continue
|
| 204 |
+
vf = v.float() if v.dtype.is_floating_point else v.to(torch.float64).float()
|
| 205 |
+
if (vf.abs() > 1.0).any():
|
| 206 |
+
final_nonternary.append(k)
|
| 207 |
+
|
| 208 |
+
if ternary and strict_ternary and final_nonternary:
|
| 209 |
+
raise ValueError(
|
| 210 |
+
f"--strict failed: {len(final_nonternary)} weight tensors are not "
|
| 211 |
+
f"ternary after transformation; first: {final_nonternary[:5]}"
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
# Drop the original mmap-backed tensors before writing in-place.
|
| 215 |
del tensors
|
| 216 |
out_path.parent.mkdir(parents=True, exist_ok=True)
|
| 217 |
+
if ternary:
|
| 218 |
+
# Note ternary mode in metadata so downstream tools can see it
|
| 219 |
+
if metadata is None:
|
| 220 |
+
metadata = {}
|
| 221 |
+
metadata = dict(metadata)
|
| 222 |
+
metadata["weight_quantization"] = (
|
| 223 |
+
"ternary_partial" if final_nonternary else "ternary"
|
| 224 |
+
)
|
| 225 |
save_file(new_tensors, str(out_path), metadata=metadata or None)
|
| 226 |
|
| 227 |
file_after = out_path.stat().st_size
|
|
|
|
| 233 |
"tensor_bytes_after": after,
|
| 234 |
"file_size_before": file_before,
|
| 235 |
"file_size_after": file_after,
|
| 236 |
+
"ternary": tstats,
|
| 237 |
+
"final_nonternary": final_nonternary,
|
| 238 |
}
|
| 239 |
|
| 240 |
|
|
|
|
| 253 |
f"({ratio_t:.2f}x)"
|
| 254 |
)
|
| 255 |
print(f" {bucket_str}")
|
| 256 |
+
if info.get("ternary", {}).get("applied"):
|
| 257 |
+
ts = info["ternary"]
|
| 258 |
+
nt = info["final_nonternary"]
|
| 259 |
+
print(f" ternary: {ts['fixed']} buffer gates rewritten; "
|
| 260 |
+
f"{len(nt)} weight tensors remain non-ternary")
|
| 261 |
|
| 262 |
|
| 263 |
def main() -> int:
|
|
|
|
| 266 |
parser.add_argument("-o", "--output", type=Path, default=None,
|
| 267 |
help="output file or directory (default: in-place)")
|
| 268 |
parser.add_argument("-v", "--verbose", action="store_true")
|
| 269 |
+
parser.add_argument("--ternary", action="store_true",
|
| 270 |
+
help="Rewrite single-input weight=+/-2 buffers as +/-1 to push toward "
|
| 271 |
+
"ternary {-1, 0, 1} weights and report remaining violations")
|
| 272 |
+
parser.add_argument("--strict", action="store_true",
|
| 273 |
+
help="With --ternary, fail if any weight tensor is still non-ternary")
|
| 274 |
+
parser.add_argument("--report-violations", type=int, default=0, metavar="N",
|
| 275 |
+
help="Print first N non-ternary weight tensor names per file")
|
| 276 |
args = parser.parse_args()
|
| 277 |
|
| 278 |
inputs = []
|
|
|
|
| 301 |
|
| 302 |
total_before = 0
|
| 303 |
total_after = 0
|
| 304 |
+
print(f"Quantizing {len(inputs)} file(s)" + (" (ternary mode)" if args.ternary else "") + "\n")
|
| 305 |
for src, dst in zip(inputs, outputs):
|
| 306 |
+
info = quantize_file(src, dst, verbose=args.verbose,
|
| 307 |
+
ternary=args.ternary, strict_ternary=args.strict)
|
| 308 |
_print_summary(src.name, info)
|
| 309 |
+
if args.report_violations and info.get("final_nonternary"):
|
| 310 |
+
for name in info["final_nonternary"][: args.report_violations]:
|
| 311 |
+
print(f" non-ternary: {name}")
|
| 312 |
+
if len(info["final_nonternary"]) > args.report_violations:
|
| 313 |
+
print(f" ... and {len(info['final_nonternary']) - args.report_violations} more")
|
| 314 |
total_before += info["file_size_before"]
|
| 315 |
total_after += info["file_size_after"]
|
| 316 |
|
|
@@ -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:493f6f679b78e0d3d15a187dcd9a733b9bd8f51b8c5f4065ff68d3ea2aa351f6
|
| 3 |
+
size 11474021
|
|
@@ -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:a5907e430443b0deb48aa666b15da6ac6e57006367868282aac6dcbe19d28bde
|
| 3 |
+
size 13258660
|
|
@@ -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:136684d2ebdd3f54c73dccc2794e7e09bc265c670a0660ba03093a1386478582
|
| 3 |
+
size 10688501
|
|
@@ -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:9d9ccd2154b44ece7b39ed37c03149ab38f7d840c24d3296c8b427e1217ae2f3
|
| 3 |
+
size 19974899
|
|
@@ -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:5dc5fcb06f90d70173d26556f7ab8105f55c0f8be479f742a1c4d12668cc8116
|
| 3 |
+
size 12163635
|
|
@@ -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:254c05ec2b2e9aac83eb1944d711db20202f26baa5291a5e9bd020e1ed3c713c
|
| 3 |
+
size 11560795
|
|
@@ -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:370b35f3b1c4a290bfbb64fdfce824259348def722decfaf7f22816f0d3fcc68
|
| 3 |
+
size 11641499
|
|
@@ -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:bc54a3aa13383f738e6f2109b96df9cfa7e6bd6869d5c5aa08422c3af523e383
|
| 3 |
+
size 11760339
|
|
@@ -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:313594c493c124733f70b81a73813eb7e242143df2dc3c9b800fa7f1de57dc3b
|
| 3 |
+
size 21777962
|
|
@@ -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:836ea61f879ead37a5274edb0346ad50af92b99451555a4cc94c11bf65c237bf
|
| 3 |
+
size 13966690
|
|
@@ -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:e6443f13914c22775003fda952bad6bec7638efadde620e4e094c66d2268e72f
|
| 3 |
+
size 13363858
|
|
@@ -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:f24b2425ee50bf65746714ece769b0ddca32f13c29641a2350c9686a4c187289
|
| 3 |
+
size 13444554
|
|
@@ -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:6d037affb4b59c0c2f0c8814fe2fc75b78e2508068b520c01714e0e4f82447ca
|
| 3 |
+
size 13563410
|
|
@@ -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:4c25ab253d41866fd627a63bb1d6350c5869f4f6f86dd04e3773fab63595d277
|
| 3 |
+
size 19180203
|
|
@@ -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:ea0532e900fad00d62c3c01f9ee8a820f0504e71857c18c4b743499f02b3b1b3
|
| 3 |
+
size 11368939
|
|
@@ -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:e0f47640d477e167094e90647fdbcb2b9d5b63337f3394b3b5cd0e94229496c9
|
| 3 |
+
size 10766099
|
|
@@ -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:fd4d75e83a351b2609c3bc65cd90668228f490ea83c9fb93d86c9b6fbde5ab72
|
| 3 |
+
size 10846803
|
|
@@ -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:eaba41825a68678021fafeced6c21b49b602117ae091ea91744190c2301e8088
|
| 3 |
+
size 10965643
|