Include scalar coupling parameters in Hub size indexing
Browse filesStore the 16 complex scalar coupling values as length-one tensors, recording their names in SafeTensors metadata. Restore the exact original scalar shapes in the loader. This avoids the Hub counter omitting shape=[] parameters. All 296 state tensors again passed byte-for-byte equality and strict native loading on CPU, without CUDA or inference.
Co-Authored-By: Codex <noreply@openai.com>
- README.md +2 -0
- colm_loader.py +9 -0
- conversion_report.json +21 -3
- export_safetensors.py +8 -1
- model.safetensors +2 -2
README.md
CHANGED
|
@@ -125,6 +125,8 @@ prompt_ids = tokenizer.encode("The nature of consciousness")
|
|
| 125 |
|
| 126 |
Both export files are necessary. The loader restores all learned tensors **and the saved fixed matrices**, strips the `_orig_mod.` prefix when loading the original compiled-training checkpoint, and requires an exact match to the native model's state. It does not regenerate the trained checkpoint's mixer state, retrain the model, alter its tokenizer, or compile it automatically.
|
| 127 |
|
|
|
|
|
|
|
| 128 |
To use the original checkpoint instead, download `colm_best_Final.pt` too and call `load_colm(".", weights_format="pt")`. See the [GitHub repository](https://github.com/Eden-Eldith/COLM) for full training, generation, and evaluation scripts.
|
| 129 |
|
| 130 |
### Export Verification
|
|
|
|
| 125 |
|
| 126 |
Both export files are necessary. The loader restores all learned tensors **and the saved fixed matrices**, strips the `_orig_mod.` prefix when loading the original compiled-training checkpoint, and requires an exact match to the native model's state. It does not regenerate the trained checkpoint's mixer state, retrain the model, alter its tokenizer, or compile it automatically.
|
| 127 |
|
| 128 |
+
For Hub size indexing, the 16 scalar coupling parameters are stored as one-element tensors in SafeTensors. Their names are recorded in the file metadata, and the loader restores their original scalar shapes before loading the model. This changes only the storage representation, not the model or its values.
|
| 129 |
+
|
| 130 |
To use the original checkpoint instead, download `colm_best_Final.pt` too and call `load_colm(".", weights_format="pt")`. See the [GitHub repository](https://github.com/Eden-Eldith/COLM) for full training, generation, and evaluation scripts.
|
| 131 |
|
| 132 |
### Export Verification
|
colm_loader.py
CHANGED
|
@@ -7,6 +7,7 @@ from types import SimpleNamespace
|
|
| 7 |
|
| 8 |
import numpy as np
|
| 9 |
import torch
|
|
|
|
| 10 |
from safetensors.torch import load_file
|
| 11 |
|
| 12 |
from model import COLM
|
|
@@ -28,6 +29,14 @@ def safetensors_state(directory):
|
|
| 28 |
"""Both files are required: learned parameters plus saved fixed mixers."""
|
| 29 |
directory = Path(directory)
|
| 30 |
state = load_file(str(directory / "model.safetensors"), device="cpu")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
with np.load(directory / "model_buffers.npz", allow_pickle=False) as archive:
|
| 32 |
for name in archive.files:
|
| 33 |
if name in state:
|
|
|
|
| 7 |
|
| 8 |
import numpy as np
|
| 9 |
import torch
|
| 10 |
+
from safetensors import safe_open
|
| 11 |
from safetensors.torch import load_file
|
| 12 |
|
| 13 |
from model import COLM
|
|
|
|
| 29 |
"""Both files are required: learned parameters plus saved fixed mixers."""
|
| 30 |
directory = Path(directory)
|
| 31 |
state = load_file(str(directory / "model.safetensors"), device="cpu")
|
| 32 |
+
with safe_open(str(directory / "model.safetensors"), framework="pt", device="cpu") as archive:
|
| 33 |
+
metadata = archive.metadata() or {}
|
| 34 |
+
# The Hub counter omits shape=[] tensors. Store these as shape=[1], then
|
| 35 |
+
# restore the original scalar shape before loading the unchanged model.
|
| 36 |
+
for name in json.loads(metadata.get("scalar_parameter_names", "[]")):
|
| 37 |
+
if state[name].shape != (1,):
|
| 38 |
+
raise ValueError(f"Expected a stored length-one scalar: {name}")
|
| 39 |
+
state[name] = state[name].reshape(())
|
| 40 |
with np.load(directory / "model_buffers.npz", allow_pickle=False) as archive:
|
| 41 |
for name in archive.files:
|
| 42 |
if name in state:
|
conversion_report.json
CHANGED
|
@@ -6,6 +6,24 @@
|
|
| 6 |
"checkpoint_validation_loss": 1.144872358441353,
|
| 7 |
"parameter_tensors": 264,
|
| 8 |
"parameter_elements": 498214,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"parameter_elements_by_dtype": {
|
| 10 |
"torch.complex64": 52504,
|
| 11 |
"torch.float32": 445710
|
|
@@ -26,13 +44,13 @@
|
|
| 26 |
"numpy": "2.2.6"
|
| 27 |
},
|
| 28 |
"sha256": {
|
| 29 |
-
"model.safetensors": "
|
| 30 |
"model_buffers.npz": "2715e51c179588c3d74f7c03eec36c4a4b5f0ca658575f6c9e16f406dbcdc815",
|
| 31 |
"model.py": "22066752391c65e4f360402fe8a0064107fefd7512d1c568004d68c621553f4c",
|
| 32 |
"colm_config.json": "fba7681030b2421453f9d7aaa788384e3ffaebaf68aea200bc1c8e1480fa001c",
|
| 33 |
"colm_tokenizer.json": "c28592e50ac0fb8c3094c17bb2159bc325a791727af86c8024a2c5b521b1f4c5",
|
| 34 |
"tokenizer_train.py": "6d03d16913878e0d6e955bde1cb20a58db3f854e57dfb5b97efb0e7c75c684db",
|
| 35 |
-
"colm_loader.py": "
|
| 36 |
-
"export_safetensors.py": "
|
| 37 |
}
|
| 38 |
}
|
|
|
|
| 6 |
"checkpoint_validation_loss": 1.144872358441353,
|
| 7 |
"parameter_tensors": 264,
|
| 8 |
"parameter_elements": 498214,
|
| 9 |
+
"scalar_parameters_stored_as_length_one": [
|
| 10 |
+
"blocks.0.coupling_alpha",
|
| 11 |
+
"blocks.1.coupling_alpha",
|
| 12 |
+
"blocks.10.coupling_alpha",
|
| 13 |
+
"blocks.11.coupling_alpha",
|
| 14 |
+
"blocks.12.coupling_alpha",
|
| 15 |
+
"blocks.13.coupling_alpha",
|
| 16 |
+
"blocks.14.coupling_alpha",
|
| 17 |
+
"blocks.15.coupling_alpha",
|
| 18 |
+
"blocks.2.coupling_alpha",
|
| 19 |
+
"blocks.3.coupling_alpha",
|
| 20 |
+
"blocks.4.coupling_alpha",
|
| 21 |
+
"blocks.5.coupling_alpha",
|
| 22 |
+
"blocks.6.coupling_alpha",
|
| 23 |
+
"blocks.7.coupling_alpha",
|
| 24 |
+
"blocks.8.coupling_alpha",
|
| 25 |
+
"blocks.9.coupling_alpha"
|
| 26 |
+
],
|
| 27 |
"parameter_elements_by_dtype": {
|
| 28 |
"torch.complex64": 52504,
|
| 29 |
"torch.float32": 445710
|
|
|
|
| 44 |
"numpy": "2.2.6"
|
| 45 |
},
|
| 46 |
"sha256": {
|
| 47 |
+
"model.safetensors": "01473b0a6b1b595315552db82f29987f50f7db362425e39ff06f0f4b51fbab80",
|
| 48 |
"model_buffers.npz": "2715e51c179588c3d74f7c03eec36c4a4b5f0ca658575f6c9e16f406dbcdc815",
|
| 49 |
"model.py": "22066752391c65e4f360402fe8a0064107fefd7512d1c568004d68c621553f4c",
|
| 50 |
"colm_config.json": "fba7681030b2421453f9d7aaa788384e3ffaebaf68aea200bc1c8e1480fa001c",
|
| 51 |
"colm_tokenizer.json": "c28592e50ac0fb8c3094c17bb2159bc325a791727af86c8024a2c5b521b1f4c5",
|
| 52 |
"tokenizer_train.py": "6d03d16913878e0d6e955bde1cb20a58db3f854e57dfb5b97efb0e7c75c684db",
|
| 53 |
+
"colm_loader.py": "c6d763efc9bb1aeda99782e966a93900997bee534cc78e43156003ecf8cba264",
|
| 54 |
+
"export_safetensors.py": "4a22a7b9683a1ae669414b7fa9650da558bcbd5db908e60e9d700084ca35cb54"
|
| 55 |
}
|
| 56 |
}
|
export_safetensors.py
CHANGED
|
@@ -65,12 +65,18 @@ def main():
|
|
| 65 |
raise AssertionError("State does not partition into parameters and buffers")
|
| 66 |
parameters = {n: state[n].contiguous() for n in sorted(parameter_names)}
|
| 67 |
buffers = {n: state[n].numpy() for n in sorted(buffer_names)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
save_file(
|
| 70 |
"format": "pt",
|
| 71 |
"source_checkpoint": args.checkpoint.name,
|
| 72 |
"source_sha256": original_hash,
|
| 73 |
"fixed_buffers": "model_buffers.npz",
|
|
|
|
| 74 |
"description": "Native F32/C64 trainable parameters; fixed mixers stored separately.",
|
| 75 |
})
|
| 76 |
np.savez(directory / "model_buffers.npz", **buffers)
|
|
@@ -97,6 +103,7 @@ def main():
|
|
| 97 |
"checkpoint_validation_loss": config["checkpoint"]["validation_loss"],
|
| 98 |
"parameter_tensors": len(parameters),
|
| 99 |
"parameter_elements": sum(counts.values()),
|
|
|
|
| 100 |
"parameter_elements_by_dtype": dict(counts),
|
| 101 |
"real_scalar_degrees_of_freedom": sum(
|
| 102 |
x.numel() * (2 if x.is_complex() else 1) for x in parameters.values()),
|
|
|
|
| 65 |
raise AssertionError("State does not partition into parameters and buffers")
|
| 66 |
parameters = {n: state[n].contiguous() for n in sorted(parameter_names)}
|
| 67 |
buffers = {n: state[n].numpy() for n in sorted(buffer_names)}
|
| 68 |
+
scalar_names = [n for n, value in parameters.items() if value.ndim == 0]
|
| 69 |
+
serialized_parameters = {
|
| 70 |
+
n: value.reshape(1) if n in scalar_names else value
|
| 71 |
+
for n, value in parameters.items()
|
| 72 |
+
}
|
| 73 |
|
| 74 |
+
save_file(serialized_parameters, str(directory / "model.safetensors"), metadata={
|
| 75 |
"format": "pt",
|
| 76 |
"source_checkpoint": args.checkpoint.name,
|
| 77 |
"source_sha256": original_hash,
|
| 78 |
"fixed_buffers": "model_buffers.npz",
|
| 79 |
+
"scalar_parameter_names": json.dumps(scalar_names),
|
| 80 |
"description": "Native F32/C64 trainable parameters; fixed mixers stored separately.",
|
| 81 |
})
|
| 82 |
np.savez(directory / "model_buffers.npz", **buffers)
|
|
|
|
| 103 |
"checkpoint_validation_loss": config["checkpoint"]["validation_loss"],
|
| 104 |
"parameter_tensors": len(parameters),
|
| 105 |
"parameter_elements": sum(counts.values()),
|
| 106 |
+
"scalar_parameters_stored_as_length_one": scalar_names,
|
| 107 |
"parameter_elements_by_dtype": dict(counts),
|
| 108 |
"real_scalar_degrees_of_freedom": sum(
|
| 109 |
x.numel() * (2 if x.is_complex() else 1) for x in parameters.values()),
|
model.safetensors
CHANGED
|
@@ -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:01473b0a6b1b595315552db82f29987f50f7db362425e39ff06f0f4b51fbab80
|
| 3 |
+
size 2226600
|