Author SHA1 Message Date
Philipp Emanuel Weidmann dc1a569470 chore: add yet more CI test hashes 2026-10-02 14:34:32 +05:30
Philipp Emanuel Weidmann ab775193b8 chore: add new CI test hashes 2026-10-02 14:23:08 +05:30
Philipp Emanuel Weidmann 8cac604223 chore: update dependencies 2026-10-02 14:00:50 +05:30
662e4ba27e feat: modifier plugins + ARA (#446)
* feat: add modifier base class

* feat: re-implement abliteration as a modifier plugin

* fix: adjust good/bad prompts hack to match tests

* feat: support dataset specifications containing multiple individual datasets

* feat: re-implement ARA as a modifier plugin

Arbitrary-Rank Ablation (ARA) (Weidmann 2026) was originally introduced by @p-e-w in #211

Co-authored-by: kabachuha <artemkhrapov2001@yandex.ru>
Co-authored-by: joninco <joninco@bullpoint.org>
Co-authored-by: Ashar <coder3101@users.noreply.github.com>

* feat: add tests for ARA

* feat: reduce default number of trials

* ci: remove broken "semantic-pull-request" workflow

* ci: add yet another alternative model hash

---------

Co-authored-by: kabachuha <artemkhrapov2001@yandex.ru>
Co-authored-by: joninco <joninco@bullpoint.org>
Co-authored-by: Ashar <coder3101@users.noreply.github.com>
2026-10-01 14:30:07 +05:30
33 changed files with 3102 additions and 2208 deletions
+34 -15
View File
@@ -14,7 +14,6 @@ classifiers = [
"Environment :: Console",
"Environment :: GPU",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
@@ -22,32 +21,32 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = [
"accelerate~=1.13",
"bitsandbytes~=0.49",
"datasets~=4.7",
"huggingface-hub~=1.7",
"accelerate~=1.15",
"bitsandbytes~=0.50",
"datasets~=5.0",
"huggingface-hub~=1.33",
"immutabledict~=4.3",
"langdetect~=1.0",
"lm-eval[hf]~=0.4",
"numpy~=2.2",
"optuna~=4.7",
"peft~=0.19",
"optuna~=5.0",
"peft~=0.21",
"psutil~=7.2",
"py-cpuinfo~=9.0",
"pydantic-settings~=2.13",
"pydantic-settings~=2.15",
"questionary~=2.1",
"rich~=14.3",
"rich~=15.0",
"tomli-w~=1.2",
"torch", # version deliberately unspecified
"torchvision", # version deliberately unspecified
"tqdm~=4.67",
"transformers[kernels]~=5.6",
"tqdm~=4.70",
"transformers[kernels]~=5.18",
]
[dependency-groups]
dev = [
"ruff>=0.14.5",
"ty>=0.0.5",
"ruff>=0.16.9",
"ty>=0.0.84",
]
[project.urls]
@@ -61,11 +60,31 @@ Changelog = "https://github.com/p-e-w/heretic/releases"
heretic = "heretic.main:main"
[build-system]
requires = ["uv_build>=0.8.11,<0.9.0"]
requires = ["uv_build>=0.12.21,<0.13.0"]
build-backend = "uv_build"
[tool.ruff.lint]
ignore = [
"B023", # "Function definition does not bind loop variable"
"BLE001", # "Do not catch blind exception"
"TRY002", # "Create your own exception"
"SIM117", # "Use a single `with` statement with multiple contexts instead of nested `with` statements"
]
[tool.uv]
exclude-newer = "7 days"
# TODO: Re-enable before 2.0 release!
#exclude-newer = "7 days"
[tool.uv.sources]
torch = { index = "pytorch" }
torchvision = { index = "pytorch" }
[[tool.uv.index]]
# Default to CPU wheels for PyTorch to avoid issues in CI.
# Can be overridden by passing `--index pytorch=<url>` to uv.
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.uv.build-backend]
module-name = "heretic"
+3 -3
View File
@@ -2,7 +2,7 @@
# Copyright (C) 2025-2026 Philipp Emanuel Weidmann <pew@worldwidemann.com> + contributors
from enum import Enum
from typing import Dict, Literal, TypeAlias
from typing import Literal, TypeAlias
from pydantic import (
BaseModel,
@@ -254,12 +254,12 @@ class Settings(BaseSettings):
),
)
device_map: str | Dict[str, int | str] = Field(
device_map: str | dict[str, int | str] = Field(
default="auto",
description="Device map to pass to Accelerate when loading the model.",
)
max_memory: Dict[str, str] | None = Field(
max_memory: dict[str, str] | None = Field(
default=None,
description='Maximum memory to allocate per device (e.g., { "0" = "20GB", "cpu" = "64GB" }).',
)
+5 -17
View File
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2025-2026 Philipp Emanuel Weidmann <pew@worldwidemann.com> + contributors
# ruff: noqa: E402
import sys
# Ensure standard output/error use UTF-8 instead of system default charmap (e.g. cp1252 on Windows).
@@ -23,7 +21,7 @@ def _is_help_invocation() -> bool:
# Parse and handle CLI help before importing heavyweight ML/runtime dependencies.
if _is_help_invocation():
Settings() # ty:ignore[missing-argument]
Settings()
# FIXME: Rich progress bars are currently disabled because of rendering issues
# when used from multiple threads in parallel (e.g. by huggingface_hub).
@@ -223,7 +221,7 @@ def run():
try:
# The required argument "model" must be provided by the user,
# either on the command line or in the configuration file.
settings = Settings() # ty:ignore[missing-argument]
settings = Settings()
except ValidationError as error:
print(f"[red]Configuration contains [bold]{error.error_count()}[/] errors:[/]")
@@ -251,13 +249,11 @@ def run():
if reproduction_information["version"] != "4":
print(
(
f"[red]Unsupported file format version: [bold]{reproduction_information['version']}[/].[/] "
"This version of Heretic reads version 4 (plugin-based) reproduce.json files. "
"Older files were produced before the introduction of the plugin system and are not supported. "
"Please install Heretic 1.4 to use these files."
)
)
return
if not check_environment(settings, reproduction_information):
@@ -339,13 +335,11 @@ def run():
if settings.checkpoint_action is None:
print()
print(
(
"[green]You have already processed this model.[/] "
"You can show the results from the previous run, allowing you to export models or to run additional trials. "
"Alternatively, you can ignore the previous run and start from scratch. "
"This will delete the checkpoint file and all results from the previous run."
)
)
choices.append(
Choice(
@@ -357,13 +351,11 @@ def run():
if settings.checkpoint_action is None:
print()
print(
(
"[yellow]You have already processed this model, but the run was interrupted.[/] "
"You can continue the previous run from where it stopped. This will override any specified settings. "
"Alternatively, you can ignore the previous run and start from scratch. "
"This will delete the checkpoint file and all results from the previous run."
)
)
choices.append(
Choice(
@@ -771,13 +763,11 @@ def run():
if settings.trial_index is None:
print()
print(
(
"The following trials resulted in Pareto optimal combinations of the optimization objectives. "
"After selecting a trial, you will be able to save the model, upload it to Hugging Face, "
"chat with it to test how well it works, or run standard benchmarks on it. "
"You can return to this menu later to select a different trial. "
)
)
while trial_loop_active:
# Ensure a predefined trial is only processed once.
@@ -1077,14 +1067,12 @@ def run():
if is_reproducible:
if settings.upload_reproducibility_information is None:
print(
(
"Heretic can add information to the repository that allows others to reproduce the model. "
"This is optional, but valuable to the community as both a learning tool and to preserve computational work already done. "
"Guaranteeing reproducibility requires basic system information (Python and OS version, CPU and GPU/accelerator info) "
"as tensor operations can give different results in different system environments. "
"[bold]The information does not include any file system paths or other private data.[/]"
)
)
reproducibility_information = ask_if_unset(
settings.upload_reproducibility_information,
@@ -1115,7 +1103,7 @@ def run():
if strategy == ExportStrategy.ADAPTER:
print("Uploading LoRA adapter...")
model.model.push_to_hub(
repo_id,
repo_id, # ty: ignore[invalid-argument-type]
private=private,
max_shard_size=settings.max_shard_size,
token=token,
@@ -1124,7 +1112,7 @@ def run():
print("Uploading merged model...")
merged_model = model.get_merged_model()
merged_model.push_to_hub(
repo_id,
repo_id, # ty: ignore[invalid-argument-type]
private=private,
max_shard_size=settings.max_shard_size,
token=token,
@@ -1319,7 +1307,7 @@ def run():
benchmark_original_model = scope == "Benchmark both models"
hflm = HFLM(
pretrained=model.model, # ty:ignore[invalid-argument-type]
pretrained=model.model,
tokenizer=model.tokenizer, # ty:ignore[invalid-argument-type]
batch_size="auto",
)
+36 -29
View File
@@ -1,8 +1,9 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2025-2026 Philipp Emanuel Weidmann <pew@worldwidemann.com> + contributors
from collections.abc import Callable
from contextlib import suppress
from typing import Any, Callable, Type, TypeAlias, cast
from typing import Any, TypeAlias, cast
import torch
from peft import LoraConfig, PeftModel, get_peft_model
@@ -23,7 +24,7 @@ from transformers import (
TextStreamer,
)
from transformers.generation import (
GenerateDecoderOnlyOutput, # ty:ignore[possibly-missing-import]
GenerateDecoderOnlyOutput,
)
from .config import QuantizationMethod, Settings
@@ -33,10 +34,10 @@ from .utils import Prompt, batchify, format_exception, print
def get_model_class(
model: str,
) -> Type[AutoModelForImageTextToText] | Type[AutoModelForCausalLM]:
) -> type[AutoModelForImageTextToText] | type[AutoModelForCausalLM]:
configs = PretrainedConfig.get_config_dict(model)
if any([("vision_config" in config) for config in configs]):
if any(("vision_config" in config) for config in configs):
return AutoModelForImageTextToText
else:
return AutoModelForCausalLM
@@ -68,9 +69,14 @@ class Model:
print()
print(f"Loading model [bold]{settings.model}[/]...")
self.tokenizer = AutoTokenizer.from_pretrained(
# PreTrainedTokenizerBase is the "base class for all tokenizer backends"
# according to the documentation.
self.tokenizer = cast(
PreTrainedTokenizerBase,
AutoTokenizer.from_pretrained(
settings.model,
**self.revision_kwargs,
),
)
# Multimodal models have a processor we'll want to save.
@@ -90,7 +96,7 @@ class Model:
# after the prompt and thinks the sequence is complete.
self.tokenizer.padding_side = "left"
self.model = None # ty:ignore[invalid-assignment]
self.model = None
self.max_memory = (
{int(k) if k.isdigit() else k: v for k, v in settings.max_memory.items()}
if settings.max_memory
@@ -143,7 +149,7 @@ class Model:
max_new_tokens=1,
)
except Exception as error:
self.model = None # ty:ignore[invalid-assignment]
self.model = None
empty_cache()
formatted = format_exception(error)
@@ -315,7 +321,7 @@ class Model:
return True
# Purge existing model object from memory to make space.
self.model = None # ty:ignore[invalid-assignment]
self.model = None
empty_cache()
quantization_config = self._get_quantization_config(
@@ -352,10 +358,10 @@ class Model:
# Most multimodal models.
with suppress(Exception):
return model.model.language_model.layers
return model.model.language_model.layers # ty: ignore[unresolved-attribute, invalid-return-type]
# Text-only models.
return model.model.layers
return model.model.layers # ty: ignore[unresolved-attribute, invalid-return-type]
def get_layer_modules(self, layer_index: int) -> dict[str, list[Module]]:
layer = self.get_layers()[layer_index]
@@ -376,50 +382,50 @@ class Model:
# Standard self-attention out-projection (most models).
with suppress(Exception):
try_add("attn.o_proj", layer.self_attn.o_proj) # ty:ignore[possibly-missing-attribute]
try_add("attn.o_proj", layer.self_attn.o_proj) # ty: ignore[unresolved-attribute]
# Qwen3.5 MoE hybrid layers use GatedDeltaNet (linear attention) instead of
# standard self-attention, so self_attn.o_proj doesn't exist on those layers.
with suppress(Exception):
try_add("attn.o_proj", layer.linear_attn.out_proj) # ty:ignore[possibly-missing-attribute]
try_add("attn.o_proj", layer.linear_attn.out_proj) # ty: ignore[unresolved-attribute]
# Most dense models.
with suppress(Exception):
try_add("mlp.down_proj", layer.mlp.down_proj) # ty:ignore[possibly-missing-attribute]
try_add("mlp.down_proj", layer.mlp.down_proj) # ty: ignore[unresolved-attribute]
# Some MoE models (e.g. Qwen3).
with suppress(Exception):
for expert in layer.mlp.experts: # ty:ignore[possibly-missing-attribute, not-iterable]
try_add("mlp.down_proj", expert.down_proj) # ty:ignore[possibly-missing-attribute]
for expert in layer.mlp.experts: # ty:ignore[not-iterable, unresolved-attribute]
try_add("mlp.down_proj", expert.down_proj) # ty: ignore[unresolved-attribute]
# Phi-3.5-MoE (and possibly others).
with suppress(Exception):
for expert in layer.block_sparse_moe.experts: # ty:ignore[possibly-missing-attribute, not-iterable]
try_add("mlp.down_proj", expert.w2) # ty:ignore[possibly-missing-attribute]
for expert in layer.block_sparse_moe.experts: # ty:ignore[not-iterable, unresolved-attribute]
try_add("mlp.down_proj", expert.w2) # ty: ignore[unresolved-attribute]
# LFM dense operator blocks.
with suppress(Exception):
try_add("attn.o_proj", layer.conv.out_proj) # ty:ignore[possibly-missing-attribute]
try_add("attn.o_proj", layer.conv.out_proj) # ty: ignore[unresolved-attribute]
with suppress(Exception):
try_add("mlp.down_proj", layer.feed_forward.w2) # ty:ignore[possibly-missing-attribute]
try_add("mlp.down_proj", layer.feed_forward.w2) # ty: ignore[unresolved-attribute]
# LFM transformer blocks.
with suppress(Exception):
try_add("attn.o_proj", layer.self_attn.out_proj) # ty:ignore[possibly-missing-attribute]
try_add("attn.o_proj", layer.self_attn.out_proj) # ty: ignore[unresolved-attribute]
with suppress(Exception):
for expert in layer.feed_forward.experts: # ty:ignore[possibly-missing-attribute, not-iterable]
try_add("mlp.down_proj", expert.w2) # ty:ignore[possibly-missing-attribute]
for expert in layer.feed_forward.experts: # ty:ignore[not-iterable, unresolved-attribute]
try_add("mlp.down_proj", expert.w2) # ty: ignore[unresolved-attribute]
# Granite MoE Hybrid - attention layers with shared_mlp.
with suppress(Exception):
try_add("mlp.down_proj", layer.shared_mlp.output_linear) # ty:ignore[possibly-missing-attribute]
try_add("mlp.down_proj", layer.shared_mlp.output_linear) # ty: ignore[unresolved-attribute]
# Granite MoE Hybrid - MoE layers with experts.
with suppress(Exception):
for expert in layer.moe.experts: # ty:ignore[possibly-missing-attribute, not-iterable]
try_add("mlp.down_proj", expert.output_linear) # ty:ignore[possibly-missing-attribute]
for expert in layer.moe.experts: # ty:ignore[not-iterable, unresolved-attribute]
try_add("mlp.down_proj", expert.output_linear) # ty: ignore[unresolved-attribute]
# We need at least one module across all components for abliteration to work.
total_modules = sum(len(mods) for mods in modules.values())
@@ -512,11 +518,12 @@ class Model:
responses = []
for batch in batchify(prompts, self.settings.batch_size):
for response in self.get_responses(
responses.extend(
self.get_responses(
batch,
skip_special_tokens=skip_special_tokens,
):
responses.append(response)
)
)
return responses
@@ -809,7 +816,7 @@ class Model:
# The TextStreamer constructor annotates this parameter with the AutoTokenizer
# type, which makes no sense because AutoTokenizer is a factory class,
# not a base class that tokenizers inherit from.
self.tokenizer, # ty:ignore[invalid-argument-type]
self.tokenizer,
skip_prompt=True,
skip_special_tokens=True,
)
+1 -1
View File
@@ -32,7 +32,7 @@ class Serializable(Protocol):
Parameters = TypeVar("Parameters", bound=Serializable)
class Modifier(Generic[Parameters], Plugin, ABC):
class Modifier(Plugin, ABC, Generic[Parameters]):
"""
Abstract base class for modifier plugins.
+4 -11
View File
@@ -6,7 +6,7 @@ from dataclasses import asdict, dataclass
from enum import Enum
from typing import Any, cast
import bitsandbytes as bnb
import bitsandbytes.functional as BNB_F
import torch
import torch.linalg as LA
import torch.nn.functional as F
@@ -332,9 +332,7 @@ class Abliteration(Modifier[Parameters]):
weight_distribution = parameters.weight_distributions[component]
# Type inference fails here for some reason.
distance = cast(
float, abs(layer_index - weight_distribution.max_weight_position)
)
distance = abs(layer_index - weight_distribution.max_weight_position)
# Don't orthogonalize layers that are more than
# min_weight_distance away from max_weight_position.
@@ -390,15 +388,10 @@ class Abliteration(Modifier[Parameters]):
W = base_weight.to(torch.float32)
else:
# 4-bit quantization.
# This cast is always valid. Type inference fails here because the
# bnb.functional module is not found by ty for some reason.
W = cast(
Tensor,
bnb.functional.dequantize_4bit( # ty:ignore[possibly-missing-attribute]
W = BNB_F.dequantize_4bit(
base_weight.data,
quant_state,
).to(torch.float32),
)
).to(torch.float32)
# Flatten weight matrix to (out_features, in_features).
W = W.view(W.shape[0], -1)
+3 -6
View File
@@ -7,7 +7,7 @@
from dataclasses import asdict, dataclass
from typing import Any, cast
import bitsandbytes as bnb
import bitsandbytes.functional as BNB_F
import torch
import torch.linalg as LA
import torch.nn.functional as F
@@ -264,13 +264,10 @@ class ARA(Modifier[Parameters]):
W_base = base_weight.to(torch.float32)
else:
# Use the original dequantization logic from bitsandbytes.
W_base = cast(
Tensor,
bnb.functional.dequantize_4bit( # ty:ignore[possibly-missing-attribute]
W_base = BNB_F.dequantize_4bit(
base_weight.data,
quant_state,
).to(torch.float32),
)
).to(torch.float32)
# Pre-calculate the original row norms to preserve them.
# See https://huggingface.co/blog/grimjim/norm-preserving-biprojected-abliteration
+1 -1
View File
@@ -362,4 +362,4 @@ class Plugin:
Override this in subclasses to do one-time setup (e.g. load prompts, compute
baselines).
"""
return None
return
+1 -7
View File
@@ -81,7 +81,7 @@ def collect_reproducibles(path: str):
found += 1
commit_hash = paths_info[0].last_commit.oid
commit_hash = paths_info[0].last_commit.oid # ty: ignore[unresolved-attribute]
file_path = (
Path(path)
@@ -285,13 +285,11 @@ def check_environment(
else:
print(
(
"[yellow]The provided JSON file does not contain system information. "
"Some system parameters can affect reproducibility, but due to the lack of system information, "
"Heretic is unable to verify that those parameters match the original environment. "
"Reproduction may or may not produce a byte-for-byte identical model.[/]"
)
)
requirements = get_requirements_dict()
requirements["heretic-llm"] = format_version_information(
@@ -321,11 +319,9 @@ def check_environment(
if system_mismatches or package_mismatches:
print()
print(
(
"[yellow]Your local environment doesn't perfectly match the environment "
"used to produce the original model. The following components differ:[/]"
)
)
if system_mismatches:
table = Table()
@@ -358,13 +354,11 @@ def check_environment(
if system_mismatches or package_mismatches:
print()
print(
(
f"There is a {cast(MismatchSeverity, mismatch_severity).__rich__()} chance "
"that reproduction won't produce a byte-for-byte identical model. "
"However, the resulting model will very likely still behave similarly "
"to the original model."
)
)
if settings.ignore_mismatches is None:
print()
+1 -1
View File
@@ -44,7 +44,7 @@ class BenchmarkScore(Scorer):
model = ctx.get_model()
self.hflm = HFLM(
pretrained=model.model, # ty:ignore[invalid-argument-type]
pretrained=model.model,
tokenizer=model.tokenizer, # ty:ignore[invalid-argument-type]
batch_size="auto",
)
+4 -4
View File
@@ -96,7 +96,7 @@ def get_amdgpu_driver_version() -> str | None:
if os.path.exists(version_path):
with open(version_path, "r", encoding="utf-8") as f:
return f.read().strip()
except Exception:
except Exception: # noqa: S110
pass
return None
@@ -249,7 +249,7 @@ def get_accelerator_info_dict() -> dict[str, Any]:
info: dict[str, Any] = {
"type": "ROCm" if is_rocm else "CUDA",
"api_name": "HIP Version" if is_rocm else "CUDA Version",
"api_version": torch.version.hip if is_rocm else torch.version.cuda, # ty:ignore[unresolved-attribute]
"api_version": torch.version.hip if is_rocm else torch.version.cuda,
"driver_version": get_amdgpu_driver_version()
if is_rocm
else get_nvidia_driver_version(),
@@ -264,13 +264,13 @@ def get_accelerator_info_dict() -> dict[str, Any]:
return info
if is_xpu_available():
count = torch.xpu.device_count() # ty:ignore[unresolved-attribute]
count = torch.xpu.device_count()
return {
"type": "XPU",
"api_name": None,
"api_version": None,
"driver_version": get_xpu_driver_version(),
"devices": [{"name": torch.xpu.get_device_name(i)} for i in range(count)], # ty:ignore[unresolved-attribute]
"devices": [{"name": torch.xpu.get_device_name(i)} for i in range(count)],
}
if is_mlu_available():
+2 -2
View File
@@ -1,6 +1,6 @@
2f1b4d75d067bae3fe44e676721c7f077d243bc007156cb9c2f8b5836613d082 *chat_template.jinja
ca80080dfa4ec6ba87152fa2b9afe70b90c400e5c4b1d6bdc3aa3114467ca68f *config.json
70070bac883cf9c39b5992450d6b23cd160eaf33099e24c654e0359d2f87c760 *generation_config.json
c128bc8647a505e343c8cdff9bdd188b1a4a3f81938148685cbf90dff9827268 *config.json
58678fb2b8ae1b96652dffa43f864ad1c1c59e49c889bab4264ba0844c4a23b8 *generation_config.json
f3f4ec19504f182486459cf4e255ece265c25f827840d63b6a9d4058b8e4877a *model.safetensors
32bdf45d2ad4cc29a0822ddd157a182de76644f0419a6228d151495256e9813c *processor_config.json
cc8d3a0ce36466ccc1278bf987df5f71db1719b9ca6b4118264f45cb627bfe0f *tokenizer.json
+2 -2
View File
@@ -1,6 +1,6 @@
2f1b4d75d067bae3fe44e676721c7f077d243bc007156cb9c2f8b5836613d082 *chat_template.jinja
ca80080dfa4ec6ba87152fa2b9afe70b90c400e5c4b1d6bdc3aa3114467ca68f *config.json
70070bac883cf9c39b5992450d6b23cd160eaf33099e24c654e0359d2f87c760 *generation_config.json
c128bc8647a505e343c8cdff9bdd188b1a4a3f81938148685cbf90dff9827268 *config.json
58678fb2b8ae1b96652dffa43f864ad1c1c59e49c889bab4264ba0844c4a23b8 *generation_config.json
53c4ee891dce23c0ac85bebc2c4d48301469750fafbb3e6e024c15786d94db8b *model.safetensors
32bdf45d2ad4cc29a0822ddd157a182de76644f0419a6228d151495256e9813c *processor_config.json
cc8d3a0ce36466ccc1278bf987df5f71db1719b9ca6b4118264f45cb627bfe0f *tokenizer.json
+2 -2
View File
@@ -1,6 +1,6 @@
2f1b4d75d067bae3fe44e676721c7f077d243bc007156cb9c2f8b5836613d082 *chat_template.jinja
ca80080dfa4ec6ba87152fa2b9afe70b90c400e5c4b1d6bdc3aa3114467ca68f *config.json
70070bac883cf9c39b5992450d6b23cd160eaf33099e24c654e0359d2f87c760 *generation_config.json
c128bc8647a505e343c8cdff9bdd188b1a4a3f81938148685cbf90dff9827268 *config.json
58678fb2b8ae1b96652dffa43f864ad1c1c59e49c889bab4264ba0844c4a23b8 *generation_config.json
9ff0593e3fbd0ba463bbc980ebb3ed34798e562b606f90cd93c2df5403732c7b *model.safetensors
32bdf45d2ad4cc29a0822ddd157a182de76644f0419a6228d151495256e9813c *processor_config.json
cc8d3a0ce36466ccc1278bf987df5f71db1719b9ca6b4118264f45cb627bfe0f *tokenizer.json
+2 -2
View File
@@ -1,6 +1,6 @@
2f1b4d75d067bae3fe44e676721c7f077d243bc007156cb9c2f8b5836613d082 *chat_template.jinja
ca80080dfa4ec6ba87152fa2b9afe70b90c400e5c4b1d6bdc3aa3114467ca68f *config.json
70070bac883cf9c39b5992450d6b23cd160eaf33099e24c654e0359d2f87c760 *generation_config.json
c128bc8647a505e343c8cdff9bdd188b1a4a3f81938148685cbf90dff9827268 *config.json
58678fb2b8ae1b96652dffa43f864ad1c1c59e49c889bab4264ba0844c4a23b8 *generation_config.json
effe36925f85ecb1e29bba84501a456bb49df21e4047be8b7ea3f6f88181fb65 *model.safetensors
32bdf45d2ad4cc29a0822ddd157a182de76644f0419a6228d151495256e9813c *processor_config.json
cc8d3a0ce36466ccc1278bf987df5f71db1719b9ca6b4118264f45cb627bfe0f *tokenizer.json
-7
View File
@@ -1,7 +0,0 @@
b16d3228a775c549ba97af41233a54e9de8dd2b65250f78346661d18b936a8b5 *chat_template.jinja
0094ad598a8043f84d82ad5c886547bca1d1d7f302d82f1491f83d388e89acd4 *config.json
1a019c5d688d54cf01318eab88cb4345dfa52135eb1d83c2f54125469eb88d5c *generation_config.json
effe36925f85ecb1e29bba84501a456bb49df21e4047be8b7ea3f6f88181fb65 *model.safetensors
24d00232e58cfa179fe8b3911c788d4aad9a6279d778ebe4c72e82623b6197f9 *processor_config.json
cc8d3a0ce36466ccc1278bf987df5f71db1719b9ca6b4118264f45cb627bfe0f *tokenizer.json
8044bbbddaee8dc47e6b5660e013ba92224d4a5392b2939c59699aa0105f5c8b *tokenizer_config.json
+2 -2
View File
@@ -1,6 +1,6 @@
f8d9255777615591a7cc1a7c932f5a69e181128902295e1b81221d20d983cac7 *chat_template.jinja
91d2a5190c7ea0f74ed499428d4ad62b5208d63b36f7bbb562d15f4be25bd5c2 *config.json
dd6034a30113decdfaf8886622e20eb9e2e02d3f774918d474a4e26cfd7fbba8 *generation_config.json
22d559dde87f1a0faf02efed3062af2b1fc8a1721a55b952cd5f5d8c356b4feb *config.json
523e422e425e7a7ba23d85cc0faeef143dc5da37b72bfc649df5a8d83ee95beb *generation_config.json
aefe8b9c4b4969f6d13c5d778760f3dce4e25134324b33677934550d9df02a7c *model.safetensors
fce342a4642cb8afc42d8d89cfa21198b64a43458ded7f6ff28d1151a08c9cda *tokenizer.json
9ba5fa877168e24823cb583c55b4c2e4df0331f30084953c7cf07de294640384 *tokenizer_config.json
@@ -1,6 +1,6 @@
7451a05cf1e28a79d97d7c0bc951028c0b1915119bf9046acd06a0e3d931f47c *chat_template.jinja
fe6fd41d9f2ce5d6486748cf0330b574f37bf7d4e915f7b39d1af1a185cac3c3 *config.json
c4c2ef5ae4a4e2dd10655a3b99d801a8a50497286ddd042ba35bcfefc44ad349 *generation_config.json
de44f54b200f63c8ccb7899965bc9aaf21b23d35164c7de9a3cc3394530e3821 *config.json
12d96814a0cd1a72cae14392b04b9644353e8600614faa6eb7ee5edbf9452ec1 *generation_config.json
1535a9b7a91b2cb39ad280dbd9a940e2609a0b423d5b924df4d664e579912802 *model.safetensors
ad92aaa8d3032c98a9158b8c5e8682bed10027ed6463e4fb1320fe5384210873 *tokenizer.json
3ad32522c384dbe35192bb69de9befbf3f523e99d4bb3f95da757671d4c28281 *tokenizer_config.json
-6
View File
@@ -1,6 +0,0 @@
d8db3ff45c4c68a0ba9dee962ff1a0adde9a2be55e0895306f6bd2b2756f5adb *chat_template.jinja
a9d6f64bb9d0c02b553119e475615153af625b5c2a16ccb8fb8b3c2cc348f465 *config.json
0e7611a1e8fd0a06a139b0572b2c55b885ba9fb7db2022873c3508aebfb488aa *generation_config.json
411d95f42d3e31aef41c28314c8f0431c980687a97904d32b4ef57c42199720f *model.safetensors
ad92aaa8d3032c98a9158b8c5e8682bed10027ed6463e4fb1320fe5384210873 *tokenizer.json
aa083f3da10340925734e876e41e235c459329294ecd35d7511ec5868c1f14e3 *tokenizer_config.json
+4 -4
View File
@@ -1,7 +1,7 @@
39f03c383413f531fd302c06c7e982ad98c83f0657a8339ae25478ccb81fdcda *chat_template.jinja
f69f84977a47c8fea9ce9fc26b7de379216cb01146ea726a87996d3554cfcd19 *config.json
34dfa6012ca9ac5f57e5521d8dbaecbc7ab7f7ab0fd96ec020b543aab5f265d9 *generation_config.json
876c6691eb85e3e5e11771e589529830fb454ab26344e1271ae550661e312b50 *model.safetensors
84be30b124b50749c56d25fdbec5ccedf564446f6b3b035e88e1e07b986d2491 *processor_config.json
b2cfd8a9da09efc97040f3839fe629f3925db856a44b58314301dc5e11345ec8 *config.json
338d303c3c3df6884030cf5be24560f6e973fc183220d14acfb9364cd0e070e4 *generation_config.json
05497f43a38427c5813105fc007ce0dd41be65470e9cb8f343443f31bab7f0fe *model.safetensors
a05f93a41b7e42ccc18461b540fb54490c3ffa13aef79c800bbe7942e02e360f *processor_config.json
c3a8d92e371b92a2cd6e678e31ebc27d0235e929a51fbf290f74742b341fa96f *tokenizer.json
7b29c843c0043622d28fd4638451cbb0a609d99a0762ffbff3b92b4b2fee4d94 *tokenizer_config.json
+4 -4
View File
@@ -1,7 +1,7 @@
39f03c383413f531fd302c06c7e982ad98c83f0657a8339ae25478ccb81fdcda *chat_template.jinja
f69f84977a47c8fea9ce9fc26b7de379216cb01146ea726a87996d3554cfcd19 *config.json
34dfa6012ca9ac5f57e5521d8dbaecbc7ab7f7ab0fd96ec020b543aab5f265d9 *generation_config.json
6febb813086f253e5ec0fcda02fdfc849c551a7dba54681b37ac5bc402e4eed6 *model.safetensors
84be30b124b50749c56d25fdbec5ccedf564446f6b3b035e88e1e07b986d2491 *processor_config.json
b2cfd8a9da09efc97040f3839fe629f3925db856a44b58314301dc5e11345ec8 *config.json
338d303c3c3df6884030cf5be24560f6e973fc183220d14acfb9364cd0e070e4 *generation_config.json
ad6675b44b476a899914761257bbeb7f320cb9c0dc39a7467daf4dad0216dd1f *model.safetensors
a05f93a41b7e42ccc18461b540fb54490c3ffa13aef79c800bbe7942e02e360f *processor_config.json
c3a8d92e371b92a2cd6e678e31ebc27d0235e929a51fbf290f74742b341fa96f *tokenizer.json
7b29c843c0043622d28fd4638451cbb0a609d99a0762ffbff3b92b4b2fee4d94 *tokenizer_config.json
+7
View File
@@ -0,0 +1,7 @@
39f03c383413f531fd302c06c7e982ad98c83f0657a8339ae25478ccb81fdcda *chat_template.jinja
b2cfd8a9da09efc97040f3839fe629f3925db856a44b58314301dc5e11345ec8 *config.json
338d303c3c3df6884030cf5be24560f6e973fc183220d14acfb9364cd0e070e4 *generation_config.json
4cf4d463a94f477ed446e47130cb7da6b5994f0b788e75b82b3c65a531585621 *model.safetensors
a05f93a41b7e42ccc18461b540fb54490c3ffa13aef79c800bbe7942e02e360f *processor_config.json
c3a8d92e371b92a2cd6e678e31ebc27d0235e929a51fbf290f74742b341fa96f *tokenizer.json
7b29c843c0043622d28fd4638451cbb0a609d99a0762ffbff3b92b4b2fee4d94 *tokenizer_config.json
+4 -4
View File
@@ -1,7 +1,7 @@
39f03c383413f531fd302c06c7e982ad98c83f0657a8339ae25478ccb81fdcda *chat_template.jinja
f69f84977a47c8fea9ce9fc26b7de379216cb01146ea726a87996d3554cfcd19 *config.json
34dfa6012ca9ac5f57e5521d8dbaecbc7ab7f7ab0fd96ec020b543aab5f265d9 *generation_config.json
29aff97d5633dead9e1ccd29a2cc153b4b7431d22f63c8d6cf60bc6547681cc9 *model.safetensors
84be30b124b50749c56d25fdbec5ccedf564446f6b3b035e88e1e07b986d2491 *processor_config.json
b2cfd8a9da09efc97040f3839fe629f3925db856a44b58314301dc5e11345ec8 *config.json
338d303c3c3df6884030cf5be24560f6e973fc183220d14acfb9364cd0e070e4 *generation_config.json
8244162ecb6ce7bad7b10fe4f015889d76a09c7749dc7ac8c4d957f0864b2e82 *model.safetensors
a05f93a41b7e42ccc18461b540fb54490c3ffa13aef79c800bbe7942e02e360f *processor_config.json
c3a8d92e371b92a2cd6e678e31ebc27d0235e929a51fbf290f74742b341fa96f *tokenizer.json
7b29c843c0043622d28fd4638451cbb0a609d99a0762ffbff3b92b4b2fee4d94 *tokenizer_config.json
-7
View File
@@ -1,7 +0,0 @@
72f84af4ea36b82409c35e31b584361534305ef7c0d90fce20d0dc38a7efead8 *chat_template.jinja
e4c5278b361c57621253c27a2c3db358e1580aec8a14be8e19d4420a224137cf *config.json
8dde85c000ae807be907421465826c7c63a39f6acf6d04a5a84efaf116ed4ef7 *generation_config.json
20b5a820b38438202c64e4fc9807bd19e29678bebd678d29b2ee2d2f5bf71587 *model.safetensors
20e7a6dcde0a6f60ea3b4fb08f6f7afa62532dda93a3111e28384ba5150575f9 *processor_config.json
c3a8d92e371b92a2cd6e678e31ebc27d0235e929a51fbf290f74742b341fa96f *tokenizer.json
60a8042e29b4b20e884e48375aa1b9ac0025547371d50e60f6d55e6a9675e868 *tokenizer_config.json
+3 -3
View File
@@ -1,6 +1,6 @@
cd8e9439f0570856fd70470bf8889ebd8b5d1107207f67a5efb46e342330527f *chat_template.jinja
45134b857367fdcb97c0179199848c353fc28f8b95ac2244ac8f45cca448d864 *config.json
e81e23e025c38e825dcf8375861e26a90e804276e4db9ee390122a4fdc95dae7 *generation_config.json
bd86541d817978c896bd3579e69ae6d41b6382eaf1646accf83d6feb16acb703 *model.safetensors
6b517667960a5e39a692eb8277be7260ac02c22d9c7eda9c7aa1bbab21517fc1 *config.json
64cf6f4e0016154cae45628221d77e3925961876125fe68bd942303ec7cca40f *generation_config.json
e616cbeb5a913015eb3db96e001030048df2db560df363d4cf688f0c1b2c96de *model.safetensors
f7f96da3a872b5e901575b2067c744ad336c3a3d77a21584d20024557b1bd7f0 *tokenizer.json
04b1682c59acbd057f4c9072297faa73d56fc9de053094c659cdb4c464f58f86 *tokenizer_config.json
@@ -1,6 +1,6 @@
cd8e9439f0570856fd70470bf8889ebd8b5d1107207f67a5efb46e342330527f *chat_template.jinja
45134b857367fdcb97c0179199848c353fc28f8b95ac2244ac8f45cca448d864 *config.json
e81e23e025c38e825dcf8375861e26a90e804276e4db9ee390122a4fdc95dae7 *generation_config.json
e616cbeb5a913015eb3db96e001030048df2db560df363d4cf688f0c1b2c96de *model.safetensors
6b517667960a5e39a692eb8277be7260ac02c22d9c7eda9c7aa1bbab21517fc1 *config.json
64cf6f4e0016154cae45628221d77e3925961876125fe68bd942303ec7cca40f *generation_config.json
bd86541d817978c896bd3579e69ae6d41b6382eaf1646accf83d6feb16acb703 *model.safetensors
f7f96da3a872b5e901575b2067c744ad336c3a3d77a21584d20024557b1bd7f0 *tokenizer.json
04b1682c59acbd057f4c9072297faa73d56fc9de053094c659cdb4c464f58f86 *tokenizer_config.json
-6
View File
@@ -1,6 +0,0 @@
8aa40ce145adb73cb3a75194dc0224702a95850ec5275cabb728496bbd749fc6 *chat_template.jinja
e8f2fcd2681eb92233c0902866441f79a207b235f0b03364d41ebf8c53df62a0 *config.json
3fec6d7004e5ae311864de130b62e32dac87569874c91b3fe9c46e9309345c1c *generation_config.json
bd86541d817978c896bd3579e69ae6d41b6382eaf1646accf83d6feb16acb703 *model.safetensors
f7f96da3a872b5e901575b2067c744ad336c3a3d77a21584d20024557b1bd7f0 *tokenizer.json
154e5ff1e7c152d964edf30da854ea62465c767719ac8e97e58babf2d4fa9079 *tokenizer_config.json
+6 -6
View File
@@ -1,7 +1,7 @@
a4aee8afcf2e0711942cf848899be66016f8d14a889ff9ede07bca099c28f715 *chat_template.jinja
749b56d1b1e08081981169db6f2c44ab0be4fd6ebb452d15baafa5e09c21586a *config.json
4625d1d64d41d1fa9dae7af4ba1e1d7e65a194073d4efa58acb266a916eaaa74 *generation_config.json
2b3e575ac065f11ae5d4a7c3740efccbed294b646f1645239191ee8393354e03 *model.safetensors
01562eddd6f9e9ec4bc31656a3b7055284cafbf889acc6c4348dca431ae31f68 *processor_config.json
87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4 *tokenizer.json
2e31d1126e81bddf8d15c3f95260fb487b48c5131b24fcbb5bb9d2537e7afac0 *tokenizer_config.json
4b501bef0727793de90d446fcfdc7757a9f8d19efc42ceaa3d26e90db4f876d5 *config.json
532190619b0b243e0558a846257cc62883c26df812d456f8133e7b1043c69ad8 *generation_config.json
cfa4d5428e9b23c245fd2413ad702688cbcacd25808ecb17889e97c0976532ac *model.safetensors
3814737f2d4bfdd153a82364b3850f1be5dbc6f074a55c8d5fbf4d40127c3e87 *processor_config.json
a5cd9732badce41de57e6efce8302930ded1c1188c5f81feb2bd6c24c4a1941f *tokenizer.json
5e55dc6b9d9d28d49b6b2b80d2a2f2558a0b6e0e7b194bbca8664fc269ab3ebc *tokenizer_config.json
+6 -6
View File
@@ -1,7 +1,7 @@
a4aee8afcf2e0711942cf848899be66016f8d14a889ff9ede07bca099c28f715 *chat_template.jinja
749b56d1b1e08081981169db6f2c44ab0be4fd6ebb452d15baafa5e09c21586a *config.json
4625d1d64d41d1fa9dae7af4ba1e1d7e65a194073d4efa58acb266a916eaaa74 *generation_config.json
5e0fb0ac724cf079b693fc76a515e60bc16de72c32b36c107b9f078061c4f2ef *model.safetensors
01562eddd6f9e9ec4bc31656a3b7055284cafbf889acc6c4348dca431ae31f68 *processor_config.json
87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4 *tokenizer.json
2e31d1126e81bddf8d15c3f95260fb487b48c5131b24fcbb5bb9d2537e7afac0 *tokenizer_config.json
4b501bef0727793de90d446fcfdc7757a9f8d19efc42ceaa3d26e90db4f876d5 *config.json
532190619b0b243e0558a846257cc62883c26df812d456f8133e7b1043c69ad8 *generation_config.json
4c29b8ce99c59c90eca59aa6453029bda87165efa57cabc2c668599c02afc31a *model.safetensors
3814737f2d4bfdd153a82364b3850f1be5dbc6f074a55c8d5fbf4d40127c3e87 *processor_config.json
a5cd9732badce41de57e6efce8302930ded1c1188c5f81feb2bd6c24c4a1941f *tokenizer.json
5e55dc6b9d9d28d49b6b2b80d2a2f2558a0b6e0e7b194bbca8664fc269ab3ebc *tokenizer_config.json
-7
View File
@@ -1,7 +0,0 @@
a92e1dd97cb1cb175c9b70c0828e146bea4371c2643319b661b777e89811972e *chat_template.jinja
b75e911805663da79fb9fbbbcc917b8f1a285d2da54d95c2c63ea7c1ffe9a05a *config.json
2cbd9df0e99570efcced23b8d777bdf1fc692efda54b21eb59ad56ade76c9db6 *generation_config.json
6061519a9595326df41abcdd093892463793d4d026d6fd23548f1792f622a252 *model.safetensors
0c29f9491e769aabbc389ad5912127cf6d9d5fceda2db8767f73d48131348c81 *processor_config.json
87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4 *tokenizer.json
4796e48d790a26d65f167bec8fc742beaa71f79f9468a6cd8b3ffa97f6e2a198 *tokenizer_config.json
+6 -8
View File
@@ -53,7 +53,7 @@ for test_directory in script_directory.iterdir():
print()
valid_hashes: dict[str, list[str]] = {}
valid_hashes: dict[str, set[str]] = {}
for hash_file in hash_files:
with open(hash_file, "r", encoding="utf-8") as file:
@@ -63,26 +63,24 @@ for test_directory in script_directory.iterdir():
filename = filename.removeprefix("*")
if filename not in valid_hashes:
valid_hashes[filename] = []
valid_hashes[filename] = set()
valid_hashes[filename].append(sha256.lower())
valid_hashes[filename].add(sha256.lower())
# Track which specific files failed within this test directory.
failed_files: list[str] = []
for filename in valid_hashes:
for filename, hashes in valid_hashes.items():
sha256 = get_file_sha256(test_directory / "model" / filename)
if sha256.lower() not in valid_hashes[filename]:
if sha256.lower() not in hashes:
print(
(
f"Test {test_directory.name} has FAILED!\n"
f"Output file {filename} doesn't match any valid hash.\n\n"
f"Valid hashes:\n"
f"{chr(10).join(valid_hashes[filename])}\n\n"
f"{chr(10).join(hashes)}\n\n"
f"Actual hash:\n"
f"{sha256}\n"
)
)
failed_files.append(filename)
if failed_files:
+2 -2
View File
@@ -1,6 +1,6 @@
39a23a1a28f68acd747373fa688bea630021ec4db2bc8dec2fd3962240fb0418 *chat_template.jinja
35e3ad5aeaa78984629ceba6c22a4236b4c21d6959485900da2a5a98ea7e4062 *config.json
2ec7a17f55287d482ca956f5acff44d9e88f6c7fd5ec06c7c33d641afa9af330 *generation_config.json
45d58c7316e9dab89e918b9ca1c141b8c7f5250d55e0f9be76f2f452903aeef8 *config.json
02b35dff3057b998f224a3a5599dc7737ba028e3b4181ba89ba74ba1e707a5dc *generation_config.json
0cdea9064dcbe6db666f9d42a283d664c133d4c67a2f6ea0fd863a54f522160c *model.safetensors
3cf3a6d9520f195638a36f0194239d817de7288710bca55f1f5753de226748f7 *tokenizer.json
388b47e61cb40f2fd51a89999053686ab4c45b40b43c0329d15645f5910d069e *tokenizer_config.json
Generated
+2908 -1984
View File
File diff suppressed because it is too large Load Diff