tensorfs 0.3.70__tar.gz → 0.3.71__tar.gz
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.
- {tensorfs-0.3.70 → tensorfs-0.3.71}/Cargo.lock +2 -2
- {tensorfs-0.3.70 → tensorfs-0.3.71}/Cargo.toml +1 -1
- {tensorfs-0.3.70 → tensorfs-0.3.71}/PKG-INFO +1 -1
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/ingest.rs +15 -7
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/companion_tests.rs +44 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived.rs +48 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/fill.rs +95 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/convert.rs +148 -5
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/fingerprint.rs +5 -2
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/journal.rs +10 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/mod.rs +2 -0
- tensorfs-0.3.71/crates/tensorfs-core/src/ingest/narrow.rs +178 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/preflight.rs +3 -3
- tensorfs-0.3.71/crates/tensorfs-core/src/ingest/routes/sdxl.routes.json +1 -0
- tensorfs-0.3.71/crates/tensorfs-core/src/ingest/routes/sdxl.spec.json +51 -0
- tensorfs-0.3.71/crates/tensorfs-core/src/ingest/routes.rs +382 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/source.rs +184 -16
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/transaction.rs +76 -21
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/providers.rs +93 -4
- tensorfs-0.3.71/crates/tensorfs-core/tests/as_is.rs +334 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/civitai_sdxl_profile.rs +18 -2
- tensorfs-0.3.71/crates/tensorfs-core/tests/routed_single_file.rs +297 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/source_plan.rs +35 -14
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/src/ingest.rs +27 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/src/lib.rs +2 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/src/store.rs +13 -7
- {tensorfs-0.3.70 → tensorfs-0.3.71}/pyproject.toml +1 -1
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/__init__.py +4 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/_ext.pyi +8 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/Cargo.toml +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/build.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/examples/h3-swiglu-layout.md +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/examples/optional-cache-backfill.md +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/examples/resident-conversion.md +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/examples/resident_conversion_profile.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/asset_update.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/b64.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/ckpt.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/conform.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/fetch.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/main.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/rd.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/repo.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/snap.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/bin/tfs/watch.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/cache_roots.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/canon.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/capability.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/catalog/lock.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/catalog.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/cbor.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/checkpoint.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/checkpoint_root.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/corpus.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/adoption.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/estimate.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/graft_tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/group_commit_tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/part_rows_tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/progress.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/resume_tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/retention.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/derived/roots.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/descriptors.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/disk.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/dtype.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/durability.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/err.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/fetch.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/fit.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/gc.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/header.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/home.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ids.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/carrier.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/custody.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/gguf.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/h3_lora.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/ingest/stamp.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/jcs.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/lib.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/limits.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/machine.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/manifest.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/meta.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/project.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/read.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/receipt.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/reclaim.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/registry.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/relation.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/repo_cache/identity.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/repo_cache.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/repository.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/sha256.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/source_artifact.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/spec.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/staging.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/stats.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/storage.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/store.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/api.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/http.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/http_reuse_tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/hub.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/ledger.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/memory.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/mod.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/pace.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/policy.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/prefix.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/pull.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/push.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/ranged.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/speculate.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/transport/tests.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/unsynced.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/src/vectors.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/additive_fields.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/anima_hf_profile.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/checkpoint_roots.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fd_budget.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fd_headroom.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fetch_url_progress.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fit.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/blobs.jsonl +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_list.jsonl +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_repository.json +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/expected_rows.jsonl +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/header.cbor +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/manifest.json +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/fixtures/repo_apply/mutation.json +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/foreign_json.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/h3_lora.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/h3_swiglu.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/home.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/import_tree.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/instrument_profiles.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/liveness.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/qwen_image21_profile.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/read_plan.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/reclaim.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/reclaim_run.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/repo_cache.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/repo_store.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/resident_admission.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/sha256_backends.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/sharded_cas.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/source_artifacts.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/source_download.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/source_prefixes.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/source_preflight.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/staging.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/store_boundaries.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/tensor_schema.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/transfer_memory.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/trust_index.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/version.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-core/tests/write_through.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/Cargo.toml +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/src/docs.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/crates/tensorfs-py/src/errors.rs +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/_derived_channel.py +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/_source_channel.py +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/_tensors.py +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/derived.py +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/errors.py +0 -0
- {tensorfs-0.3.70 → tensorfs-0.3.71}/python/tensorfs/py.typed +0 -0
|
@@ -439,7 +439,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
|
439
439
|
|
|
440
440
|
[[package]]
|
|
441
441
|
name = "tensorfs-core"
|
|
442
|
-
version = "0.3.
|
|
442
|
+
version = "0.3.71"
|
|
443
443
|
dependencies = [
|
|
444
444
|
"fs2",
|
|
445
445
|
"libc",
|
|
@@ -454,7 +454,7 @@ dependencies = [
|
|
|
454
454
|
|
|
455
455
|
[[package]]
|
|
456
456
|
name = "tensorfs-py"
|
|
457
|
-
version = "0.3.
|
|
457
|
+
version = "0.3.71"
|
|
458
458
|
dependencies = [
|
|
459
459
|
"pyo3",
|
|
460
460
|
"tensorfs-core",
|
|
@@ -445,7 +445,7 @@ pub fn cmd_bank(dialect: &str, converter: &str, f: &Flags) -> ExitCode {
|
|
|
445
445
|
let mut reviewed = Vec::new();
|
|
446
446
|
for (component, path) in &srcs {
|
|
447
447
|
let (full, raw) = ok!(source_core::read_carrier_at(path));
|
|
448
|
-
let h = if conv.
|
|
448
|
+
let h = if conv.dialect == "safetensors.single_file" {
|
|
449
449
|
ok!(convert::single_file_component(component, &full))
|
|
450
450
|
} else {
|
|
451
451
|
full
|
|
@@ -584,11 +584,11 @@ pub fn cmd_bank(dialect: &str, converter: &str, f: &Flags) -> ExitCode {
|
|
|
584
584
|
.collect::<Vec<_>>()
|
|
585
585
|
.join(",");
|
|
586
586
|
let variant = flag(f, "spec-variant").and_then(|value| value.parse().ok());
|
|
587
|
-
let mut prepared = match source_core::
|
|
587
|
+
let mut prepared = match source_core::prepare(
|
|
588
588
|
&target,
|
|
589
589
|
&unnamed(&srcs),
|
|
590
590
|
&CarrierSet::default(),
|
|
591
|
-
®,
|
|
591
|
+
Some(®),
|
|
592
592
|
variant,
|
|
593
593
|
) {
|
|
594
594
|
Ok(prepared) => prepared,
|
|
@@ -849,17 +849,22 @@ fn prepare_closed_source_plan(
|
|
|
849
849
|
if closed.registry != BUILTIN_REGISTRY {
|
|
850
850
|
flags.push(("registry".to_string(), closed.registry.clone()));
|
|
851
851
|
}
|
|
852
|
+
let as_is = closed.converter == convert::IDENTITY;
|
|
853
|
+
if as_is {
|
|
854
|
+
flags.push(("source-profile".to_string(), source_core::AS_IS.to_string()));
|
|
855
|
+
}
|
|
852
856
|
for (component, source) in &closed.sources {
|
|
853
857
|
flags.push((
|
|
854
858
|
"source".to_string(),
|
|
855
859
|
format!("{component}={}", source.path.to_string_lossy()),
|
|
856
860
|
));
|
|
857
861
|
}
|
|
858
|
-
|
|
862
|
+
// The plan was re-derived above, so its converter is the planner's: as-is has no registry.
|
|
863
|
+
let mut prepared = source_core::prepare(
|
|
859
864
|
&closed.target,
|
|
860
865
|
&closed.sources,
|
|
861
866
|
&closed.set,
|
|
862
|
-
®istry,
|
|
867
|
+
(!as_is).then_some(®istry),
|
|
863
868
|
None,
|
|
864
869
|
)
|
|
865
870
|
.map_err(bail)?;
|
|
@@ -989,15 +994,17 @@ pub(crate) fn construction_order(f: &Flags) -> Result<Vec<(String, String)>, Exi
|
|
|
989
994
|
|
|
990
995
|
/// Headers in, plan out. The one function `plan`, `run` and the worker all go through, so
|
|
991
996
|
/// a preview and a run cannot disagree about what was going to happen.
|
|
997
|
+
/// `--source-profile as-is/1` stores the sources as they are, unclassified.
|
|
992
998
|
fn prepare(f: &Flags, target: &str) -> Result<Prepared, ExitCode> {
|
|
993
999
|
let sources = sources(f)?;
|
|
994
1000
|
let registry = load_registry(f)?;
|
|
995
1001
|
let variant = flag(f, "spec-variant").and_then(|value| value.parse().ok());
|
|
996
|
-
source_core::
|
|
1002
|
+
let as_is = flag(f, "source-profile") == Some(source_core::AS_IS);
|
|
1003
|
+
source_core::prepare(
|
|
997
1004
|
target,
|
|
998
1005
|
&unnamed(&sources),
|
|
999
1006
|
&CarrierSet::default(),
|
|
1000
|
-
®istry,
|
|
1007
|
+
(!as_is).then_some(®istry),
|
|
1001
1008
|
variant,
|
|
1002
1009
|
)
|
|
1003
1010
|
.map_err(bail)
|
|
@@ -1206,6 +1213,7 @@ pub fn cmd_run(root: &Path, target: &str, f: &Flags) -> ExitCode {
|
|
|
1206
1213
|
| "tenant"
|
|
1207
1214
|
| "isolation-tier"
|
|
1208
1215
|
| "checkpoint-bytes"
|
|
1216
|
+
| "source-profile"
|
|
1209
1217
|
) {
|
|
1210
1218
|
argv.push(format!("--{k}"));
|
|
1211
1219
|
argv.push(v.clone());
|
|
@@ -196,6 +196,50 @@ fn ordinary_companions_survive_derivation_without_copying_tensor_backing_files()
|
|
|
196
196
|
std::fs::remove_dir_all(store.root()).unwrap();
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
#[test]
|
|
200
|
+
fn a_verified_store_object_is_a_companion_by_reference_and_never_a_new_byte() {
|
|
201
|
+
let (store, meta, id) = fixture();
|
|
202
|
+
let vocab = vec![0x7b; 256 << 10]; // over the inline bound: references have none
|
|
203
|
+
let object = store
|
|
204
|
+
.put_stream(
|
|
205
|
+
&mut vocab.as_slice(),
|
|
206
|
+
Some(&ObjectRef::of(&vocab)),
|
|
207
|
+
&Fault::default(),
|
|
208
|
+
)
|
|
209
|
+
.unwrap()
|
|
210
|
+
.obj;
|
|
211
|
+
let mut d = super::tests::created_declaration();
|
|
212
|
+
d.objects = vec![("tokenizer/vocab.json".into(), object.clone())];
|
|
213
|
+
let encoded = d.canonical_work_bytes().unwrap();
|
|
214
|
+
assert_eq!(
|
|
215
|
+
Declaration::parse_text(std::str::from_utf8(&encoded).unwrap()).unwrap(),
|
|
216
|
+
d
|
|
217
|
+
);
|
|
218
|
+
let writer = begin(&store, &meta, &id, 1, d.clone(), None).unwrap();
|
|
219
|
+
write_weight(&store, &meta, &id);
|
|
220
|
+
let receipt = commit(&store, &meta, &id, 1).unwrap();
|
|
221
|
+
release(&meta, writer);
|
|
222
|
+
assert!(!receipt.added_objects.contains(&object));
|
|
223
|
+
let header = checkpoint::load_header(&store, &receipt.header).unwrap();
|
|
224
|
+
let (name, asset) = &header.assets[0];
|
|
225
|
+
assert_eq!(
|
|
226
|
+
(name.as_str(), &asset.segments),
|
|
227
|
+
("tokenizer/vocab.json", &vec![object])
|
|
228
|
+
);
|
|
229
|
+
let mut read = Vec::new();
|
|
230
|
+
checkpoint::read_asset(&store, name, asset, &mut read).unwrap();
|
|
231
|
+
assert_eq!(read, vocab);
|
|
232
|
+
|
|
233
|
+
// An object this Store does not hold is refused at commit, never published.
|
|
234
|
+
let next = format!("sha256:{}", "c3".repeat(32));
|
|
235
|
+
d.objects = vec![("tokenizer/vocab.json".into(), ObjectRef::of(b"absent"))];
|
|
236
|
+
let writer = begin(&store, &meta, &next, 1, d, None).unwrap();
|
|
237
|
+
write_weight(&store, &meta, &next);
|
|
238
|
+
assert!(commit(&store, &meta, &next, 1).is_err());
|
|
239
|
+
release(&meta, writer);
|
|
240
|
+
std::fs::remove_dir_all(store.root()).unwrap();
|
|
241
|
+
}
|
|
242
|
+
|
|
199
243
|
#[test]
|
|
200
244
|
fn companion_paths_size_count_and_quotas_are_native_refusals() {
|
|
201
245
|
for path in [
|
|
@@ -181,6 +181,9 @@ pub struct Declaration {
|
|
|
181
181
|
pub configs: Vec<ConfigDeclaration>,
|
|
182
182
|
/// Bounded immutable ordinary companion files, locked into the work intent.
|
|
183
183
|
pub files: Vec<(String, Vec<u8>)>,
|
|
184
|
+
/// Companion files that are already verified Store objects (a pinned tokenizer), named
|
|
185
|
+
/// by reference: no bytes in the intent, none new in the output.
|
|
186
|
+
pub objects: Vec<(String, ObjectRef)>,
|
|
184
187
|
pub order: Vec<(String, String)>,
|
|
185
188
|
pub max_new_bytes: u64,
|
|
186
189
|
}
|
|
@@ -248,6 +251,19 @@ impl Declaration {
|
|
|
248
251
|
}
|
|
249
252
|
|
|
250
253
|
validate_files(&mut self.files)?;
|
|
254
|
+
self.objects.sort_by(|a, b| a.0.cmp(&b.0));
|
|
255
|
+
let mut paths: Vec<String> = self
|
|
256
|
+
.files
|
|
257
|
+
.iter()
|
|
258
|
+
.map(|(path, _)| path.clone())
|
|
259
|
+
.chain(std::iter::once("model.cozytensors".to_string()))
|
|
260
|
+
.collect();
|
|
261
|
+
for (path, object) in &self.objects {
|
|
262
|
+
crate::manifest::check_path(path)?;
|
|
263
|
+
crate::ids::hex64("companion object", &object.sha256)?;
|
|
264
|
+
paths.push(path.clone());
|
|
265
|
+
}
|
|
266
|
+
validate_companion_paths(&mut paths)?;
|
|
251
267
|
|
|
252
268
|
for source in &self.sources {
|
|
253
269
|
name("source alias", &source.alias)?;
|
|
@@ -563,6 +579,15 @@ impl Declaration {
|
|
|
563
579
|
));
|
|
564
580
|
}
|
|
565
581
|
}
|
|
582
|
+
let mut objects = Vec::new();
|
|
583
|
+
if let Some(value) = f.opt("objects") {
|
|
584
|
+
for (path, value) in as_obj("DerivedDeclaration", "objects", value)? {
|
|
585
|
+
objects.push((
|
|
586
|
+
path.clone(),
|
|
587
|
+
ObjectRef::from_value("companion object", value)?,
|
|
588
|
+
));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
566
591
|
let work_fingerprint = f
|
|
567
592
|
.opt("work_fingerprint")
|
|
568
593
|
.map(|value| {
|
|
@@ -710,6 +735,7 @@ impl Declaration {
|
|
|
710
735
|
components,
|
|
711
736
|
configs,
|
|
712
737
|
files,
|
|
738
|
+
objects,
|
|
713
739
|
order,
|
|
714
740
|
max_new_bytes,
|
|
715
741
|
})
|
|
@@ -873,6 +899,17 @@ impl Declaration {
|
|
|
873
899
|
),
|
|
874
900
|
));
|
|
875
901
|
}
|
|
902
|
+
if !self.objects.is_empty() {
|
|
903
|
+
fields.push((
|
|
904
|
+
"objects",
|
|
905
|
+
Value::map(
|
|
906
|
+
self.objects
|
|
907
|
+
.iter()
|
|
908
|
+
.map(|(path, object)| (path.clone(), object.to_value()))
|
|
909
|
+
.collect(),
|
|
910
|
+
),
|
|
911
|
+
));
|
|
912
|
+
}
|
|
876
913
|
if let Some(fingerprint) = &self.work_fingerprint {
|
|
877
914
|
fields.push(("work_fingerprint", Value::str(fingerprint.clone())));
|
|
878
915
|
}
|
|
@@ -947,6 +984,7 @@ fn companion_files(
|
|
|
947
984
|
.files
|
|
948
985
|
.iter()
|
|
949
986
|
.map(|(path, _)| path.as_str())
|
|
987
|
+
.chain(declaration.objects.iter().map(|(path, _)| path.as_str()))
|
|
950
988
|
.collect();
|
|
951
989
|
for source in sources {
|
|
952
990
|
let mut backing: HashSet<_> = source
|
|
@@ -989,6 +1027,12 @@ fn companion_files(
|
|
|
989
1027
|
.iter()
|
|
990
1028
|
.map(|(path, data)| (path.clone(), Entry::File(ObjectRef::of(data)))),
|
|
991
1029
|
);
|
|
1030
|
+
files.extend(
|
|
1031
|
+
declaration
|
|
1032
|
+
.objects
|
|
1033
|
+
.iter()
|
|
1034
|
+
.map(|(path, object)| (path.clone(), Entry::File(object.clone()))),
|
|
1035
|
+
);
|
|
992
1036
|
let mut paths: Vec<_> = files
|
|
993
1037
|
.keys()
|
|
994
1038
|
.cloned()
|
|
@@ -2197,6 +2241,7 @@ fn inspect_retained_source(
|
|
|
2197
2241
|
let alias = "source".to_string();
|
|
2198
2242
|
let mut declaration = Declaration {
|
|
2199
2243
|
files: Vec::new(),
|
|
2244
|
+
objects: Vec::new(),
|
|
2200
2245
|
work_fingerprint: None,
|
|
2201
2246
|
sources: vec![Source {
|
|
2202
2247
|
alias: alias.clone(),
|
|
@@ -3932,6 +3977,7 @@ mod tests {
|
|
|
3932
3977
|
.object_id();
|
|
3933
3978
|
Declaration {
|
|
3934
3979
|
files: Vec::new(),
|
|
3980
|
+
objects: Vec::new(),
|
|
3935
3981
|
work_fingerprint: Some(format!("sha256:{}", "44".repeat(32))),
|
|
3936
3982
|
sources: Vec::new(),
|
|
3937
3983
|
components: vec![ComponentDeclaration {
|
|
@@ -3961,6 +4007,7 @@ mod tests {
|
|
|
3961
4007
|
fn inherited_declaration(manifest: ObjectRef) -> Declaration {
|
|
3962
4008
|
Declaration {
|
|
3963
4009
|
files: Vec::new(),
|
|
4010
|
+
objects: Vec::new(),
|
|
3964
4011
|
work_fingerprint: Some(format!("sha256:{}", "44".repeat(32))),
|
|
3965
4012
|
sources: vec![Source {
|
|
3966
4013
|
alias: "source".into(),
|
|
@@ -4574,6 +4621,7 @@ mod tests {
|
|
|
4574
4621
|
1,
|
|
4575
4622
|
Declaration {
|
|
4576
4623
|
files: Vec::new(),
|
|
4624
|
+
objects: Vec::new(),
|
|
4577
4625
|
work_fingerprint: Some(format!("sha256:{}", "44".repeat(32))),
|
|
4578
4626
|
sources: vec![Source {
|
|
4579
4627
|
alias: "source".into(),
|
|
@@ -109,6 +109,13 @@ pub enum Xform {
|
|
|
109
109
|
/// Bytes in one share unit — derived from the source run, never assumed.
|
|
110
110
|
unit_bytes: u64,
|
|
111
111
|
},
|
|
112
|
+
/// A row-major `[rows, cols]` matrix becomes `[cols, rows]`. Every element moves on its
|
|
113
|
+
/// own, so this is gather-class by construction: it is applied buffered, never as runs.
|
|
114
|
+
Transpose {
|
|
115
|
+
rows: u64,
|
|
116
|
+
cols: u64,
|
|
117
|
+
elem_bytes: u64,
|
|
118
|
+
},
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
impl Xform {
|
|
@@ -122,6 +129,11 @@ impl Xform {
|
|
|
122
129
|
unit_bytes,
|
|
123
130
|
..
|
|
124
131
|
} => groups * (shares[0] + shares[1] + shares[2]) * unit_bytes,
|
|
132
|
+
Xform::Transpose {
|
|
133
|
+
rows,
|
|
134
|
+
cols,
|
|
135
|
+
elem_bytes,
|
|
136
|
+
} => rows * cols * elem_bytes,
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
|
|
@@ -135,6 +147,36 @@ impl Xform {
|
|
|
135
147
|
take,
|
|
136
148
|
unit_bytes,
|
|
137
149
|
} => groups * shares[*take as usize] * unit_bytes,
|
|
150
|
+
Xform::Transpose { .. } => self.in_bytes(),
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// Whether the transform streams its source runs straight out of the carrier. A
|
|
155
|
+
/// transpose reads its bounded source once and reorders it in memory instead.
|
|
156
|
+
pub fn streams(&self) -> bool {
|
|
157
|
+
!matches!(self, Xform::Transpose { .. })
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// `(bytes, runs, class)` of the decomposition, without materializing element runs.
|
|
161
|
+
pub fn census(&self) -> (u64, usize, Class) {
|
|
162
|
+
match self {
|
|
163
|
+
Xform::Transpose {
|
|
164
|
+
rows,
|
|
165
|
+
cols,
|
|
166
|
+
elem_bytes,
|
|
167
|
+
} => (
|
|
168
|
+
rows * cols * elem_bytes,
|
|
169
|
+
(rows * cols) as usize,
|
|
170
|
+
if *elem_bytes >= GATHER_FLOOR_BYTES {
|
|
171
|
+
Class::LongRun
|
|
172
|
+
} else {
|
|
173
|
+
Class::Gather
|
|
174
|
+
},
|
|
175
|
+
),
|
|
176
|
+
_ => {
|
|
177
|
+
let d = self.runs();
|
|
178
|
+
(d.bytes, d.runs.len(), d.class)
|
|
179
|
+
}
|
|
138
180
|
}
|
|
139
181
|
}
|
|
140
182
|
|
|
@@ -175,6 +217,21 @@ impl Xform {
|
|
|
175
217
|
.collect(),
|
|
176
218
|
)
|
|
177
219
|
}
|
|
220
|
+
Xform::Transpose {
|
|
221
|
+
rows,
|
|
222
|
+
cols,
|
|
223
|
+
elem_bytes,
|
|
224
|
+
} => Decomposition::of(
|
|
225
|
+
(0..*cols)
|
|
226
|
+
.flat_map(|j| {
|
|
227
|
+
(0..*rows).map(move |i| Run {
|
|
228
|
+
src_off: (i * cols + j) * elem_bytes,
|
|
229
|
+
dest_off: (j * rows + i) * elem_bytes,
|
|
230
|
+
len: *elem_bytes,
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
.collect(),
|
|
234
|
+
),
|
|
178
235
|
}
|
|
179
236
|
}
|
|
180
237
|
|
|
@@ -206,6 +263,24 @@ impl Xform {
|
|
|
206
263
|
),
|
|
207
264
|
);
|
|
208
265
|
}
|
|
266
|
+
if let Xform::Transpose {
|
|
267
|
+
rows,
|
|
268
|
+
cols,
|
|
269
|
+
elem_bytes,
|
|
270
|
+
} = *self
|
|
271
|
+
{
|
|
272
|
+
let (rows, cols, e) = (rows as usize, cols as usize, elem_bytes as usize);
|
|
273
|
+
for (i, row) in src.chunks_exact(cols * e).enumerate() {
|
|
274
|
+
for (j, value) in row.chunks_exact(e).enumerate() {
|
|
275
|
+
dest[(j * rows + i) * e..][..e].copy_from_slice(value);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return Ok(Decomposition {
|
|
279
|
+
runs: Vec::new(),
|
|
280
|
+
class: Class::Gather,
|
|
281
|
+
bytes: self.out_bytes(),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
209
284
|
let d = self.runs();
|
|
210
285
|
for r in &d.runs {
|
|
211
286
|
let (s, o, n) = (r.src_off as usize, r.dest_off as usize, r.len as usize);
|
|
@@ -229,6 +304,26 @@ impl Xform {
|
|
|
229
304
|
/// indexing and the three members must reassemble the source bit-for-bit.
|
|
230
305
|
pub fn reassembles(&self, src: &[u8]) -> Result<bool> {
|
|
231
306
|
match self {
|
|
307
|
+
Xform::Transpose {
|
|
308
|
+
rows,
|
|
309
|
+
cols,
|
|
310
|
+
elem_bytes,
|
|
311
|
+
} => {
|
|
312
|
+
let mut once = Vec::new();
|
|
313
|
+
self.apply(src, &mut once)?;
|
|
314
|
+
let mut back = Vec::new();
|
|
315
|
+
Xform::Transpose {
|
|
316
|
+
rows: *cols,
|
|
317
|
+
cols: *rows,
|
|
318
|
+
elem_bytes: *elem_bytes,
|
|
319
|
+
}
|
|
320
|
+
.apply(&once, &mut back)?;
|
|
321
|
+
Ok(back == src
|
|
322
|
+
&& self.runs().runs.iter().all(|r| {
|
|
323
|
+
once[r.dest_off as usize..][..r.len as usize]
|
|
324
|
+
== src[r.src_off as usize..][..r.len as usize]
|
|
325
|
+
}))
|
|
326
|
+
}
|
|
232
327
|
Xform::SwapHalves { .. } => {
|
|
233
328
|
let mut swapped = Vec::new();
|
|
234
329
|
self.apply(src, &mut swapped)?;
|
|
@@ -51,9 +51,25 @@ pub struct Converter {
|
|
|
51
51
|
/// Quarry-derived geometry that has NOT yet met the real bytes it describes (tfs-010).
|
|
52
52
|
/// Stated in the type so a receipt cannot quietly claim more than the evidence supports.
|
|
53
53
|
pub validated_on_real_bytes: bool,
|
|
54
|
+
/// `(state, dialect of the stored keys)` for the output's `normalization` config:
|
|
55
|
+
/// `raw` keys need a consumer that reads that dialect, `normalized` ones are canonical.
|
|
56
|
+
/// `None` records nothing (reviewed outputs that predate the record).
|
|
57
|
+
pub normalization: Option<(&'static str, &'static str)>,
|
|
58
|
+
/// The one declared value change a converter may make: floating sources narrow to this
|
|
59
|
+
/// dtype, IEEE round-to-nearest-even, and a finite value it cannot hold refuses
|
|
60
|
+
/// NUMBER_RANGE. `None` moves bytes only.
|
|
61
|
+
pub lane: Option<Dtype>,
|
|
62
|
+
/// The pinned repository (`hf://org/repo@<commit>`, a Diffusers pipeline) whose index,
|
|
63
|
+
/// configs, scheduler and tokenizers the output needs when its source carries none.
|
|
64
|
+
pub reference: Option<&'static str>,
|
|
54
65
|
}
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
/// The header config an output's [`Converter::normalization`] is recorded under.
|
|
68
|
+
pub const NORMALIZATION: &str = "normalization";
|
|
69
|
+
/// The converter for a source no reviewed profile recognizes: its keys, stored as they are.
|
|
70
|
+
pub const IDENTITY: &str = "identity/1";
|
|
71
|
+
|
|
72
|
+
pub const CONVERTERS: [Converter; 7] = [
|
|
57
73
|
Converter {
|
|
58
74
|
name: "diffusers.identity/1",
|
|
59
75
|
dialect: "safetensors.diffusers",
|
|
@@ -62,6 +78,9 @@ pub const CONVERTERS: [Converter; 5] = [
|
|
|
62
78
|
becomes one logical tensor; `.weight_scale` siblings fold into their base as \
|
|
63
79
|
encoding ROLES; marker tensors are dropped. Bytes stream through untouched.",
|
|
64
80
|
validated_on_real_bytes: true,
|
|
81
|
+
normalization: None,
|
|
82
|
+
lane: None,
|
|
83
|
+
reference: None,
|
|
65
84
|
},
|
|
66
85
|
Converter {
|
|
67
86
|
name: "single_file.identity/1",
|
|
@@ -70,6 +89,9 @@ pub const CONVERTERS: [Converter; 5] = [
|
|
|
70
89
|
doc: "One file carrying several components, split on the reviewed component prefix \
|
|
71
90
|
map. Same byte path as the diffusers converter — packaging is not identity.",
|
|
72
91
|
validated_on_real_bytes: true,
|
|
92
|
+
normalization: None,
|
|
93
|
+
lane: None,
|
|
94
|
+
reference: None,
|
|
73
95
|
},
|
|
74
96
|
Converter {
|
|
75
97
|
name: "cozytensors.inherit/1",
|
|
@@ -78,6 +100,9 @@ pub const CONVERTERS: [Converter; 5] = [
|
|
|
78
100
|
doc: "An already-canonical source. Every untouched tensor carries by OBJECT \
|
|
79
101
|
REFERENCE; nothing is re-hashed and nothing is re-uploaded.",
|
|
80
102
|
validated_on_real_bytes: true,
|
|
103
|
+
normalization: None,
|
|
104
|
+
lane: None,
|
|
105
|
+
reference: None,
|
|
81
106
|
},
|
|
82
107
|
Converter {
|
|
83
108
|
name: "h3.lora/1",
|
|
@@ -85,6 +110,9 @@ pub const CONVERTERS: [Converter; 5] = [
|
|
|
85
110
|
class: Class::Permutation,
|
|
86
111
|
doc: "Native H3 LoRA A/B and Kohya down/up factors: split head-interleaved QKV B rows, swap SwiGLU B halves, preserve A and alpha without arithmetic.",
|
|
87
112
|
validated_on_real_bytes: false,
|
|
113
|
+
normalization: None,
|
|
114
|
+
lane: None,
|
|
115
|
+
reference: None,
|
|
88
116
|
},
|
|
89
117
|
Converter {
|
|
90
118
|
name: "h3.native/2",
|
|
@@ -106,9 +134,59 @@ pub const CONVERTERS: [Converter; 5] = [
|
|
|
106
134
|
// pinned official converter requires. The complete trained Ref2VA block0
|
|
107
135
|
// fc1 (308281344 B) converted to e7cf97ae...3b19; fc2 stayed byte-identical.
|
|
108
136
|
validated_on_real_bytes: true,
|
|
137
|
+
normalization: None,
|
|
138
|
+
lane: None,
|
|
139
|
+
reference: None,
|
|
140
|
+
},
|
|
141
|
+
Converter {
|
|
142
|
+
name: IDENTITY,
|
|
143
|
+
dialect: "safetensors",
|
|
144
|
+
class: Class::Identity,
|
|
145
|
+
doc: "An unrecognized source, stored as it is: every key becomes one plain tensor \
|
|
146
|
+
under its own name and dtype. Nothing is folded, dropped or renamed, so a \
|
|
147
|
+
consumer that needs another spelling normalizes it.",
|
|
148
|
+
validated_on_real_bytes: true,
|
|
149
|
+
normalization: Some(("raw", "safetensors")),
|
|
150
|
+
lane: None,
|
|
151
|
+
reference: None,
|
|
152
|
+
},
|
|
153
|
+
Converter {
|
|
154
|
+
name: super::routes::SDXL,
|
|
155
|
+
dialect: "safetensors.single_file",
|
|
156
|
+
class: Class::Permutation,
|
|
157
|
+
doc: "An SDXL single-file checkpoint becomes the Diffusers constructor's checkpoint: \
|
|
158
|
+
the generated route table rekeys every tensor into constructor order, splits \
|
|
159
|
+
OpenCLIP's fused in_proj into q|k|v runs, transposes its text_projection, \
|
|
160
|
+
squeezes 1x1-conv attention to linear and drops CLIP position IDs and \
|
|
161
|
+
logit_scale. bf16/f32 sources narrow to f16. Pipeline index, configs and \
|
|
162
|
+
tokenizers come from the pinned SDXL base reference.",
|
|
163
|
+
// The generated table equals packages-v2 sdxl normalization.json route for route, the
|
|
164
|
+
// mapping the sdxl normalize job served real Civitai checkpoints with.
|
|
165
|
+
validated_on_real_bytes: true,
|
|
166
|
+
normalization: Some(("normalized", "diffusers")),
|
|
167
|
+
lane: Some(Dtype::F16),
|
|
168
|
+
reference: Some(
|
|
169
|
+
"hf://stabilityai/stable-diffusion-xl-base-1.0@462165984030d82259a11f4367a4eed129e94a7b",
|
|
170
|
+
),
|
|
109
171
|
},
|
|
110
172
|
];
|
|
111
173
|
|
|
174
|
+
/// The `normalization` config the output of `converter` carries, if it records one.
|
|
175
|
+
pub fn normalization_config(converter: &str) -> Option<(String, Vec<u8>)> {
|
|
176
|
+
let converter_row = CONVERTERS.iter().find(|c| c.name == converter)?;
|
|
177
|
+
let (state, dialect) = converter_row.normalization?;
|
|
178
|
+
let mut fields = vec![
|
|
179
|
+
("converter", crate::canon::Value::str(converter)),
|
|
180
|
+
("dialect", crate::canon::Value::str(dialect)),
|
|
181
|
+
("state", crate::canon::Value::str(state)),
|
|
182
|
+
];
|
|
183
|
+
if let Some(reference) = converter_row.reference {
|
|
184
|
+
fields.push(("reference", crate::canon::Value::str(reference)));
|
|
185
|
+
}
|
|
186
|
+
let record = crate::canon::Value::obj(fields);
|
|
187
|
+
Some((NORMALIZATION.to_string(), crate::canon::write(&record)))
|
|
188
|
+
}
|
|
189
|
+
|
|
112
190
|
pub fn converter(name: &str) -> Result<&'static Converter> {
|
|
113
191
|
match CONVERTERS.iter().find(|c| c.name == name) {
|
|
114
192
|
Some(c) => Ok(c),
|
|
@@ -359,11 +437,11 @@ impl Plan {
|
|
|
359
437
|
for o in &self.ops {
|
|
360
438
|
for r in &o.roles {
|
|
361
439
|
if let Bytes::Permute { xform, .. } = &r.bytes {
|
|
362
|
-
let
|
|
440
|
+
let (moved, count, class) = xform.census();
|
|
363
441
|
ops += 1;
|
|
364
|
-
bytes +=
|
|
365
|
-
runs +=
|
|
366
|
-
gather |=
|
|
442
|
+
bytes += moved;
|
|
443
|
+
runs += count;
|
|
444
|
+
gather |= class == crate::fill::Class::Gather;
|
|
367
445
|
}
|
|
368
446
|
}
|
|
369
447
|
}
|
|
@@ -968,6 +1046,12 @@ fn plan_carrier(
|
|
|
968
1046
|
}
|
|
969
1047
|
return super::h3_lora::plan(component, file, h, cands.plain, p);
|
|
970
1048
|
}
|
|
1049
|
+
if conv.name == IDENTITY {
|
|
1050
|
+
return plan_as_is(component, file, h, allowed, cands.plain, p);
|
|
1051
|
+
}
|
|
1052
|
+
if let Some(table) = super::routes::table(conv.name) {
|
|
1053
|
+
return super::routes::plan(conv, table, component, file, h, allowed, cands.plain, p);
|
|
1054
|
+
}
|
|
971
1055
|
let alias = Allowed(allowed);
|
|
972
1056
|
p.header_bytes += h.header_bytes;
|
|
973
1057
|
let plain_map = role_map("plain/1")?;
|
|
@@ -1232,6 +1316,46 @@ fn plan_carrier(
|
|
|
1232
1316
|
Ok(())
|
|
1233
1317
|
}
|
|
1234
1318
|
|
|
1319
|
+
/// Every key, its own plain tensor: no role folds, no marker drops, no rename.
|
|
1320
|
+
fn plan_as_is(
|
|
1321
|
+
component: &str,
|
|
1322
|
+
file: usize,
|
|
1323
|
+
h: &SourceHeader,
|
|
1324
|
+
allowed: &[&str],
|
|
1325
|
+
plain: &EncodingSpec,
|
|
1326
|
+
p: &mut Plan,
|
|
1327
|
+
) -> Result<()> {
|
|
1328
|
+
if allowed != ["plain/1"] {
|
|
1329
|
+
return refuse(
|
|
1330
|
+
Code::UNKNOWN_ENCODING,
|
|
1331
|
+
format!("{IDENTITY} stores an unrecognized source in plain/1 only"),
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
p.header_bytes += h.header_bytes;
|
|
1335
|
+
let (data, id) = (role_map("plain/1")?.data, plain.object_id());
|
|
1336
|
+
for t in &h.tensors {
|
|
1337
|
+
p.ops.push(Op {
|
|
1338
|
+
component: component.to_string(),
|
|
1339
|
+
out_key: t.key.clone(),
|
|
1340
|
+
encoding: "plain/1".into(),
|
|
1341
|
+
encoding_id: id.clone(),
|
|
1342
|
+
logical_dtype: t.dtype,
|
|
1343
|
+
logical_shape: t.shape.clone(),
|
|
1344
|
+
roles: vec![RolePlan {
|
|
1345
|
+
role: data.into(),
|
|
1346
|
+
dtype: t.dtype,
|
|
1347
|
+
shape: t.shape.clone(),
|
|
1348
|
+
bytes: Bytes::Stream {
|
|
1349
|
+
file,
|
|
1350
|
+
key: t.key.clone(),
|
|
1351
|
+
},
|
|
1352
|
+
}],
|
|
1353
|
+
effect: Effect::Recontain,
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
Ok(())
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1235
1359
|
/// The original H3 MLP consumes [gate; value], while Diffusers SwiGLU consumes
|
|
1236
1360
|
/// [value; gate]. The sibling fc2 projection proves the gate width, for main and
|
|
1237
1361
|
/// token-refiner blocks alike. Only source runs move; no tensor value changes.
|
|
@@ -1776,6 +1900,25 @@ pub fn golden_cases(c: &Converter) -> Vec<(&'static str, Xform)> {
|
|
|
1776
1900
|
},
|
|
1777
1901
|
),
|
|
1778
1902
|
],
|
|
1903
|
+
name if name == super::routes::SDXL => vec![
|
|
1904
|
+
(
|
|
1905
|
+
"OpenCLIP in_proj_bias, row block 2 of 3 (1280 x f16)",
|
|
1906
|
+
Xform::QkvSplit {
|
|
1907
|
+
groups: 1,
|
|
1908
|
+
shares: [2, 1, 0],
|
|
1909
|
+
take: 1,
|
|
1910
|
+
unit_bytes: 1280 * 2,
|
|
1911
|
+
},
|
|
1912
|
+
),
|
|
1913
|
+
(
|
|
1914
|
+
"OpenCLIP text_projection 3 x 5 x f32 transpose",
|
|
1915
|
+
Xform::Transpose {
|
|
1916
|
+
rows: 3,
|
|
1917
|
+
cols: 5,
|
|
1918
|
+
elem_bytes: 4,
|
|
1919
|
+
},
|
|
1920
|
+
),
|
|
1921
|
+
],
|
|
1779
1922
|
"h3.native/2" => vec![
|
|
1780
1923
|
(
|
|
1781
1924
|
"h3-swiglu gate/value rows",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
//! Classification: what IS this carrier, and
|
|
1
|
+
//! Classification: what IS this carrier, and which reviewed converter and profile fit it?
|
|
2
|
+
//! The registry is a HINT: a source it does not recognize is stored as it is
|
|
3
|
+
//! (`source::AS_IS`), never refused for being unknown.
|
|
2
4
|
//!
|
|
3
5
|
//! Three separations this file exists to keep:
|
|
4
6
|
//!
|
|
@@ -417,7 +419,8 @@ impl FingerprintRegistry {
|
|
|
417
419
|
Code::UNREGISTERED_FINGERPRINT,
|
|
418
420
|
format!(
|
|
419
421
|
"{what}: key set {} ({} logical keys) matches no reviewed registry entry. \
|
|
420
|
-
A filename never authorizes
|
|
422
|
+
A filename never authorizes: bank the fingerprint under review, or plan \
|
|
423
|
+
the source as-is.",
|
|
421
424
|
fp.keyset_digest, fp.logical_keys
|
|
422
425
|
),
|
|
423
426
|
),
|
|
@@ -237,6 +237,16 @@ pub fn plan_digest(plan: &Plan, headers: &[(PathBuf, &SourceHeader)]) -> String
|
|
|
237
237
|
field(&mut hash, b"swap-halves");
|
|
238
238
|
field(&mut hash, &half_bytes.to_le_bytes());
|
|
239
239
|
}
|
|
240
|
+
Xform::Transpose {
|
|
241
|
+
rows,
|
|
242
|
+
cols,
|
|
243
|
+
elem_bytes,
|
|
244
|
+
} => {
|
|
245
|
+
field(&mut hash, b"transpose");
|
|
246
|
+
for n in [rows, cols, elem_bytes] {
|
|
247
|
+
field(&mut hash, &n.to_le_bytes());
|
|
248
|
+
}
|
|
249
|
+
}
|
|
240
250
|
}
|
|
241
251
|
}
|
|
242
252
|
}
|