Publish verified Mamba2-8B Resurface adapter and reproducibility package
Browse files- .gitattributes +0 -34
- LICENSE +674 -0
- README.md +201 -0
- artifacts/source_resurface_v1/adapter_fp16.pt +3 -0
- checksum_manifest.json +173 -0
- docs/PROTOCOL.md +77 -0
- docs/REPRODUCE.md +67 -0
- docs/RESULTS.md +61 -0
- docs/VERIFICATION.md +97 -0
- docs/confirm_manifest.json +1 -0
- docs/prose_train_manifest.json +0 -0
- mamba2_recall/__init__.py +1 -0
- mamba2_recall/calibration.py +47 -0
- mamba2_recall/evaluation.py +190 -0
- mamba2_recall/resurface_data.py +391 -0
- mamba2_recall/resurface_loss.py +179 -0
- mamba2_recall/resurface_native.py +557 -0
- mamba2_recall/runtime.py +235 -0
- pyproject.toml +13 -0
- reports/four_arm_comparison_v1.json +67 -0
- reports/source_resurface_v1_confirm_full.json +0 -0
- reports/source_resurface_v1_train.json +0 -0
- reports/verification_audit_v1.json +2175 -0
- reports/verification_hub_metadata_v1.json +20 -0
- reports/verification_origin_v1.json +48 -0
- reports/verification_replay_v1.json +0 -0
- reports/verification_token_receipts_v1.json +22 -0
- resurface_config.json +68 -0
- scripts/compare_four_arms.py +101 -0
- scripts/evaluate.py +158 -0
- scripts/prepare_data.py +41 -0
- scripts/prepare_prose.py +53 -0
- scripts/train.py +242 -0
- scripts/verify_replay.py +488 -0
.gitattributes
CHANGED
|
@@ -1,35 +1 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE
ADDED
|
@@ -0,0 +1,674 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GNU GENERAL PUBLIC LICENSE
|
| 2 |
+
Version 3, 29 June 2007
|
| 3 |
+
|
| 4 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
| 5 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 6 |
+
of this license document, but changing it is not allowed.
|
| 7 |
+
|
| 8 |
+
Preamble
|
| 9 |
+
|
| 10 |
+
The GNU General Public License is a free, copyleft license for
|
| 11 |
+
software and other kinds of works.
|
| 12 |
+
|
| 13 |
+
The licenses for most software and other practical works are designed
|
| 14 |
+
to take away your freedom to share and change the works. By contrast,
|
| 15 |
+
the GNU General Public License is intended to guarantee your freedom to
|
| 16 |
+
share and change all versions of a program--to make sure it remains free
|
| 17 |
+
software for all its users. We, the Free Software Foundation, use the
|
| 18 |
+
GNU General Public License for most of our software; it applies also to
|
| 19 |
+
any other work released this way by its authors. You can apply it to
|
| 20 |
+
your programs, too.
|
| 21 |
+
|
| 22 |
+
When we speak of free software, we are referring to freedom, not
|
| 23 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 24 |
+
have the freedom to distribute copies of free software (and charge for
|
| 25 |
+
them if you wish), that you receive source code or can get it if you
|
| 26 |
+
want it, that you can change the software or use pieces of it in new
|
| 27 |
+
free programs, and that you know you can do these things.
|
| 28 |
+
|
| 29 |
+
To protect your rights, we need to prevent others from denying you
|
| 30 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
| 31 |
+
certain responsibilities if you distribute copies of the software, or if
|
| 32 |
+
you modify it: responsibilities to respect the freedom of others.
|
| 33 |
+
|
| 34 |
+
For example, if you distribute copies of such a program, whether
|
| 35 |
+
gratis or for a fee, you must pass on to the recipients the same
|
| 36 |
+
freedoms that you received. You must make sure that they, too, receive
|
| 37 |
+
or can get the source code. And you must show them these terms so they
|
| 38 |
+
know their rights.
|
| 39 |
+
|
| 40 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
| 41 |
+
(1) assert copyright on the software, and (2) offer you this License
|
| 42 |
+
giving you legal permission to copy, distribute and/or modify it.
|
| 43 |
+
|
| 44 |
+
For the developers' and authors' protection, the GPL clearly explains
|
| 45 |
+
that there is no warranty for this free software. For both users' and
|
| 46 |
+
authors' sake, the GPL requires that modified versions be marked as
|
| 47 |
+
changed, so that their problems will not be attributed erroneously to
|
| 48 |
+
authors of previous versions.
|
| 49 |
+
|
| 50 |
+
Some devices are designed to deny users access to install or run
|
| 51 |
+
modified versions of the software inside them, although the manufacturer
|
| 52 |
+
can do so. This is fundamentally incompatible with the aim of
|
| 53 |
+
protecting users' freedom to change the software. The systematic
|
| 54 |
+
pattern of such abuse occurs in the area of products for individuals to
|
| 55 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
| 56 |
+
have designed this version of the GPL to prohibit the practice for those
|
| 57 |
+
products. If such problems arise substantially in other domains, we
|
| 58 |
+
stand ready to extend this provision to those domains in future versions
|
| 59 |
+
of the GPL, as needed to protect the freedom of users.
|
| 60 |
+
|
| 61 |
+
Finally, every program is threatened constantly by software patents.
|
| 62 |
+
States should not allow patents to restrict development and use of
|
| 63 |
+
software on general-purpose computers, but in those that do, we wish to
|
| 64 |
+
avoid the special danger that patents applied to a free program could
|
| 65 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
| 66 |
+
patents cannot be used to render the program non-free.
|
| 67 |
+
|
| 68 |
+
The precise terms and conditions for copying, distribution and
|
| 69 |
+
modification follow.
|
| 70 |
+
|
| 71 |
+
TERMS AND CONDITIONS
|
| 72 |
+
|
| 73 |
+
0. Definitions.
|
| 74 |
+
|
| 75 |
+
"This License" refers to version 3 of the GNU General Public License.
|
| 76 |
+
|
| 77 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 78 |
+
works, such as semiconductor masks.
|
| 79 |
+
|
| 80 |
+
"The Program" refers to any copyrightable work licensed under this
|
| 81 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
| 82 |
+
"recipients" may be individuals or organizations.
|
| 83 |
+
|
| 84 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
| 85 |
+
in a fashion requiring copyright permission, other than the making of an
|
| 86 |
+
exact copy. The resulting work is called a "modified version" of the
|
| 87 |
+
earlier work or a work "based on" the earlier work.
|
| 88 |
+
|
| 89 |
+
A "covered work" means either the unmodified Program or a work based
|
| 90 |
+
on the Program.
|
| 91 |
+
|
| 92 |
+
To "propagate" a work means to do anything with it that, without
|
| 93 |
+
permission, would make you directly or secondarily liable for
|
| 94 |
+
infringement under applicable copyright law, except executing it on a
|
| 95 |
+
computer or modifying a private copy. Propagation includes copying,
|
| 96 |
+
distribution (with or without modification), making available to the
|
| 97 |
+
public, and in some countries other activities as well.
|
| 98 |
+
|
| 99 |
+
To "convey" a work means any kind of propagation that enables other
|
| 100 |
+
parties to make or receive copies. Mere interaction with a user through
|
| 101 |
+
a computer network, with no transfer of a copy, is not conveying.
|
| 102 |
+
|
| 103 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
| 104 |
+
to the extent that it includes a convenient and prominently visible
|
| 105 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
| 106 |
+
tells the user that there is no warranty for the work (except to the
|
| 107 |
+
extent that warranties are provided), that licensees may convey the
|
| 108 |
+
work under this License, and how to view a copy of this License. If
|
| 109 |
+
the interface presents a list of user commands or options, such as a
|
| 110 |
+
menu, a prominent item in the list meets this criterion.
|
| 111 |
+
|
| 112 |
+
1. Source Code.
|
| 113 |
+
|
| 114 |
+
The "source code" for a work means the preferred form of the work
|
| 115 |
+
for making modifications to it. "Object code" means any non-source
|
| 116 |
+
form of a work.
|
| 117 |
+
|
| 118 |
+
A "Standard Interface" means an interface that either is an official
|
| 119 |
+
standard defined by a recognized standards body, or, in the case of
|
| 120 |
+
interfaces specified for a particular programming language, one that
|
| 121 |
+
is widely used among developers working in that language.
|
| 122 |
+
|
| 123 |
+
The "System Libraries" of an executable work include anything, other
|
| 124 |
+
than the work as a whole, that (a) is included in the normal form of
|
| 125 |
+
packaging a Major Component, but which is not part of that Major
|
| 126 |
+
Component, and (b) serves only to enable use of the work with that
|
| 127 |
+
Major Component, or to implement a Standard Interface for which an
|
| 128 |
+
implementation is available to the public in source code form. A
|
| 129 |
+
"Major Component", in this context, means a major essential component
|
| 130 |
+
(kernel, window system, and so on) of the specific operating system
|
| 131 |
+
(if any) on which the executable work runs, or a compiler used to
|
| 132 |
+
produce the work, or an object code interpreter used to run it.
|
| 133 |
+
|
| 134 |
+
The "Corresponding Source" for a work in object code form means all
|
| 135 |
+
the source code needed to generate, install, and (for an executable
|
| 136 |
+
work) run the object code and to modify the work, including scripts to
|
| 137 |
+
control those activities. However, it does not include the work's
|
| 138 |
+
System Libraries, or general-purpose tools or generally available free
|
| 139 |
+
programs which are used unmodified in performing those activities but
|
| 140 |
+
which are not part of the work. For example, Corresponding Source
|
| 141 |
+
includes interface definition files associated with source files for
|
| 142 |
+
the work, and the source code for shared libraries and dynamically
|
| 143 |
+
linked subprograms that the work is specifically designed to require,
|
| 144 |
+
such as by intimate data communication or control flow between those
|
| 145 |
+
subprograms and other parts of the work.
|
| 146 |
+
|
| 147 |
+
The Corresponding Source need not include anything that users
|
| 148 |
+
can regenerate automatically from other parts of the Corresponding
|
| 149 |
+
Source.
|
| 150 |
+
|
| 151 |
+
The Corresponding Source for a work in source code form is that
|
| 152 |
+
same work.
|
| 153 |
+
|
| 154 |
+
2. Basic Permissions.
|
| 155 |
+
|
| 156 |
+
All rights granted under this License are granted for the term of
|
| 157 |
+
copyright on the Program, and are irrevocable provided the stated
|
| 158 |
+
conditions are met. This License explicitly affirms your unlimited
|
| 159 |
+
permission to run the unmodified Program. The output from running a
|
| 160 |
+
covered work is covered by this License only if the output, given its
|
| 161 |
+
content, constitutes a covered work. This License acknowledges your
|
| 162 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
| 163 |
+
|
| 164 |
+
You may make, run and propagate covered works that you do not
|
| 165 |
+
convey, without conditions so long as your license otherwise remains
|
| 166 |
+
in force. You may convey covered works to others for the sole purpose
|
| 167 |
+
of having them make modifications exclusively for you, or provide you
|
| 168 |
+
with facilities for running those works, provided that you comply with
|
| 169 |
+
the terms of this License in conveying all material for which you do
|
| 170 |
+
not control copyright. Those thus making or running the covered works
|
| 171 |
+
for you must do so exclusively on your behalf, under your direction
|
| 172 |
+
and control, on terms that prohibit them from making any copies of
|
| 173 |
+
your copyrighted material outside their relationship with you.
|
| 174 |
+
|
| 175 |
+
Conveying under any other circumstances is permitted solely under
|
| 176 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
| 177 |
+
makes it unnecessary.
|
| 178 |
+
|
| 179 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 180 |
+
|
| 181 |
+
No covered work shall be deemed part of an effective technological
|
| 182 |
+
measure under any applicable law fulfilling obligations under article
|
| 183 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 184 |
+
similar laws prohibiting or restricting circumvention of such
|
| 185 |
+
measures.
|
| 186 |
+
|
| 187 |
+
When you convey a covered work, you waive any legal power to forbid
|
| 188 |
+
circumvention of technological measures to the extent such circumvention
|
| 189 |
+
is effected by exercising rights under this License with respect to
|
| 190 |
+
the covered work, and you disclaim any intention to limit operation or
|
| 191 |
+
modification of the work as a means of enforcing, against the work's
|
| 192 |
+
users, your or third parties' legal rights to forbid circumvention of
|
| 193 |
+
technological measures.
|
| 194 |
+
|
| 195 |
+
4. Conveying Verbatim Copies.
|
| 196 |
+
|
| 197 |
+
You may convey verbatim copies of the Program's source code as you
|
| 198 |
+
receive it, in any medium, provided that you conspicuously and
|
| 199 |
+
appropriately publish on each copy an appropriate copyright notice;
|
| 200 |
+
keep intact all notices stating that this License and any
|
| 201 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
| 202 |
+
keep intact all notices of the absence of any warranty; and give all
|
| 203 |
+
recipients a copy of this License along with the Program.
|
| 204 |
+
|
| 205 |
+
You may charge any price or no price for each copy that you convey,
|
| 206 |
+
and you may offer support or warranty protection for a fee.
|
| 207 |
+
|
| 208 |
+
5. Conveying Modified Source Versions.
|
| 209 |
+
|
| 210 |
+
You may convey a work based on the Program, or the modifications to
|
| 211 |
+
produce it from the Program, in the form of source code under the
|
| 212 |
+
terms of section 4, provided that you also meet all of these conditions:
|
| 213 |
+
|
| 214 |
+
a) The work must carry prominent notices stating that you modified
|
| 215 |
+
it, and giving a relevant date.
|
| 216 |
+
|
| 217 |
+
b) The work must carry prominent notices stating that it is
|
| 218 |
+
released under this License and any conditions added under section
|
| 219 |
+
7. This requirement modifies the requirement in section 4 to
|
| 220 |
+
"keep intact all notices".
|
| 221 |
+
|
| 222 |
+
c) You must license the entire work, as a whole, under this
|
| 223 |
+
License to anyone who comes into possession of a copy. This
|
| 224 |
+
License will therefore apply, along with any applicable section 7
|
| 225 |
+
additional terms, to the whole of the work, and all its parts,
|
| 226 |
+
regardless of how they are packaged. This License gives no
|
| 227 |
+
permission to license the work in any other way, but it does not
|
| 228 |
+
invalidate such permission if you have separately received it.
|
| 229 |
+
|
| 230 |
+
d) If the work has interactive user interfaces, each must display
|
| 231 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
| 232 |
+
interfaces that do not display Appropriate Legal Notices, your
|
| 233 |
+
work need not make them do so.
|
| 234 |
+
|
| 235 |
+
A compilation of a covered work with other separate and independent
|
| 236 |
+
works, which are not by their nature extensions of the covered work,
|
| 237 |
+
and which are not combined with it such as to form a larger program,
|
| 238 |
+
in or on a volume of a storage or distribution medium, is called an
|
| 239 |
+
"aggregate" if the compilation and its resulting copyright are not
|
| 240 |
+
used to limit the access or legal rights of the compilation's users
|
| 241 |
+
beyond what the individual works permit. Inclusion of a covered work
|
| 242 |
+
in an aggregate does not cause this License to apply to the other
|
| 243 |
+
parts of the aggregate.
|
| 244 |
+
|
| 245 |
+
6. Conveying Non-Source Forms.
|
| 246 |
+
|
| 247 |
+
You may convey a covered work in object code form under the terms
|
| 248 |
+
of sections 4 and 5, provided that you also convey the
|
| 249 |
+
machine-readable Corresponding Source under the terms of this License,
|
| 250 |
+
in one of these ways:
|
| 251 |
+
|
| 252 |
+
a) Convey the object code in, or embodied in, a physical product
|
| 253 |
+
(including a physical distribution medium), accompanied by the
|
| 254 |
+
Corresponding Source fixed on a durable physical medium
|
| 255 |
+
customarily used for software interchange.
|
| 256 |
+
|
| 257 |
+
b) Convey the object code in, or embodied in, a physical product
|
| 258 |
+
(including a physical distribution medium), accompanied by a
|
| 259 |
+
written offer, valid for at least three years and valid for as
|
| 260 |
+
long as you offer spare parts or customer support for that product
|
| 261 |
+
model, to give anyone who possesses the object code either (1) a
|
| 262 |
+
copy of the Corresponding Source for all the software in the
|
| 263 |
+
product that is covered by this License, on a durable physical
|
| 264 |
+
medium customarily used for software interchange, for a price no
|
| 265 |
+
more than your reasonable cost of physically performing this
|
| 266 |
+
conveying of source, or (2) access to copy the
|
| 267 |
+
Corresponding Source from a network server at no charge.
|
| 268 |
+
|
| 269 |
+
c) Convey individual copies of the object code with a copy of the
|
| 270 |
+
written offer to provide the Corresponding Source. This
|
| 271 |
+
alternative is allowed only occasionally and noncommercially, and
|
| 272 |
+
only if you received the object code with such an offer, in accord
|
| 273 |
+
with subsection 6b.
|
| 274 |
+
|
| 275 |
+
d) Convey the object code by offering access from a designated
|
| 276 |
+
place (gratis or for a charge), and offer equivalent access to the
|
| 277 |
+
Corresponding Source in the same way through the same place at no
|
| 278 |
+
further charge. You need not require recipients to copy the
|
| 279 |
+
Corresponding Source along with the object code. If the place to
|
| 280 |
+
copy the object code is a network server, the Corresponding Source
|
| 281 |
+
may be on a different server (operated by you or a third party)
|
| 282 |
+
that supports equivalent copying facilities, provided you maintain
|
| 283 |
+
clear directions next to the object code saying where to find the
|
| 284 |
+
Corresponding Source. Regardless of what server hosts the
|
| 285 |
+
Corresponding Source, you remain obligated to ensure that it is
|
| 286 |
+
available for as long as needed to satisfy these requirements.
|
| 287 |
+
|
| 288 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
| 289 |
+
you inform other peers where the object code and Corresponding
|
| 290 |
+
Source of the work are being offered to the general public at no
|
| 291 |
+
charge under subsection 6d.
|
| 292 |
+
|
| 293 |
+
A separable portion of the object code, whose source code is excluded
|
| 294 |
+
from the Corresponding Source as a System Library, need not be
|
| 295 |
+
included in conveying the object code work.
|
| 296 |
+
|
| 297 |
+
A "User Product" is either (1) a "consumer product", which means any
|
| 298 |
+
tangible personal property which is normally used for personal, family,
|
| 299 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
| 300 |
+
into a dwelling. In determining whether a product is a consumer product,
|
| 301 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 302 |
+
product received by a particular user, "normally used" refers to a
|
| 303 |
+
typical or common use of that class of product, regardless of the status
|
| 304 |
+
of the particular user or of the way in which the particular user
|
| 305 |
+
actually uses, or expects or is expected to use, the product. A product
|
| 306 |
+
is a consumer product regardless of whether the product has substantial
|
| 307 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
| 308 |
+
the only significant mode of use of the product.
|
| 309 |
+
|
| 310 |
+
"Installation Information" for a User Product means any methods,
|
| 311 |
+
procedures, authorization keys, or other information required to install
|
| 312 |
+
and execute modified versions of a covered work in that User Product from
|
| 313 |
+
a modified version of its Corresponding Source. The information must
|
| 314 |
+
suffice to ensure that the continued functioning of the modified object
|
| 315 |
+
code is in no case prevented or interfered with solely because
|
| 316 |
+
modification has been made.
|
| 317 |
+
|
| 318 |
+
If you convey an object code work under this section in, or with, or
|
| 319 |
+
specifically for use in, a User Product, and the conveying occurs as
|
| 320 |
+
part of a transaction in which the right of possession and use of the
|
| 321 |
+
User Product is transferred to the recipient in perpetuity or for a
|
| 322 |
+
fixed term (regardless of how the transaction is characterized), the
|
| 323 |
+
Corresponding Source conveyed under this section must be accompanied
|
| 324 |
+
by the Installation Information. But this requirement does not apply
|
| 325 |
+
if neither you nor any third party retains the ability to install
|
| 326 |
+
modified object code on the User Product (for example, the work has
|
| 327 |
+
been installed in ROM).
|
| 328 |
+
|
| 329 |
+
The requirement to provide Installation Information does not include a
|
| 330 |
+
requirement to continue to provide support service, warranty, or updates
|
| 331 |
+
for a work that has been modified or installed by the recipient, or for
|
| 332 |
+
the User Product in which it has been modified or installed. Access to a
|
| 333 |
+
network may be denied when the modification itself materially and
|
| 334 |
+
adversely affects the operation of the network or violates the rules and
|
| 335 |
+
protocols for communication across the network.
|
| 336 |
+
|
| 337 |
+
Corresponding Source conveyed, and Installation Information provided,
|
| 338 |
+
in accord with this section must be in a format that is publicly
|
| 339 |
+
documented (and with an implementation available to the public in
|
| 340 |
+
source code form), and must require no special password or key for
|
| 341 |
+
unpacking, reading or copying.
|
| 342 |
+
|
| 343 |
+
7. Additional Terms.
|
| 344 |
+
|
| 345 |
+
"Additional permissions" are terms that supplement the terms of this
|
| 346 |
+
License by making exceptions from one or more of its conditions.
|
| 347 |
+
Additional permissions that are applicable to the entire Program shall
|
| 348 |
+
be treated as though they were included in this License, to the extent
|
| 349 |
+
that they are valid under applicable law. If additional permissions
|
| 350 |
+
apply only to part of the Program, that part may be used separately
|
| 351 |
+
under those permissions, but the entire Program remains governed by
|
| 352 |
+
this License without regard to the additional permissions.
|
| 353 |
+
|
| 354 |
+
When you convey a copy of a covered work, you may at your option
|
| 355 |
+
remove any additional permissions from that copy, or from any part of
|
| 356 |
+
it. (Additional permissions may be written to require their own
|
| 357 |
+
removal in certain cases when you modify the work.) You may place
|
| 358 |
+
additional permissions on material, added by you to a covered work,
|
| 359 |
+
for which you have or can give appropriate copyright permission.
|
| 360 |
+
|
| 361 |
+
Notwithstanding any other provision of this License, for material you
|
| 362 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
| 363 |
+
that material) supplement the terms of this License with terms:
|
| 364 |
+
|
| 365 |
+
a) Disclaiming warranty or limiting liability differently from the
|
| 366 |
+
terms of sections 15 and 16 of this License; or
|
| 367 |
+
|
| 368 |
+
b) Requiring preservation of specified reasonable legal notices or
|
| 369 |
+
author attributions in that material or in the Appropriate Legal
|
| 370 |
+
Notices displayed by works containing it; or
|
| 371 |
+
|
| 372 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
| 373 |
+
requiring that modified versions of such material be marked in
|
| 374 |
+
reasonable ways as different from the original version; or
|
| 375 |
+
|
| 376 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
| 377 |
+
authors of the material; or
|
| 378 |
+
|
| 379 |
+
e) Declining to grant rights under trademark law for use of some
|
| 380 |
+
trade names, trademarks, or service marks; or
|
| 381 |
+
|
| 382 |
+
f) Requiring indemnification of licensors and authors of that
|
| 383 |
+
material by anyone who conveys the material (or modified versions of
|
| 384 |
+
it) with contractual assumptions of liability to the recipient, for
|
| 385 |
+
any liability that these contractual assumptions directly impose on
|
| 386 |
+
those licensors and authors.
|
| 387 |
+
|
| 388 |
+
All other non-permissive additional terms are considered "further
|
| 389 |
+
restrictions" within the meaning of section 10. If the Program as you
|
| 390 |
+
received it, or any part of it, contains a notice stating that it is
|
| 391 |
+
governed by this License along with a term that is a further
|
| 392 |
+
restriction, you may remove that term. If a license document contains
|
| 393 |
+
a further restriction but permits relicensing or conveying under this
|
| 394 |
+
License, you may add to a covered work material governed by the terms
|
| 395 |
+
of that license document, provided that the further restriction does
|
| 396 |
+
not survive such relicensing or conveying.
|
| 397 |
+
|
| 398 |
+
If you add terms to a covered work in accord with this section, you
|
| 399 |
+
must place, in the relevant source files, a statement of the
|
| 400 |
+
additional terms that apply to those files, or a notice indicating
|
| 401 |
+
where to find the applicable terms.
|
| 402 |
+
|
| 403 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
| 404 |
+
form of a separately written license, or stated as exceptions;
|
| 405 |
+
the above requirements apply either way.
|
| 406 |
+
|
| 407 |
+
8. Termination.
|
| 408 |
+
|
| 409 |
+
You may not propagate or modify a covered work except as expressly
|
| 410 |
+
provided under this License. Any attempt otherwise to propagate or
|
| 411 |
+
modify it is void, and will automatically terminate your rights under
|
| 412 |
+
this License (including any patent licenses granted under the third
|
| 413 |
+
paragraph of section 11).
|
| 414 |
+
|
| 415 |
+
However, if you cease all violation of this License, then your
|
| 416 |
+
license from a particular copyright holder is reinstated (a)
|
| 417 |
+
provisionally, unless and until the copyright holder explicitly and
|
| 418 |
+
finally terminates your license, and (b) permanently, if the copyright
|
| 419 |
+
holder fails to notify you of the violation by some reasonable means
|
| 420 |
+
prior to 60 days after the cessation.
|
| 421 |
+
|
| 422 |
+
Moreover, your license from a particular copyright holder is
|
| 423 |
+
reinstated permanently if the copyright holder notifies you of the
|
| 424 |
+
violation by some reasonable means, this is the first time you have
|
| 425 |
+
received notice of violation of this License (for any work) from that
|
| 426 |
+
copyright holder, and you cure the violation prior to 30 days after
|
| 427 |
+
your receipt of the notice.
|
| 428 |
+
|
| 429 |
+
Termination of your rights under this section does not terminate the
|
| 430 |
+
licenses of parties who have received copies or rights from you under
|
| 431 |
+
this License. If your rights have been terminated and not permanently
|
| 432 |
+
reinstated, you do not qualify to receive new licenses for the same
|
| 433 |
+
material under section 10.
|
| 434 |
+
|
| 435 |
+
9. Acceptance Not Required for Having Copies.
|
| 436 |
+
|
| 437 |
+
You are not required to accept this License in order to receive or
|
| 438 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
| 439 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
| 440 |
+
to receive a copy likewise does not require acceptance. However,
|
| 441 |
+
nothing other than this License grants you permission to propagate or
|
| 442 |
+
modify any covered work. These actions infringe copyright if you do
|
| 443 |
+
not accept this License. Therefore, by modifying or propagating a
|
| 444 |
+
covered work, you indicate your acceptance of this License to do so.
|
| 445 |
+
|
| 446 |
+
10. Automatic Licensing of Downstream Recipients.
|
| 447 |
+
|
| 448 |
+
Each time you convey a covered work, the recipient automatically
|
| 449 |
+
receives a license from the original licensors, to run, modify and
|
| 450 |
+
propagate that work, subject to this License. You are not responsible
|
| 451 |
+
for enforcing compliance by third parties with this License.
|
| 452 |
+
|
| 453 |
+
An "entity transaction" is a transaction transferring control of an
|
| 454 |
+
organization, or substantially all assets of one, or subdividing an
|
| 455 |
+
organization, or merging organizations. If propagation of a covered
|
| 456 |
+
work results from an entity transaction, each party to that
|
| 457 |
+
transaction who receives a copy of the work also receives whatever
|
| 458 |
+
licenses to the work the party's predecessor in interest had or could
|
| 459 |
+
give under the previous paragraph, plus a right to possession of the
|
| 460 |
+
Corresponding Source of the work from the predecessor in interest, if
|
| 461 |
+
the predecessor has it or can get it with reasonable efforts.
|
| 462 |
+
|
| 463 |
+
You may not impose any further restrictions on the exercise of the
|
| 464 |
+
rights granted or affirmed under this License. For example, you may
|
| 465 |
+
not impose a license fee, royalty, or other charge for exercise of
|
| 466 |
+
rights granted under this License, and you may not initiate litigation
|
| 467 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 468 |
+
any patent claim is infringed by making, using, selling, offering for
|
| 469 |
+
sale, or importing the Program or any portion of it.
|
| 470 |
+
|
| 471 |
+
11. Patents.
|
| 472 |
+
|
| 473 |
+
A "contributor" is a copyright holder who authorizes use under this
|
| 474 |
+
License of the Program or a work on which the Program is based. The
|
| 475 |
+
work thus licensed is called the contributor's "contributor version".
|
| 476 |
+
|
| 477 |
+
A contributor's "essential patent claims" are all patent claims
|
| 478 |
+
owned or controlled by the contributor, whether already acquired or
|
| 479 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
| 480 |
+
by this License, of making, using, or selling its contributor version,
|
| 481 |
+
but do not include claims that would be infringed only as a
|
| 482 |
+
consequence of further modification of the contributor version. For
|
| 483 |
+
purposes of this definition, "control" includes the right to grant
|
| 484 |
+
patent sublicenses in a manner consistent with the requirements of
|
| 485 |
+
this License.
|
| 486 |
+
|
| 487 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 488 |
+
patent license under the contributor's essential patent claims, to
|
| 489 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 490 |
+
propagate the contents of its contributor version.
|
| 491 |
+
|
| 492 |
+
In the following three paragraphs, a "patent license" is any express
|
| 493 |
+
agreement or commitment, however denominated, not to enforce a patent
|
| 494 |
+
(such as an express permission to practice a patent or covenant not to
|
| 495 |
+
sue for patent infringement). To "grant" such a patent license to a
|
| 496 |
+
party means to make such an agreement or commitment not to enforce a
|
| 497 |
+
patent against the party.
|
| 498 |
+
|
| 499 |
+
If you convey a covered work, knowingly relying on a patent license,
|
| 500 |
+
and the Corresponding Source of the work is not available for anyone
|
| 501 |
+
to copy, free of charge and under the terms of this License, through a
|
| 502 |
+
publicly available network server or other readily accessible means,
|
| 503 |
+
then you must either (1) cause the Corresponding Source to be so
|
| 504 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
| 505 |
+
patent license for this particular work, or (3) arrange, in a manner
|
| 506 |
+
consistent with the requirements of this License, to extend the patent
|
| 507 |
+
license to downstream recipients. "Knowingly relying" means you have
|
| 508 |
+
actual knowledge that, but for the patent license, your conveying the
|
| 509 |
+
covered work in a country, or your recipient's use of the covered work
|
| 510 |
+
in a country, would infringe one or more identifiable patents in that
|
| 511 |
+
country that you have reason to believe are valid.
|
| 512 |
+
|
| 513 |
+
If, pursuant to or in connection with a single transaction or
|
| 514 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 515 |
+
covered work, and grant a patent license to some of the parties
|
| 516 |
+
receiving the covered work authorizing them to use, propagate, modify
|
| 517 |
+
or convey a specific copy of the covered work, then the patent license
|
| 518 |
+
you grant is automatically extended to all recipients of the covered
|
| 519 |
+
work and works based on it.
|
| 520 |
+
|
| 521 |
+
A patent license is "discriminatory" if it does not include within
|
| 522 |
+
the scope of its coverage, prohibits the exercise of, or is
|
| 523 |
+
conditioned on the non-exercise of one or more of the rights that are
|
| 524 |
+
specifically granted under this License. You may not convey a covered
|
| 525 |
+
work if you are a party to an arrangement with a third party that is
|
| 526 |
+
in the business of distributing software, under which you make payment
|
| 527 |
+
to the third party based on the extent of your activity of conveying
|
| 528 |
+
the work, and under which the third party grants, to any of the
|
| 529 |
+
parties who would receive the covered work from you, a discriminatory
|
| 530 |
+
patent license (a) in connection with copies of the covered work
|
| 531 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
| 532 |
+
for and in connection with specific products or compilations that
|
| 533 |
+
contain the covered work, unless you entered into that arrangement,
|
| 534 |
+
or that patent license was granted, prior to 28 March 2007.
|
| 535 |
+
|
| 536 |
+
Nothing in this License shall be construed as excluding or limiting
|
| 537 |
+
any implied license or other defenses to infringement that may
|
| 538 |
+
otherwise be available to you under applicable patent law.
|
| 539 |
+
|
| 540 |
+
12. No Surrender of Others' Freedom.
|
| 541 |
+
|
| 542 |
+
If conditions are imposed on you (whether by court order, agreement or
|
| 543 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 544 |
+
excuse you from the conditions of this License. If you cannot convey a
|
| 545 |
+
covered work so as to satisfy simultaneously your obligations under this
|
| 546 |
+
License and any other pertinent obligations, then as a consequence you may
|
| 547 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
| 548 |
+
to collect a royalty for further conveying from those to whom you convey
|
| 549 |
+
the Program, the only way you could satisfy both those terms and this
|
| 550 |
+
License would be to refrain entirely from conveying the Program.
|
| 551 |
+
|
| 552 |
+
13. Use with the GNU Affero General Public License.
|
| 553 |
+
|
| 554 |
+
Notwithstanding any other provision of this License, you have
|
| 555 |
+
permission to link or combine any covered work with a work licensed
|
| 556 |
+
under version 3 of the GNU Affero General Public License into a single
|
| 557 |
+
combined work, and to convey the resulting work. The terms of this
|
| 558 |
+
License will continue to apply to the part which is the covered work,
|
| 559 |
+
but the special requirements of the GNU Affero General Public License,
|
| 560 |
+
section 13, concerning interaction through a network will apply to the
|
| 561 |
+
combination as such.
|
| 562 |
+
|
| 563 |
+
14. Revised Versions of this License.
|
| 564 |
+
|
| 565 |
+
The Free Software Foundation may publish revised and/or new versions of
|
| 566 |
+
the GNU General Public License from time to time. Such new versions will
|
| 567 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 568 |
+
address new problems or concerns.
|
| 569 |
+
|
| 570 |
+
Each version is given a distinguishing version number. If the
|
| 571 |
+
Program specifies that a certain numbered version of the GNU General
|
| 572 |
+
Public License "or any later version" applies to it, you have the
|
| 573 |
+
option of following the terms and conditions either of that numbered
|
| 574 |
+
version or of any later version published by the Free Software
|
| 575 |
+
Foundation. If the Program does not specify a version number of the
|
| 576 |
+
GNU General Public License, you may choose any version ever published
|
| 577 |
+
by the Free Software Foundation.
|
| 578 |
+
|
| 579 |
+
If the Program specifies that a proxy can decide which future
|
| 580 |
+
versions of the GNU General Public License can be used, that proxy's
|
| 581 |
+
public statement of acceptance of a version permanently authorizes you
|
| 582 |
+
to choose that version for the Program.
|
| 583 |
+
|
| 584 |
+
Later license versions may give you additional or different
|
| 585 |
+
permissions. However, no additional obligations are imposed on any
|
| 586 |
+
author or copyright holder as a result of your choosing to follow a
|
| 587 |
+
later version.
|
| 588 |
+
|
| 589 |
+
15. Disclaimer of Warranty.
|
| 590 |
+
|
| 591 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 592 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 593 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 594 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 595 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 596 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 597 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 598 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 599 |
+
|
| 600 |
+
16. Limitation of Liability.
|
| 601 |
+
|
| 602 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 603 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 604 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 605 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 606 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 607 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 608 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 609 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 610 |
+
SUCH DAMAGES.
|
| 611 |
+
|
| 612 |
+
17. Interpretation of Sections 15 and 16.
|
| 613 |
+
|
| 614 |
+
If the disclaimer of warranty and limitation of liability provided
|
| 615 |
+
above cannot be given local legal effect according to their terms,
|
| 616 |
+
reviewing courts shall apply local law that most closely approximates
|
| 617 |
+
an absolute waiver of all civil liability in connection with the
|
| 618 |
+
Program, unless a warranty or assumption of liability accompanies a
|
| 619 |
+
copy of the Program in return for a fee.
|
| 620 |
+
|
| 621 |
+
END OF TERMS AND CONDITIONS
|
| 622 |
+
|
| 623 |
+
How to Apply These Terms to Your New Programs
|
| 624 |
+
|
| 625 |
+
If you develop a new program, and you want it to be of the greatest
|
| 626 |
+
possible use to the public, the best way to achieve this is to make it
|
| 627 |
+
free software which everyone can redistribute and change under these terms.
|
| 628 |
+
|
| 629 |
+
To do so, attach the following notices to the program. It is safest
|
| 630 |
+
to attach them to the start of each source file to most effectively
|
| 631 |
+
state the exclusion of warranty; and each file should have at least
|
| 632 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 633 |
+
|
| 634 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 635 |
+
Copyright (C) <year> <name of author>
|
| 636 |
+
|
| 637 |
+
This program is free software: you can redistribute it and/or modify
|
| 638 |
+
it under the terms of the GNU General Public License as published by
|
| 639 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 640 |
+
(at your option) any later version.
|
| 641 |
+
|
| 642 |
+
This program is distributed in the hope that it will be useful,
|
| 643 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 644 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 645 |
+
GNU General Public License for more details.
|
| 646 |
+
|
| 647 |
+
You should have received a copy of the GNU General Public License
|
| 648 |
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
| 649 |
+
|
| 650 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 651 |
+
|
| 652 |
+
If the program does terminal interaction, make it output a short
|
| 653 |
+
notice like this when it starts in an interactive mode:
|
| 654 |
+
|
| 655 |
+
<program> Copyright (C) <year> <name of author>
|
| 656 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 657 |
+
This is free software, and you are welcome to redistribute it
|
| 658 |
+
under certain conditions; type `show c' for details.
|
| 659 |
+
|
| 660 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 661 |
+
parts of the General Public License. Of course, your program's commands
|
| 662 |
+
might be different; for a GUI interface, you would use an "about box".
|
| 663 |
+
|
| 664 |
+
You should also get your employer (if you work as a programmer) or school,
|
| 665 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 666 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
| 667 |
+
<https://www.gnu.org/licenses/>.
|
| 668 |
+
|
| 669 |
+
The GNU General Public License does not permit incorporating your program
|
| 670 |
+
into proprietary programs. If your program is a subroutine library, you
|
| 671 |
+
may consider it more useful to permit linking proprietary applications with
|
| 672 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
| 673 |
+
Public License instead of this License. But first, please read
|
| 674 |
+
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: gpl-3.0
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
base_model: nvidia/mamba2-8b-3t-4k
|
| 6 |
+
base_model_relation: adapter
|
| 7 |
+
pipeline_tag: text-generation
|
| 8 |
+
inference: false
|
| 9 |
+
tags:
|
| 10 |
+
- mamba2
|
| 11 |
+
- state-space-model
|
| 12 |
+
- adapter
|
| 13 |
+
- resurface
|
| 14 |
+
- recall
|
| 15 |
+
- custom-runtime
|
| 16 |
+
datasets:
|
| 17 |
+
- Salesforce/wikitext
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
# Mamb2_8B_Recall
|
| 21 |
+
|
| 22 |
+
A **post-D Resurface-style readout adapter** for the uncompressed, pure
|
| 23 |
+
[`nvidia/mamba2-8b-3t-4k`](https://huggingface.co/nvidia/mamba2-8b-3t-4k)
|
| 24 |
+
language model. On the verified evaluation protocol, normal numeric multi-key
|
| 25 |
+
recall improved from **147/384 (38.28%) to 365/384 (95.05%)**, while WikiText-2
|
| 26 |
+
validation perplexity improved from **7.3341759473 to 7.0520635156**.
|
| 27 |
+
|
| 28 |
+
This repository distributes the **2,374,143-byte adapter**, with 1,154,104 FP16
|
| 29 |
+
parameters. Inference requires the separately downloaded 8B base weights and
|
| 30 |
+
the custom native runtime. The adapter is not a standalone 2.37 MB language
|
| 31 |
+
model, a PEFT checkpoint, or an `AutoModel.from_pretrained` package.
|
| 32 |
+
|
| 33 |
+
Source and reproduction code:
|
| 34 |
+
[`EndlessChasing/mamb2_8B_Recall`](https://github.com/EndlessChasing/mamb2_8B_Recall/tree/4478c034aff9e5dab7af47efa84214287824138d),
|
| 35 |
+
pinned at commit `4478c034aff9e5dab7af47efa84214287824138d`.
|
| 36 |
+
|
| 37 |
+
## Verified results
|
| 38 |
+
|
| 39 |
+
| Model | WikiText-2 validation PPL | Normal MK | N=16 | N=64 | Target removed |
|
| 40 |
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
| 41 |
+
| Base model in FP16 runtime | 7.334175947318572 | 147/384 (38.28%) | 113/192 | 34/192 | 0/384 |
|
| 42 |
+
| Base model + this adapter | **7.052063515606311** | **365/384 (95.05%)** | **191/192** | **174/192** | 0/384 |
|
| 43 |
+
|
| 44 |
+
PPL covers all **130 reset windows**, up to 2,048 next-token targets per window,
|
| 45 |
+
and **264,764 targets** in the pinned WikiText-2 validation split. Each window
|
| 46 |
+
starts with zero state and uses parallel SSD scan computation. MK uses three
|
| 47 |
+
synthetic numeric templates, 16 or 64 key/value bindings, and prompt lengths
|
| 48 |
+
of 257–1,236 tokens. Generation is greedy, at most 12 new tokens, over the full
|
| 49 |
+
256K vocabulary; scoring matches the first standalone six-digit integer.
|
| 50 |
+
The 384 normal prompts have 384 paired target-removed controls. MK uses native
|
| 51 |
+
prefill followed by recurrent decoding with fresh FP16 cache.
|
| 52 |
+
|
| 53 |
+
A fresh public GitHub clone was replayed on an RTX PRO 6000 Blackwell on
|
| 54 |
+
2026-09-28. Across the two arms, all **260 per-window NLLs and 1,536 MK
|
| 55 |
+
generation records matched exactly**. An independent audit recalculated the
|
| 56 |
+
metrics, decoded generated token IDs and checked regenerated input identities.
|
| 57 |
+
See the [verification report](https://github.com/EndlessChasing/mamb2_8B_Recall/blob/4478c034aff9e5dab7af47efa84214287824138d/docs/VERIFICATION.md)
|
| 58 |
+
and its linked raw receipts.
|
| 59 |
+
|
| 60 |
+
## Method and training
|
| 61 |
+
|
| 62 |
+
The base has 56 Mamba2 blocks, 8 SSM groups, 8,236,999,680 parameters, and no
|
| 63 |
+
attention or MoE blocks. Its official BF16 weights are cast to FP16 by the
|
| 64 |
+
native runtime and frozen. The adapter modifies readout at the gated RMSNorm
|
| 65 |
+
inputs, after the D skip term, with a learned head-mixing residual and a soft
|
| 66 |
+
sigmoid gate. The same gate operates on prose and recall inputs. It adds no
|
| 67 |
+
recurrent cache.
|
| 68 |
+
|
| 69 |
+
This is a Resurface-style adaptation based on the
|
| 70 |
+
[Resurface reference](https://github.com/Oso1106/Resurface-Multi-Binding-Recall-Is-Latent-in-Mamba-s-State),
|
| 71 |
+
with a different insertion site. It is not an exact reproduction of the
|
| 72 |
+
reference's private checkpoint, data or code.
|
| 73 |
+
|
| 74 |
+
Training completed 1,536 successful AdamW updates with FP32 adapter masters,
|
| 75 |
+
one pass over 1,536 synthetic numeric TRAIN examples, and paired prose from
|
| 76 |
+
448 pinned WikiText-2 TRAIN windows. The objective combines recall answer CE,
|
| 77 |
+
prose CE, KL to a separately loaded frozen base teacher, and a prose gate
|
| 78 |
+
closure penalty. Six overflow retries occurred within the declared budget.
|
| 79 |
+
The final step was the sole candidate. Full settings and source hashes are
|
| 80 |
+
in the [frozen protocol](https://github.com/EndlessChasing/mamb2_8B_Recall/blob/4478c034aff9e5dab7af47efa84214287824138d/docs/PROTOCOL.md).
|
| 81 |
+
|
| 82 |
+
## Download and use
|
| 83 |
+
|
| 84 |
+
Use a Linux CUDA environment. The tested environment was Python 3.10.12,
|
| 85 |
+
PyTorch 2.11.0+cu128, Mamba-SSM 2.3.2.post1, Triton 3.6.0, NumPy 1.26.4,
|
| 86 |
+
datasets 4.8.5 and SentencePiece 0.2.1. Install CUDA-compatible PyTorch first;
|
| 87 |
+
building Mamba-SSM requires a matching CUDA toolkit/compiler.
|
| 88 |
+
|
| 89 |
+
```bash
|
| 90 |
+
# Download the small adapter, runtime, scripts and verification receipts.
|
| 91 |
+
hf download EndlessChasing/Mamb2_8B_Recall --local-dir mamb2-recall
|
| 92 |
+
cd mamb2-recall
|
| 93 |
+
python -m pip install -e .
|
| 94 |
+
python -m pip install --no-build-isolation 'mamba-ssm==2.3.2.post1'
|
| 95 |
+
|
| 96 |
+
# Separately download the original checkpoint and tokenizer (~16.48 GB).
|
| 97 |
+
hf download nvidia/mamba2-8b-3t-4k \
|
| 98 |
+
release/mp_rank_00/model_optim_rng.pt \
|
| 99 |
+
mt_nlg_plus_multilingual_ja_zh_the_stack_frac_015_256k.model \
|
| 100 |
+
--revision b915550c63ba9359f88f44d1f6a600d85af27302 \
|
| 101 |
+
--local-dir models/source
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
The base loader verifies its pinned checkpoint/tokenizer hashes. Verify the
|
| 105 |
+
adapter and use the project's runtime explicitly:
|
| 106 |
+
|
| 107 |
+
```python
|
| 108 |
+
from pathlib import Path
|
| 109 |
+
import hashlib
|
| 110 |
+
import torch
|
| 111 |
+
from mamba2_recall import runtime, resurface_native
|
| 112 |
+
from mamba2_recall.evaluation import generate_greedy
|
| 113 |
+
|
| 114 |
+
adapter = Path("artifacts/source_resurface_v1/adapter_fp16.pt")
|
| 115 |
+
assert hashlib.sha256(adapter.read_bytes()).hexdigest() == (
|
| 116 |
+
"e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0"
|
| 117 |
+
)
|
| 118 |
+
torch.backends.cuda.matmul.allow_tf32 = False
|
| 119 |
+
torch.set_float32_matmul_precision("highest")
|
| 120 |
+
tokenizer = runtime.SentencePieceTokenizer("models/source")
|
| 121 |
+
model = runtime.load_source_model("models/source")
|
| 122 |
+
payload = resurface_native.read_fp16(adapter)
|
| 123 |
+
assert payload["binding"]["source_checkpoint_sha256"] == runtime.SOURCE_CHECKPOINT_SHA256
|
| 124 |
+
|
| 125 |
+
prompt = "Key-value records:\n123456: 654321\n234567: 765432\n\nLookup the value for key 123456.\nValue:"
|
| 126 |
+
with resurface_native.install_fp16(
|
| 127 |
+
model, adapter, expected_binding=payload["binding"]
|
| 128 |
+
):
|
| 129 |
+
text, token_ids, prompt_tokens, cache_bytes = generate_greedy(
|
| 130 |
+
model, tokenizer, prompt, max_new_tokens=12, execution="prefill"
|
| 131 |
+
)
|
| 132 |
+
print(text)
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
This example shows the loading API; the small example prompt is not a reported
|
| 136 |
+
benchmark result. Measured peak PyTorch CUDA allocation during paired
|
| 137 |
+
evaluation was **17.08 GB** and during two-model training was **34.59 GB**.
|
| 138 |
+
These measurements exclude some device and host overhead and are not minimum
|
| 139 |
+
hardware requirements. Full base weights remain resident during inference.
|
| 140 |
+
|
| 141 |
+
## Reproduce PPL and MK
|
| 142 |
+
|
| 143 |
+
From the downloaded repository after the commands above:
|
| 144 |
+
|
| 145 |
+
```bash
|
| 146 |
+
CUDA_VISIBLE_DEVICES= python scripts/prepare_data.py \
|
| 147 |
+
--split confirm --source-dir models/source
|
| 148 |
+
confirm_manifest_sha=$(python -c "import hashlib; from pathlib import Path; print(hashlib.sha256(Path('training_data/numeric_v1/confirm/manifest.json').read_bytes()).hexdigest())")
|
| 149 |
+
python scripts/evaluate.py \
|
| 150 |
+
--source-dir models/source \
|
| 151 |
+
--adapter artifacts/source_resurface_v1/adapter_fp16.pt \
|
| 152 |
+
--data-root training_data/numeric_v1 \
|
| 153 |
+
--eval-manifest-sha256 "$confirm_manifest_sha" \
|
| 154 |
+
--split confirm \
|
| 155 |
+
--report reports/hf_adapter_evaluation.json
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
This evaluates the base and serialized adapter in the same process, with full
|
| 159 |
+
PPL and both MK conditions, then checks baseline restoration after removing
|
| 160 |
+
the adapter. The output path must be new. The preparation script and evaluator
|
| 161 |
+
validate frozen data content; use the newly generated manifest's SHA because
|
| 162 |
+
its Python build metadata may vary. See the
|
| 163 |
+
[reproduction guide](https://github.com/EndlessChasing/mamb2_8B_Recall/blob/4478c034aff9e5dab7af47efa84214287824138d/docs/REPRODUCE.md)
|
| 164 |
+
for training and the independent saved-report audit.
|
| 165 |
+
|
| 166 |
+
`resurface_config.json` describes this custom adapter format and its base
|
| 167 |
+
binding; it is not a Transformers or PEFT configuration. The release includes
|
| 168 |
+
`checksum_manifest.json` for checking its packaged files.
|
| 169 |
+
|
| 170 |
+
## Limitations
|
| 171 |
+
|
| 172 |
+
- The numeric CONFIRM instances/template family and WikiText-2 validation
|
| 173 |
+
corpus had been observed during earlier project development. The reported
|
| 174 |
+
results establish performance on this specified replay protocol, rather
|
| 175 |
+
than an untouched holdout. TRAIN and CONFIRM numeric identities were
|
| 176 |
+
separately checked to be disjoint.
|
| 177 |
+
- Unseen template families, longer recall distances, full 4K recall, other
|
| 178 |
+
languages, broad downstream task quality and untouched prose have not been
|
| 179 |
+
established by these measurements.
|
| 180 |
+
- Target-removed 0/384 means the absent answer was not recovered; it does not
|
| 181 |
+
measure calibrated refusal behavior.
|
| 182 |
+
- The runtime casts the official BF16 source to FP16. Native Megatron BF16
|
| 183 |
+
parity and tokenwise FP16-state-rounding PPL have not been established.
|
| 184 |
+
- Exact replay was observed in the recorded environment. Other GPU, CUDA,
|
| 185 |
+
PyTorch or Mamba kernel versions can change numerical outputs.
|
| 186 |
+
- The published adapter is bound to the specified uncompressed source.
|
| 187 |
+
Transfer to a quantized or different checkpoint needs separate validation.
|
| 188 |
+
|
| 189 |
+
## License and attribution
|
| 190 |
+
|
| 191 |
+
The `gpl-3.0` card metadata reflects this release's existing GitHub repository
|
| 192 |
+
license; see the bundled `LICENSE`. The custom runtime derives from the
|
| 193 |
+
associated [E8/W5 project](https://github.com/EndlessChasing/mamba2-8b-e8w5).
|
| 194 |
+
The original NVIDIA model is downloaded separately under its Apache-2.0
|
| 195 |
+
license, and its own model card and terms apply to those base weights.
|
| 196 |
+
This release does not redistribute those weights. The metadata does not
|
| 197 |
+
relicense the NVIDIA model or create an additional adapter-specific license.
|
| 198 |
+
|
| 199 |
+
Method credit: [Resurface — Multi-Binding Recall Is Latent in Mamba's State](https://github.com/Oso1106/Resurface-Multi-Binding-Recall-Is-Latent-in-Mamba-s-State).
|
| 200 |
+
Implementation and experiment details are available in the pinned GitHub
|
| 201 |
+
repository linked above.
|
artifacts/source_resurface_v1/adapter_fp16.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0
|
| 3 |
+
size 2374143
|
checksum_manifest.json
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "MAMBA2_RESURFACE_HF_CHECKSUM_MANIFEST_V1",
|
| 3 |
+
"repo_id": "EndlessChasing/Mamb2_8B_Recall",
|
| 4 |
+
"source_commit": "4478c034aff9e5dab7af47efa84214287824138d",
|
| 5 |
+
"scope": "All distributed files except this checksum manifest itself",
|
| 6 |
+
"files": [
|
| 7 |
+
{
|
| 8 |
+
"path": ".gitattributes",
|
| 9 |
+
"bytes": 41,
|
| 10 |
+
"sha256": "4009e8f5faf67ca3607a646c9b12350d8237e344e6853c59bf9dbad697db3952"
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"path": "LICENSE",
|
| 14 |
+
"bytes": 35149,
|
| 15 |
+
"sha256": "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986"
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"path": "README.md",
|
| 19 |
+
"bytes": 9722,
|
| 20 |
+
"sha256": "6cccc0796a4e8e843fd1c086298fff0b6b9b57f7cf6d93e518942be3cbcb8519"
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"path": "artifacts/source_resurface_v1/adapter_fp16.pt",
|
| 24 |
+
"bytes": 2374143,
|
| 25 |
+
"sha256": "e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0"
|
| 26 |
+
},
|
| 27 |
+
{
|
| 28 |
+
"path": "docs/PROTOCOL.md",
|
| 29 |
+
"bytes": 4537,
|
| 30 |
+
"sha256": "dee9457bfaca067b63837dcd3bc94bf9ef9a3d805b1ab04227db05a4b92c54c2"
|
| 31 |
+
},
|
| 32 |
+
{
|
| 33 |
+
"path": "docs/REPRODUCE.md",
|
| 34 |
+
"bytes": 3393,
|
| 35 |
+
"sha256": "8e993bc5745875e16580d41ad3f47345c137ef5c50834435f931902bc533556c"
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"path": "docs/RESULTS.md",
|
| 39 |
+
"bytes": 3620,
|
| 40 |
+
"sha256": "16cbb30bb287abfffa01b52948b4f7afcd195257d294848610c9ad4924165e16"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"path": "docs/VERIFICATION.md",
|
| 44 |
+
"bytes": 5405,
|
| 45 |
+
"sha256": "53e16aace1f7eb0f7da9c1c313fcc58a3bbc8873f3a75b984a820bf84f18efa9"
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"path": "docs/confirm_manifest.json",
|
| 49 |
+
"bytes": 2411,
|
| 50 |
+
"sha256": "227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c"
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"path": "docs/prose_train_manifest.json",
|
| 54 |
+
"bytes": 126611,
|
| 55 |
+
"sha256": "facb2ca461615a4199781bd21784d642d6674f5b862641b3b9edac3fb499b89d"
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"path": "mamba2_recall/__init__.py",
|
| 59 |
+
"bytes": 56,
|
| 60 |
+
"sha256": "79b32606ac476c3248911c55571bf97f96689770067856ce8347837478ef33fd"
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"path": "mamba2_recall/calibration.py",
|
| 64 |
+
"bytes": 1941,
|
| 65 |
+
"sha256": "54e178521abfe2513fb7bac2aed2ef178fc01b63135222ecc212001ee3ce0a04"
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"path": "mamba2_recall/evaluation.py",
|
| 69 |
+
"bytes": 10299,
|
| 70 |
+
"sha256": "95cba0b201e37f92e6cbfadb9b3e9d79ba7b0cdc9efda6a58a6216b0d84d35e0"
|
| 71 |
+
},
|
| 72 |
+
{
|
| 73 |
+
"path": "mamba2_recall/resurface_data.py",
|
| 74 |
+
"bytes": 21740,
|
| 75 |
+
"sha256": "1a547fe3cedca406d6e3db85f65c3ce554558691e3b29b9c92d8fd6bd1c1ba35"
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"path": "mamba2_recall/resurface_loss.py",
|
| 79 |
+
"bytes": 10656,
|
| 80 |
+
"sha256": "ec045368583b6e49f484341b2d718658bb59e8d11050710377742752c1c67294"
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"path": "mamba2_recall/resurface_native.py",
|
| 84 |
+
"bytes": 28603,
|
| 85 |
+
"sha256": "2dd08c7ee8958c832f0ae9da7cf5f261dceeff3e528e493c905c7c52df7166d7"
|
| 86 |
+
},
|
| 87 |
+
{
|
| 88 |
+
"path": "mamba2_recall/runtime.py",
|
| 89 |
+
"bytes": 9912,
|
| 90 |
+
"sha256": "73a405b4286dda403f252cf0b73d367adcfead96298a1e6f440b65f5b309530c"
|
| 91 |
+
},
|
| 92 |
+
{
|
| 93 |
+
"path": "pyproject.toml",
|
| 94 |
+
"bytes": 398,
|
| 95 |
+
"sha256": "6378c4de2788a21d36d6e5a96aba9c2277158c9eb1ff3252d8e155f6a998da0b"
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"path": "reports/four_arm_comparison_v1.json",
|
| 99 |
+
"bytes": 1965,
|
| 100 |
+
"sha256": "d4b75b7a68028e36e93130cd31d3400442fb83e4bff30f67a011702598983e20"
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"path": "reports/source_resurface_v1_confirm_full.json",
|
| 104 |
+
"bytes": 1123173,
|
| 105 |
+
"sha256": "4c99694d66af1db71924bd9d3113f1ea2f0a9b93191ed229f3d26f2320c8c940"
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"path": "reports/source_resurface_v1_train.json",
|
| 109 |
+
"bytes": 837067,
|
| 110 |
+
"sha256": "72c5c46ffff8e9981b8747a2fe10cb9ab67695d1555f2deb43d497ec7caed5e1"
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"path": "reports/verification_audit_v1.json",
|
| 114 |
+
"bytes": 53942,
|
| 115 |
+
"sha256": "16ab2fcf54b3786554b9d45770c1818f715d54c6fc0d61a295aa38cffd17ca91"
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"path": "reports/verification_hub_metadata_v1.json",
|
| 119 |
+
"bytes": 739,
|
| 120 |
+
"sha256": "194839dc297df34b749a69d7ddfd9b4f62c3d733b0918e43eddad6cf6b76bbd8"
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"path": "reports/verification_origin_v1.json",
|
| 124 |
+
"bytes": 2286,
|
| 125 |
+
"sha256": "53fdecf6395bf9ebdf2d0e04be816ba0906aab4f1df761c088aac6fc85f852e6"
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"path": "reports/verification_replay_v1.json",
|
| 129 |
+
"bytes": 1123172,
|
| 130 |
+
"sha256": "a83faedb5f25150ff8c3bf93a312619c11191e5dd06677d236cb7658c8173779"
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"path": "reports/verification_token_receipts_v1.json",
|
| 134 |
+
"bytes": 827,
|
| 135 |
+
"sha256": "ec95ed2c5a1bfb04a9aa0f538cf2f9c5fd881549e012cc26bbf67736b8ae1d6f"
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"path": "resurface_config.json",
|
| 139 |
+
"bytes": 2903,
|
| 140 |
+
"sha256": "08f481f3218092abd1d1b68935ca641dd1239b80ffd25e9b3ac96dd4655ac96d"
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"path": "scripts/compare_four_arms.py",
|
| 144 |
+
"bytes": 5376,
|
| 145 |
+
"sha256": "6e41f9ab4f6e39c5a23da6ad1edc29e5b10da57e93e2ea008f4d153c8f195e3b"
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"path": "scripts/evaluate.py",
|
| 149 |
+
"bytes": 8114,
|
| 150 |
+
"sha256": "825acc58d957abe9c755b44c783970c7a379594dfd15e0a67f0ff9a0638f74bb"
|
| 151 |
+
},
|
| 152 |
+
{
|
| 153 |
+
"path": "scripts/prepare_data.py",
|
| 154 |
+
"bytes": 1815,
|
| 155 |
+
"sha256": "11d5e6872382fb8a62987937ec37006422b38e4b1650431a4794d5834c6a4604"
|
| 156 |
+
},
|
| 157 |
+
{
|
| 158 |
+
"path": "scripts/prepare_prose.py",
|
| 159 |
+
"bytes": 2371,
|
| 160 |
+
"sha256": "f63659bab565f2428629f2c9239ba2bdb4ccfb6c647accc44be71b2f419a7c7e"
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"path": "scripts/train.py",
|
| 164 |
+
"bytes": 12177,
|
| 165 |
+
"sha256": "3ea5ef8beadf5d4f14650e9fe15949cd6116e247ddd7641d7f024c5763aa8eb2"
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"path": "scripts/verify_replay.py",
|
| 169 |
+
"bytes": 28920,
|
| 170 |
+
"sha256": "8b08f0e9f8e8f5239764646e44c816dfb8ba9987ffb1c6dd936aea90ed652b2f"
|
| 171 |
+
}
|
| 172 |
+
]
|
| 173 |
+
}
|
docs/PROTOCOL.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Full precision Mamba2-8B Resurface control
|
| 2 |
+
|
| 3 |
+
Declared 2026-09-28 before fitting this repository's adapter. The purpose is to
|
| 4 |
+
measure the effect of the same readout adapter and training budget on NVIDIA's
|
| 5 |
+
uncompressed pure Mamba2-8B. The E8/W5 experiment is a historical comparator,
|
| 6 |
+
not a training dependency. All metrics are reported at the actually measured
|
| 7 |
+
precision and protocol, without assuming equality to native Megatron BF16.
|
| 8 |
+
|
| 9 |
+
## Frozen model and intervention
|
| 10 |
+
|
| 11 |
+
Load `nvidia/mamba2-8b-3t-4k` revision
|
| 12 |
+
`b915550c63ba9359f88f44d1f6a600d85af27302`, checkpoint SHA256
|
| 13 |
+
`47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb`
|
| 14 |
+
and tokenizer SHA256
|
| 15 |
+
`5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09`.
|
| 16 |
+
Cast the 507 original BF16 tensors to FP16 in the native state-spaces Mamba2
|
| 17 |
+
runtime; freeze all 8,236,999,680 base parameters. Verify strict source tensor
|
| 18 |
+
mapping, model geometry and no shared embedding/output storage.
|
| 19 |
+
|
| 20 |
+
Use the same post-D adapter as the compressed experiment at all 56 native
|
| 21 |
+
gated RMSNorm inputs: `y + sigmoid(w dot u+b) * g*(V@y)` across 128 heads.
|
| 22 |
+
Its 224 tensors contain 1,154,104 FP32 trainable master parameters, exported
|
| 23 |
+
as FP16 for inference. Initialize V=0, g=1, w=0, b=-4; use soft sigmoid at
|
| 24 |
+
train and eval, no task switch, EMA, or new recurrent cache. The adapter is
|
| 25 |
+
external to the frozen base; check its identities and absence of base grads.
|
| 26 |
+
|
| 27 |
+
## Training
|
| 28 |
+
|
| 29 |
+
Reuse the *same exact data generator contract and seeds* as the compressed
|
| 30 |
+
adapter: 1,536 TRAIN numeric bindings over three templates and N=16/64,
|
| 31 |
+
disjoint six-digit key/value intervals; full 256K CE on every answer suffix
|
| 32 |
+
token. Use seed 2026092803 and `torch.randperm(1536)` once for example order.
|
| 33 |
+
Each step pairs one MK example with a 512-token segment from the already
|
| 34 |
+
prepared 448 WikiText-2 TRAIN windows. Their historical manifest and file
|
| 35 |
+
SHA256 are pinned by the train command. Heldout and validation windows are
|
| 36 |
+
not included in training. Reusing this fixed TRAIN text gives the control the
|
| 37 |
+
same training exposures as the compressed arm.
|
| 38 |
+
|
| 39 |
+
Use a second, independently loaded **uncompressed FP16** model as the frozen
|
| 40 |
+
prose teacher. This is the direct counterpart to the compressed experiment's
|
| 41 |
+
teacher, which was its own unadapted compressed base. The fixed per-step loss is
|
| 42 |
+
`MK answer CE + 0.5 prose CE + 0.5 KL(own unadapted teacher || student) + 3 C`,
|
| 43 |
+
where C is the same prose-only router closure, with budget 0.006 and excess
|
| 44 |
+
coefficient 10. Temperature 1, 511 prose targets per step, 64-token staged
|
| 45 |
+
head chunks, and one optimizer update after both task gradients.
|
| 46 |
+
|
| 47 |
+
AdamW FP32 masters: V/g LR 1e-4, w/b LR 3e-4, betas (.9,.999), eps 1e-8,
|
| 48 |
+
weight decay 0, clip norm 1. Multiplicative schedule
|
| 49 |
+
`0.1+0.9*(1+cos(pi*j/1535))/2` at successful index j. Native FP16 forward,
|
| 50 |
+
block checkpointing, gradient scale 1024 with growth interval 2000. Overflow
|
| 51 |
+
retries the exact same pair without optimizer/master update, at most 8 retries
|
| 52 |
+
and 1,544 total attempts. Run 1,536 **successful** updates; the final step is
|
| 53 |
+
the only candidate. Small GPU smokes are discarded before formal training.
|
| 54 |
+
|
| 55 |
+
## Evaluation and interpretation
|
| 56 |
+
|
| 57 |
+
After training, restore the actual serialized FP16 adapter onto the same
|
| 58 |
+
uncompressed base. Evaluate baseline, adapter enabled and restored baseline
|
| 59 |
+
in a single process, with identical tokenizer, MK prompts and full WikiText-2
|
| 60 |
+
validation windows. For MK use full 256K greedy generation up to 12 tokens,
|
| 61 |
+
first standalone six-digit number, normal and target-removed controls, native
|
| 62 |
+
prefill plus recurrent decode with fresh FP16 cache. For PPL use all 130
|
| 63 |
+
nonoverlapping reset windows and all 264,764 next-token targets. Record all
|
| 64 |
+
raw scores, differences and file hashes; no early selection or task switch.
|
| 65 |
+
|
| 66 |
+
The earlier compressed arm's independent CONFIRM set has now been observed and
|
| 67 |
+
uses the same three template families. Running this source control on it gives
|
| 68 |
+
a matched historical comparison, **not a newly untouched holdout**. The
|
| 69 |
+
WikiText-2 validation text also informed earlier development. We will not
|
| 70 |
+
promote a source+adapter result to a general recall conclusion without new
|
| 71 |
+
templates, longer distances and a truly untouched corpus.
|
| 72 |
+
|
| 73 |
+
Report all four observed arms explicitly: source FP16, source+adapter,
|
| 74 |
+
compressed/readapted, compressed/readapted+adapter. The source and compressed
|
| 75 |
+
teachers differ by construction. Report PPL and recall together; any cross-arm
|
| 76 |
+
claim remains limited by shared test protocols and the historical numerical
|
| 77 |
+
replay discrepancy in the compressed project.
|
docs/REPRODUCE.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Reproduce the source control
|
| 2 |
+
|
| 3 |
+
Use the verified NVIDIA `nvidia/mamba2-8b-3t-4k` source checkpoint and
|
| 4 |
+
tokenizer revision recorded in [PROTOCOL.md](PROTOCOL.md). The source model
|
| 5 |
+
is downloaded separately; the repository supplies the 2.37 MB adapter.
|
| 6 |
+
The measured environment was PyTorch 2.11.0+cu128, `mamba-ssm`
|
| 7 |
+
2.3.2.post1, `sentencepiece` 0.2.1 and `datasets` 4.8.5 on an RTX PRO 6000
|
| 8 |
+
Blackwell. `train.py` loads two FP16 copies of the source, so its measured
|
| 9 |
+
peak PyTorch CUDA allocation was 34.59 GB.
|
| 10 |
+
|
| 11 |
+
Install a CUDA-compatible PyTorch first. The native GPU extension is a
|
| 12 |
+
separate prerequisite; `pip install -e .` alone does not install it:
|
| 13 |
+
|
| 14 |
+
```bash
|
| 15 |
+
python -m pip install -e .
|
| 16 |
+
python -m pip install --no-build-isolation 'mamba-ssm==2.3.2.post1'
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
Building the extension requires a matching CUDA toolkit/compiler. Use the
|
| 20 |
+
package versions in the [verification environment receipt](../reports/verification_origin_v1.json) when comparing
|
| 21 |
+
numerical replay results.
|
| 22 |
+
|
| 23 |
+
From the repository root, replace `/path/to/source` with the directory
|
| 24 |
+
containing the official source checkpoint and tokenizer:
|
| 25 |
+
|
| 26 |
+
```bash
|
| 27 |
+
CUDA_VISIBLE_DEVICES= python scripts/prepare_prose.py \
|
| 28 |
+
--source-dir /path/to/source \
|
| 29 |
+
--out training_data/prose/training_tokens.pt
|
| 30 |
+
CUDA_VISIBLE_DEVICES= python scripts/prepare_data.py \
|
| 31 |
+
--split train --source-dir /path/to/source
|
| 32 |
+
CUDA_VISIBLE_DEVICES= python scripts/prepare_data.py \
|
| 33 |
+
--split confirm --source-dir /path/to/source
|
| 34 |
+
train_manifest_sha=$(python -c "import hashlib; from pathlib import Path; print(hashlib.sha256(Path('training_data/numeric_v1/train/manifest.json').read_bytes()).hexdigest())")
|
| 35 |
+
confirm_manifest_sha=$(python -c "import hashlib; from pathlib import Path; print(hashlib.sha256(Path('training_data/numeric_v1/confirm/manifest.json').read_bytes()).hexdigest())")
|
| 36 |
+
python scripts/train.py \
|
| 37 |
+
--source-dir /path/to/source \
|
| 38 |
+
--data-root training_data/numeric_v1 \
|
| 39 |
+
--train-manifest-sha256 "$train_manifest_sha" \
|
| 40 |
+
--prose-manifest docs/prose_train_manifest.json \
|
| 41 |
+
--prose-tokens training_data/prose/training_tokens.pt \
|
| 42 |
+
--out-dir artifacts/reproduction_1
|
| 43 |
+
python scripts/evaluate.py \
|
| 44 |
+
--source-dir /path/to/source \
|
| 45 |
+
--adapter artifacts/reproduction_1/adapter_fp16.pt \
|
| 46 |
+
--data-root training_data/numeric_v1 \
|
| 47 |
+
--eval-manifest-sha256 "$confirm_manifest_sha" \
|
| 48 |
+
--split confirm \
|
| 49 |
+
--report reports/reproduction_1.json
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
Use the hashes of your newly prepared manifests (also printed by preparation).
|
| 53 |
+
Manifests record `sys.version`, so a different Python build can change the
|
| 54 |
+
whole-file hash even when all generated prompts and tokens are identical.
|
| 55 |
+
The historical hashes remain in the published reports as run receipts. The
|
| 56 |
+
loaders independently check the frozen generator, tokenizer, protocol and
|
| 57 |
+
all generated raw/token data; computing the local manifest hash does not
|
| 58 |
+
replace those content checks. All scripts
|
| 59 |
+
refuse to overwrite existing result paths. To score the published adapter
|
| 60 |
+
without retraining, use
|
| 61 |
+
`artifacts/source_resurface_v1/adapter_fp16.pt` with `scripts/evaluate.py`.
|
| 62 |
+
For the four-arm comparison, supply the two historical compressed reports to
|
| 63 |
+
`scripts/compare_four_arms.py`; it verifies their SHA-256 values and every
|
| 64 |
+
MK/PPL input identity before computing the table.
|
| 65 |
+
|
| 66 |
+
Reproduction may differ numerically across CUDA, PyTorch and Mamba kernel
|
| 67 |
+
versions. The published reports retain the actual tested output and hashes.
|
docs/RESULTS.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Mamba2-8B source Resurface control: completed results
|
| 2 |
+
|
| 3 |
+
This is a **post-D Resurface-style adapter** on the uncompressed, pure NVIDIA
|
| 4 |
+
Mamba2-8B source. The official BF16 checkpoint is cast to FP16 in the native
|
| 5 |
+
Mamba2 runtime. All 8,236,999,680 base parameters stay frozen. The serialized
|
| 6 |
+
adapter contains 1,154,104 FP16 parameters across 56 layers and is
|
| 7 |
+
[2,374,143 bytes](../artifacts/source_resurface_v1/adapter_fp16.pt).
|
| 8 |
+
|
| 9 |
+
## Matched four-arm comparison
|
| 10 |
+
|
| 11 |
+
All four arms were checked against the same 768 tokenized MK prompts and the
|
| 12 |
+
same 130 WikiText-2 validation windows (264,764 next-token targets). For MK,
|
| 13 |
+
the denominator is 384 normal prompts and 384 target-removed controls per arm.
|
| 14 |
+
|
| 15 |
+
| Arm | Normal MK | Target removed | WikiText-2 PPL |
|
| 16 |
+
| --- | ---: | ---: | ---: |
|
| 17 |
+
| Source FP16 | 147/384 (38.28%) | 0/384 | 7.33418 |
|
| 18 |
+
| Source FP16 + Resurface | **365/384 (95.05%)** | 0/384 | **7.05206** |
|
| 19 |
+
| E8/W5 compressed, readapted base | 91/384 (23.70%) | 0/384 | 7.62240 |
|
| 20 |
+
| E8/W5 compressed, readapted base + Resurface | 340/384 (88.54%) | 0/384 | 7.59316 |
|
| 21 |
+
|
| 22 |
+
On the source, the adapter gained 222 previously wrong normal prompts and lost
|
| 23 |
+
4 previously correct prompts: net +218/384, or **+56.77 percentage points**.
|
| 24 |
+
Its PPL changed by -0.28211 (-3.85%). The compressed arm's normal recall gain
|
| 25 |
+
was +249/384 (+64.84 points), with a PPL change of -0.02923 (-0.38%). The
|
| 26 |
+
8.07-point difference between these *gains* is descriptive; it does not
|
| 27 |
+
isolate the effect of quantization, since the compressed base also had 448
|
| 28 |
+
small-tensor readaptation updates and the two adapters used different frozen
|
| 29 |
+
base teachers for their KL losses.
|
| 30 |
+
|
| 31 |
+
## Run and verification
|
| 32 |
+
|
| 33 |
+
- Final candidate: 1,536 successful optimizer updates, 1,542 attempts, six
|
| 34 |
+
numerical overflow retries within the frozen eight-retry budget. All 1,536
|
| 35 |
+
TRAIN examples appeared once; no checkpoint was chosen using validation.
|
| 36 |
+
- Four saved optimizer checkpoints independently matched their recorded
|
| 37 |
+
SHA-256 values. The final adapter passed exact FP16 tensor roundtrip and
|
| 38 |
+
source-checkpoint binding checks. Adapter SHA-256:
|
| 39 |
+
`e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0`.
|
| 40 |
+
- Evaluation loaded the **serialized** adapter, scored source and adapter in
|
| 41 |
+
one process, then removed it. The first eight baseline MK outputs were
|
| 42 |
+
reproduced exactly after removal. Frozen-base parameter identity, version
|
| 43 |
+
counters and absence of gradients were checked; a full bytewise rescan of
|
| 44 |
+
all 16 GB of base weights was not performed.
|
| 45 |
+
- `compare_four_arms.py` required exact ordered prompt token hashes for all
|
| 46 |
+
768 MK rows and exact token hashes for every PPL window across all four
|
| 47 |
+
arms. Both checks passed. The old compressed reports were also verified by
|
| 48 |
+
their pinned SHA-256 values.
|
| 49 |
+
- Peak PyTorch CUDA allocation was 34.59 GB during two-model training and
|
| 50 |
+
17.08 GB during single-model paired evaluation. These are GPU allocation
|
| 51 |
+
measurements, not total device or host memory requirements.
|
| 52 |
+
|
| 53 |
+
The [protocol](PROTOCOL.md) was frozen before this adapter was trained. Raw
|
| 54 |
+
[training](../reports/source_resurface_v1_train.json),
|
| 55 |
+
[paired evaluation](../reports/source_resurface_v1_confirm_full.json) and
|
| 56 |
+
[four-arm comparison](../reports/four_arm_comparison_v1.json) reports are
|
| 57 |
+
included for audit. The numeric CONFIRM template family and instances had
|
| 58 |
+
already been observed in the earlier compressed project, and WikiText-2
|
| 59 |
+
validation was used in prior development. These results establish performance
|
| 60 |
+
on this specified replay protocol; they do not establish generalization to
|
| 61 |
+
unseen template families, longer recall distances, or untouched prose.
|
docs/VERIFICATION.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Independent verification of published PPL and MK
|
| 2 |
+
|
| 3 |
+
The published adapter and metrics at commit
|
| 4 |
+
`e4137a43ef87cb95b70243ea2271f8e9b3d93d27` passed a fresh GPU replay on
|
| 5 |
+
2026-09-28. A new, clean clone was downloaded from public GitHub, all Python
|
| 6 |
+
source hashes were compared with that commit, and the numeric CONFIRM data
|
| 7 |
+
were regenerated. The adapter SHA-256 was
|
| 8 |
+
`e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0`.
|
| 9 |
+
The original reports were retained.
|
| 10 |
+
|
| 11 |
+
| Arm | WikiText-2 validation PPL | Normal MK | N=16 | N=64 | Target removed |
|
| 12 |
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
| 13 |
+
| Source FP16 | 7.334175947318572 | 147/384 | 113/192 | 34/192 | 0/384 |
|
| 14 |
+
| Source FP16 + Resurface | 7.052063515606311 | 365/384 | 191/192 | 174/192 | 0/384 |
|
| 15 |
+
|
| 16 |
+
The replay was **exact for the measured outputs**: both arms matched every
|
| 17 |
+
one of their 130 per-window NLLs, with maximum absolute NLL error 0, and all
|
| 18 |
+
768 MK generated-token sequences, decoded strings, predictions and correctness
|
| 19 |
+
flags. The final eight baseline probes after adapter removal also matched.
|
| 20 |
+
Across the two arms, this covers 260 PPL windows and 1,536 MK generations.
|
| 21 |
+
Run timestamps and GPU memory receipts are separate from this equality claim.
|
| 22 |
+
|
| 23 |
+
Normal MK increased by 218/384, or 56.77 percentage points: 222 previously
|
| 24 |
+
wrong cases became correct and four previously correct cases became wrong.
|
| 25 |
+
PPL decreased by 0.2821124317, or 3.8465%, on this validation protocol.
|
| 26 |
+
|
| 27 |
+
## Checks independent of the inference loop
|
| 28 |
+
|
| 29 |
+
- A standard-library audit recomputed PPL as `exp(sum(NLL)/sum(targets))`
|
| 30 |
+
from every window and rescored each output string with the declared
|
| 31 |
+
six-digit matcher. It checked exact input identities, paired gains/losses,
|
| 32 |
+
summary arithmetic and the actual adapter file SHA. Its 17 self-tests
|
| 33 |
+
exercise corrupt identities, wrong counts, numerical drift and receipt
|
| 34 |
+
preservation.
|
| 35 |
+
- A separate CPU pass used the pinned SentencePiece tokenizer to decode all
|
| 36 |
+
3,088 saved output records across the original/replay reports, including
|
| 37 |
+
restoration probes. It regenerated and checked their prompt token hashes
|
| 38 |
+
and expected answers. All 520 PPL window receipts across both reports and
|
| 39 |
+
arms were checked against newly loaded, pinned WikiText tokens. There were
|
| 40 |
+
zero mismatches.
|
| 41 |
+
- Regenerating the 1,536 numeric TRAIN examples and 768 CONFIRM rows found
|
| 42 |
+
zero shared case IDs, prompts, record keys or record values between those
|
| 43 |
+
splits. The training receipt contains exactly one successful update for
|
| 44 |
+
each TRAIN example and six overflow retries.
|
| 45 |
+
- The pinned NVIDIA model revision and WikiText revision resolved on the
|
| 46 |
+
Hugging Face Hub. Official model/tokenizer LFS SHA-256 values matched the
|
| 47 |
+
runtime pins. The GPU loader verifies the 16,474,189,490-byte checkpoint
|
| 48 |
+
before strict tensor mapping into the native model.
|
| 49 |
+
|
| 50 |
+
The actual environment was Python 3.10.12, PyTorch 2.11.0+cu128, Mamba-SSM
|
| 51 |
+
2.3.2.post1, Triton 3.6.0, NumPy 1.26.4, datasets 4.8.5 and SentencePiece
|
| 52 |
+
0.2.1 on an RTX PRO 6000 Blackwell Server Edition, with TF32 matmul disabled.
|
| 53 |
+
|
| 54 |
+
## Receipts and reproduction
|
| 55 |
+
|
| 56 |
+
- [Fresh GPU replay](../reports/verification_replay_v1.json)
|
| 57 |
+
- [Independent metric and exact-output audit](../reports/verification_audit_v1.json)
|
| 58 |
+
- [Tokenizer and regenerated-input checks](../reports/verification_token_receipts_v1.json)
|
| 59 |
+
- [Clean-clone origin, source hashes, command and environment](../reports/verification_origin_v1.json)
|
| 60 |
+
- [Pinned official Hub metadata](../reports/verification_hub_metadata_v1.json)
|
| 61 |
+
|
| 62 |
+
Recheck the saved reports without a GPU or PyTorch:
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
python3 scripts/verify_replay.py \
|
| 66 |
+
--published reports/source_resurface_v1_confirm_full.json \
|
| 67 |
+
--replay reports/verification_replay_v1.json \
|
| 68 |
+
--adapter artifacts/source_resurface_v1/adapter_fp16.pt \
|
| 69 |
+
--output reports/my_verification_audit.json
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
An audit exit code of zero means internally valid reports; inspect
|
| 73 |
+
`exact_replay` and `status` for equality. Valid numerical differences are
|
| 74 |
+
reported explicitly. The script refuses to overwrite an existing receipt.
|
| 75 |
+
For a fresh GPU run, follow [REPRODUCE.md](REPRODUCE.md) with a new output path.
|
| 76 |
+
|
| 77 |
+
The review found a documentation portability defect: numeric manifests embed
|
| 78 |
+
the Python build string, so their whole-file SHA can differ even for identical
|
| 79 |
+
data. The reproduction commands now use each newly generated manifest's SHA;
|
| 80 |
+
the loaders still validate the frozen generator, tokenizer, protocol and all
|
| 81 |
+
raw/token content. The docs also clarify the separate native Mamba extension
|
| 82 |
+
installation. Neither change alters the measured model or scoring protocol.
|
| 83 |
+
|
| 84 |
+
## Scope
|
| 85 |
+
|
| 86 |
+
PPL uses WikiText-2 **validation**, 130 reset windows of up to 2,048 next-token
|
| 87 |
+
targets (264,764 targets total), with parallel SSD scan precision. The model
|
| 88 |
+
is the official BF16 source cast to FP16 in the native runtime; this does not
|
| 89 |
+
establish native Megatron BF16 parity or tokenwise FP16-state rounding.
|
| 90 |
+
|
| 91 |
+
MK uses three synthetic numeric templates with 16 or 64 bindings and prompt
|
| 92 |
+
lengths of 257-1,236 tokens. The CONFIRM instances and validation corpus had
|
| 93 |
+
been observed during earlier development. Exact replay confirms these
|
| 94 |
+
reported scores, not unseen-template or full-4K recall generalization.
|
| 95 |
+
Target-removed 0/384 means the absent answer was not recovered; it is not a
|
| 96 |
+
refusal-calibration metric. Base freezing was checked by identities, version
|
| 97 |
+
counters and gradients, not a complete post-training bytewise weight scan.
|
docs/confirm_manifest.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"answer_target_tokens":0,"answer_token_count_histogram":{},"automatic_bos_eos":false,"complete":true,"confirmation_loaded_for_training":false,"contract":{"control_key_base":490000,"control_value_base":990000,"key_range":[400000,480000],"normal_count":384,"positions":"floor(sample*(N-1)/63)","removed_count":384,"samples_per_cell":64,"seed":2026092802,"value_ranges":[[691000,700000],[791000,800000],[891000,900000],[991000,1000000]]},"evaluation_supervised_targets_stored":false,"files":{"raw.jsonl":{"bytes":1465048,"sha256":"7af8c4721ada3b9813e4ea6a6b14a53efc4cda56c2406d90dc17a967c74d2ef2"},"tokens.jsonl":{"bytes":3607304,"sha256":"f7e00c83ad20a1aa910587d8de28ca4ceef679f3ad8dff16b3d9ac8f2c63a00f"}},"format":"MAMBA2_RESURFACE_NUMERIC_DATA_V1","full_vocabulary":256000,"helper_source_sha256":"1a547fe3cedca406d6e3db85f65c3ce554558691e3b29b9c92d8fd6bd1c1ba35","prompt_tokens_max":1236,"prompt_tokens_total":517120,"proof":{"exact_binding_and_control_absence":true,"normal_count":384,"raw_rows_sha256":"7af8c4721ada3b9813e4ea6a6b14a53efc4cda56c2406d90dc17a967c74d2ef2","removed_count":384,"split":"confirm","template_scope":"Same three template families; only instances/key-value ranges are separated.","unique_prompts":768},"protocol_sha256":"dee9457bfaca067b63837dcd3bc94bf9ef9a3d805b1ab04227db05a4b92c54c2","public_generator_sha256":null,"python_version":"3.10.12 (main, Mar 3 2026, 11:56:32) [GCC 11.4.0]","row_count":768,"sizes":[16,64],"split":"confirm","templates":[0,1,2],"tokenizer_sha256":"5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09","value_pool_statistics":{"bands":[{"binding_value_occurrences":3898,"pool_cardinality":9000,"range_half_open":[691000,700000],"target_value_occurrences":90},{"binding_value_occurrences":3869,"pool_cardinality":9000,"range_half_open":[791000,800000],"target_value_occurrences":101},{"binding_value_occurrences":3826,"pool_cardinality":9000,"range_half_open":[891000,900000],"target_value_occurrences":98},{"binding_value_occurrences":3767,"pool_cardinality":9000,"range_half_open":[991000,1000000],"target_value_occurrences":95}],"normal_binding_value_occurrences":15360,"normal_target_value_occurrences":384,"paired_removed_controls_included_in_draw_totals":false,"pool_cardinality":36000,"sampling":"Uniform without replacement within each prompt over the pooled bands; not exact per-prompt band balancing.","unique_normal_values":12602}}
|
docs/prose_train_manifest.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
mamba2_recall/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""Full-precision Mamba2-8B Resurface readout study."""
|
mamba2_recall/calibration.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pinned WikiText tokenization and window selection for recall controls."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
import time
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
|
| 12 |
+
from .runtime import (MODEL_CONFIG, SOURCE_CHECKPOINT_SHA256, SentencePieceTokenizer,
|
| 13 |
+
environment_receipt, gpu_memory_receipt, load_source_model, sha256_file, token_digest)
|
| 14 |
+
|
| 15 |
+
WIKITEXT_REVISION = "b08601e04326c79dfdd32d625aee71d232d685c3"
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def window_starts(token_count, seqlen, nwin, offset=0):
|
| 19 |
+
"""Evenly spread, nonoverlapping windows; never silently reuse short data."""
|
| 20 |
+
usable = token_count - offset
|
| 21 |
+
if seqlen <= 0 or nwin <= 0 or usable < seqlen * nwin:
|
| 22 |
+
raise ValueError("Insufficient tokens for the requested nonoverlapping windows")
|
| 23 |
+
if nwin == 1:
|
| 24 |
+
return [offset]
|
| 25 |
+
span = usable - seqlen
|
| 26 |
+
starts = [offset + (index * span) // (nwin-1) for index in range(nwin)]
|
| 27 |
+
if any(b-a < seqlen for a, b in zip(starts, starts[1:])):
|
| 28 |
+
raise ValueError("Calibration windows overlap")
|
| 29 |
+
return starts
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def load_wikitext_tokens(tokenizer, split, revision=WIKITEXT_REVISION):
|
| 33 |
+
from datasets import load_dataset
|
| 34 |
+
kwargs = {"revision": revision} if revision else {}
|
| 35 |
+
dataset = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split=split, **kwargs)
|
| 36 |
+
text = "\n\n".join(dataset["text"])
|
| 37 |
+
ids = tokenizer.encode(text)
|
| 38 |
+
metadata = {
|
| 39 |
+
"dataset": "Salesforce/wikitext", "configuration": "wikitext-2-raw-v1",
|
| 40 |
+
"split": split, "revision_argument": revision, "dataset_fingerprint": dataset._fingerprint,
|
| 41 |
+
"document_join": "two newline characters", "text_sha256": hashlib.sha256(text.encode()).hexdigest(),
|
| 42 |
+
"token_stream_sha256_int64le": token_digest(ids), "total_tokens": len(ids),
|
| 43 |
+
"tokenizer_sha256": tokenizer.sha256, "automatic_special_tokens": False,
|
| 44 |
+
}
|
| 45 |
+
return torch.tensor(ids, dtype=torch.long), metadata
|
| 46 |
+
|
| 47 |
+
|
mamba2_recall/evaluation.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Frozen prose PPL and a public synthetic multi-key recall protocol.
|
| 2 |
+
|
| 3 |
+
This MK protocol is new and is not interchangeable with private Resurface scores.
|
| 4 |
+
Use --execution tokenwise to round the recurrent FP16 state after every token.
|
| 5 |
+
The faster prefill protocol is reported separately and is never called tokenwise.
|
| 6 |
+
The source-only experiment uses these scoring functions with an external adapter.
|
| 7 |
+
"""
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
import argparse
|
| 11 |
+
import json
|
| 12 |
+
import math
|
| 13 |
+
import random
|
| 14 |
+
import re
|
| 15 |
+
import time
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
import torch
|
| 19 |
+
import torch.nn.functional as F
|
| 20 |
+
|
| 21 |
+
from .calibration import WIKITEXT_REVISION, load_wikitext_tokens, window_starts
|
| 22 |
+
from .runtime import (SOURCE_CHECKPOINT_SHA256, SentencePieceTokenizer, backbone_tokenwise,
|
| 23 |
+
cache_bytes, load_source_model, make_cache,
|
| 24 |
+
environment_receipt, gpu_memory_receipt, sha256_file, token_digest)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def ppl_windows(ids, seqlen, nwin=None):
|
| 28 |
+
if nwin is not None:
|
| 29 |
+
starts = window_starts(len(ids), seqlen+1, nwin)
|
| 30 |
+
return [(start, ids[start:start+seqlen+1]) for start in starts]
|
| 31 |
+
return [(start, ids[start:min(start+seqlen+1, len(ids))])
|
| 32 |
+
for start in range(0, len(ids)-1, seqlen)]
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@torch.inference_mode()
|
| 36 |
+
def evaluate_ppl(model, windows, execution="prefill", logits_chunk=64):
|
| 37 |
+
device = next(model.parameters()).device
|
| 38 |
+
nll, count, rows = 0.0, 0, []
|
| 39 |
+
started = time.time()
|
| 40 |
+
state_memory = None
|
| 41 |
+
for index, (start, window) in enumerate(windows):
|
| 42 |
+
tokens = window.to(device)
|
| 43 |
+
if execution == "tokenwise":
|
| 44 |
+
hidden, cache = backbone_tokenwise(model, tokens[:-1][None], torch.float16)
|
| 45 |
+
state_memory = cache_bytes(cache)
|
| 46 |
+
if any(t.dtype != torch.float16 for pair in cache.key_value_memory_dict.values() for t in pair):
|
| 47 |
+
raise RuntimeError("Tokenwise protocol requires FP16 state and conv cache")
|
| 48 |
+
del cache
|
| 49 |
+
else:
|
| 50 |
+
hidden = model.backbone(tokens[:-1][None])
|
| 51 |
+
if not torch.isfinite(hidden).all():
|
| 52 |
+
raise RuntimeError(f"Nonfinite hidden states in PPL window {index}")
|
| 53 |
+
window_nll = 0.0
|
| 54 |
+
for position in range(0, hidden.shape[1], logits_chunk):
|
| 55 |
+
end = min(position+logits_chunk, hidden.shape[1])
|
| 56 |
+
logits = model.lm_head(hidden[:, position:end]).float()
|
| 57 |
+
if not torch.isfinite(logits).all():
|
| 58 |
+
raise RuntimeError(f"Nonfinite logits in PPL window {index}")
|
| 59 |
+
loss = F.cross_entropy(logits.reshape(-1, logits.shape[-1]),
|
| 60 |
+
tokens[position+1:end+1], reduction="sum")
|
| 61 |
+
window_nll += float(loss)
|
| 62 |
+
if not math.isfinite(window_nll):
|
| 63 |
+
raise RuntimeError(f"Nonfinite loss in PPL window {index}")
|
| 64 |
+
del logits, loss
|
| 65 |
+
targets = len(window)-1
|
| 66 |
+
nll += window_nll
|
| 67 |
+
count += targets
|
| 68 |
+
rows.append({"start": start, "input_tokens": targets, "target_tokens": targets,
|
| 69 |
+
"token_sha256_int64le": token_digest(window.numpy()),
|
| 70 |
+
"nll": window_nll, "ppl": math.exp(window_nll/targets)})
|
| 71 |
+
del hidden, tokens
|
| 72 |
+
if (index+1) % 4 == 0 or index == 0:
|
| 73 |
+
print(f"[PPL {execution}] {index+1}/{len(windows)}, ppl={math.exp(nll/count):.6f}, "
|
| 74 |
+
f"{time.time()-started:.1f}s", flush=True)
|
| 75 |
+
return {"ppl": math.exp(nll/count), "nll": nll, "target_tokens": count,
|
| 76 |
+
"execution": execution, "windows": rows, "elapsed_seconds": time.time()-started,
|
| 77 |
+
"cache_dtype": "float16 each token" if execution == "tokenwise" else "SSD scan internal precision",
|
| 78 |
+
"cache_bytes": state_memory, "logits_chunk_tokens": logits_chunk,
|
| 79 |
+
"score": "next-token cross entropy; no BOS/EOS added; each window starts from zero state"}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def synthetic_mk_cases(split="test", samples_per_cell=8, sizes=(16, 64)):
|
| 83 |
+
"""Frozen public prompts; dev and test use disjoint keys and value ranges."""
|
| 84 |
+
if split not in ("validation", "test"):
|
| 85 |
+
raise ValueError(split)
|
| 86 |
+
offset = 0 if split == "validation" else 100000
|
| 87 |
+
rng = random.Random(834901 if split == "validation" else 834902)
|
| 88 |
+
cases = []
|
| 89 |
+
for size in sizes:
|
| 90 |
+
for template in range(3):
|
| 91 |
+
for sample in range(samples_per_cell):
|
| 92 |
+
keys = rng.sample(range(100000+offset, 180000+offset), size)
|
| 93 |
+
values = rng.sample(range(600000+offset, 680000+offset), size)
|
| 94 |
+
pairs = list(zip(keys, values))
|
| 95 |
+
# Query positions cycle across the sequence, including both ends.
|
| 96 |
+
target_position = (sample * max(1, size-1)) // max(1, samples_per_cell-1)
|
| 97 |
+
key, value = pairs[target_position]
|
| 98 |
+
|
| 99 |
+
def render(records):
|
| 100 |
+
if template == 0:
|
| 101 |
+
body = "\n".join(f"{k}: {v}" for k, v in records)
|
| 102 |
+
return f"Key-value records:\n{body}\n\nLookup the value for key {key}.\nValue:"
|
| 103 |
+
if template == 1:
|
| 104 |
+
body = "\n".join(f"Key {k} has value {v}." for k, v in records)
|
| 105 |
+
return f"{body}\n\nQuestion: What is the value of key {key}?\nAnswer:"
|
| 106 |
+
body = "\n".join(f"{k} -> {v}" for k, v in records)
|
| 107 |
+
return f"Dictionary:\n{body}\n\nReturn the stored value.\n{key} ->"
|
| 108 |
+
|
| 109 |
+
case_id = f"{split}-n{size}-t{template}-s{sample}"
|
| 110 |
+
cases.append({"id": case_id, "N": size, "template": template,
|
| 111 |
+
"query_position": target_position, "key": key, "answer": str(value),
|
| 112 |
+
"prompt": render(pairs), "condition": "normal"})
|
| 113 |
+
# Controls replace the target with an unrelated held-out key/value.
|
| 114 |
+
# Keep record count and template fixed; the target value is absent.
|
| 115 |
+
removed = pairs.copy()
|
| 116 |
+
removed[target_position] = (190000+offset+sample, 690000+offset+sample)
|
| 117 |
+
cases.append({"id": case_id+"-removed", "N": size, "template": template,
|
| 118 |
+
"query_position": target_position, "key": key, "answer": str(value),
|
| 119 |
+
"prompt": render(removed), "condition": "target_removed"})
|
| 120 |
+
return cases
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
@torch.inference_mode()
|
| 124 |
+
def generate_greedy(model, tokenizer, prompt, max_new_tokens=12, execution="prefill"):
|
| 125 |
+
device = next(model.parameters()).device
|
| 126 |
+
ids = torch.tensor(tokenizer.encode(prompt), dtype=torch.long, device=device)[None]
|
| 127 |
+
if ids.shape[1] == 0:
|
| 128 |
+
raise ValueError("Empty recall prompt")
|
| 129 |
+
cache = make_cache(model, ids.shape[1]+max_new_tokens, state_dtype=torch.float16)
|
| 130 |
+
if execution == "tokenwise":
|
| 131 |
+
for position in range(ids.shape[1]):
|
| 132 |
+
cache.seqlen_offset = position
|
| 133 |
+
hidden = model.backbone(ids[:, position:position+1], inference_params=cache)
|
| 134 |
+
else:
|
| 135 |
+
hidden = model.backbone(ids, inference_params=cache)
|
| 136 |
+
hidden = hidden[:, -1:]
|
| 137 |
+
generated = []
|
| 138 |
+
for position in range(max_new_tokens):
|
| 139 |
+
logits = model.lm_head(hidden[:, -1:])
|
| 140 |
+
if not torch.isfinite(logits).all():
|
| 141 |
+
raise RuntimeError("Nonfinite generation logits")
|
| 142 |
+
token = int(logits.argmax(-1).item())
|
| 143 |
+
generated.append(token)
|
| 144 |
+
if token == tokenizer.eos_token_id:
|
| 145 |
+
break
|
| 146 |
+
cache.seqlen_offset = ids.shape[1]+position
|
| 147 |
+
hidden = model.backbone(torch.tensor([[token]], device=device), inference_params=cache)
|
| 148 |
+
return tokenizer.decode(generated), generated, ids.shape[1], cache_bytes(cache)
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def evaluate_mk(model, tokenizer, split="test", samples_per_cell=8, execution="prefill"):
|
| 152 |
+
cases = synthetic_mk_cases(split, samples_per_cell)
|
| 153 |
+
rows = []
|
| 154 |
+
started = time.time()
|
| 155 |
+
for index, case in enumerate(cases):
|
| 156 |
+
output, generated, count, memory = generate_greedy(model, tokenizer, case["prompt"], execution=execution)
|
| 157 |
+
first = re.search(r"(?<!\d)\d{6}(?!\d)", output)
|
| 158 |
+
prediction = first.group() if first else None
|
| 159 |
+
ids = tokenizer.encode(case["prompt"])
|
| 160 |
+
rows.append({**{k: v for k, v in case.items() if k != "prompt"},
|
| 161 |
+
"prompt_tokens": count, "prompt_token_sha256_int64le": token_digest(ids),
|
| 162 |
+
"prompt": case["prompt"], "output": output, "generated_ids": generated,
|
| 163 |
+
"prediction": prediction, "correct": prediction == case["answer"],
|
| 164 |
+
"cache_bytes": memory})
|
| 165 |
+
if (index+1) % 8 == 0 or index == 0:
|
| 166 |
+
print(f"[public MK {execution}] {index+1}/{len(cases)}, {time.time()-started:.1f}s", flush=True)
|
| 167 |
+
summary = {}
|
| 168 |
+
for condition in ("normal", "target_removed"):
|
| 169 |
+
selected = [row for row in rows if row["condition"] == condition]
|
| 170 |
+
correct = sum(row["correct"] for row in selected)
|
| 171 |
+
summary[condition] = {"correct": correct, "count": len(selected), "accuracy": correct/len(selected)}
|
| 172 |
+
cells = []
|
| 173 |
+
for size in (16, 64):
|
| 174 |
+
for template in range(3):
|
| 175 |
+
for condition in ("normal", "target_removed"):
|
| 176 |
+
selected = [row for row in rows if row["N"] == size and row["template"] == template
|
| 177 |
+
and row["condition"] == condition]
|
| 178 |
+
cells.append({"N": size, "template": template, "condition": condition,
|
| 179 |
+
"correct": sum(row["correct"] for row in selected), "count": len(selected),
|
| 180 |
+
"query_positions": [row["query_position"] for row in selected],
|
| 181 |
+
"paired_case_ids": [row["id"] for row in selected]})
|
| 182 |
+
return {"protocol": "public-mamba8-mk-v1", "split": split,
|
| 183 |
+
"execution": execution, "cache_dtype": "float16",
|
| 184 |
+
"prefill_rounding": "each token" if execution == "tokenwise" else "at end of prefill",
|
| 185 |
+
"generation": "greedy, at most 12 tokens, stop at EOS",
|
| 186 |
+
"matching": "first standalone six-digit integer equals answer",
|
| 187 |
+
"private_resurface_comparable": False, "summary": summary, "cells": cells, "rows": rows,
|
| 188 |
+
"interpretation": "Small engineering screen; not statistical equivalence. Near-zero baseline recall cannot establish retained recall capacity.",
|
| 189 |
+
"elapsed_seconds": time.time()-started}
|
| 190 |
+
|
mamba2_recall/resurface_data.py
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CPU-only, split-isolated numeric recall data for the proposed readout study.
|
| 2 |
+
|
| 3 |
+
Importing this module generates no examples and opens no dataset. The training
|
| 4 |
+
loader opens only the literal train subdirectory. Confirmation data have a
|
| 5 |
+
separate, explicit evaluation loader. Generation is not permission to train or
|
| 6 |
+
to inspect confirmation scores; the caller must freeze its protocol first.
|
| 7 |
+
"""
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from collections import Counter
|
| 11 |
+
import hashlib
|
| 12 |
+
import json
|
| 13 |
+
from pathlib import Path
|
| 14 |
+
import random
|
| 15 |
+
import re
|
| 16 |
+
import sys
|
| 17 |
+
|
| 18 |
+
FORMAT = 'MAMBA2_RESURFACE_NUMERIC_DATA_V1'
|
| 19 |
+
PUBLIC_EVALUATION_SHA = '95cba0b201e37f92e6cbfadb9b3e9d79ba7b0cdc9efda6a58a6216b0d84d35e0'
|
| 20 |
+
TOKENIZER_SHA = '5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09'
|
| 21 |
+
SIZES = (16, 64)
|
| 22 |
+
TEMPLATES = (0, 1, 2)
|
| 23 |
+
CONTRACT = {
|
| 24 |
+
'train': {'seed':2026092801, 'key_range':[300000,380000],
|
| 25 |
+
'value_ranges':[[681000,690000],[781000,790000],[881000,890000],[981000,990000]],
|
| 26 |
+
'samples_per_cell':256,
|
| 27 |
+
'normal_count':1536, 'removed_count':0, 'positions':'independent uniform rng.randrange(N)'},
|
| 28 |
+
'dev': {'seed':834901, 'key_range':[100000,180000],
|
| 29 |
+
'value_ranges':[[600000,680000]], 'samples_per_cell':64,
|
| 30 |
+
'normal_count':384, 'removed_count':384, 'positions':'floor(sample*(N-1)/63)',
|
| 31 |
+
'control_key_base':190000, 'control_value_base':690000,
|
| 32 |
+
'generator':'frozen public-mamba8-mk-v1 validation, samples_per_cell=64'},
|
| 33 |
+
'confirm': {'seed':2026092802, 'key_range':[400000,480000],
|
| 34 |
+
'value_ranges':[[691000,700000],[791000,800000],[891000,900000],[991000,1000000]],
|
| 35 |
+
'samples_per_cell':64,
|
| 36 |
+
'normal_count':384, 'removed_count':384, 'positions':'floor(sample*(N-1)/63)',
|
| 37 |
+
'control_key_base':490000, 'control_value_base':990000},
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def in_value_pool(value, spec):
|
| 42 |
+
return any(low<=value<high for low,high in spec['value_ranges'])
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def value_pool_statistics(rows, split):
|
| 46 |
+
"""Actual normal-row counts; controls are excluded from these draw totals."""
|
| 47 |
+
ranges = CONTRACT[split]['value_ranges']
|
| 48 |
+
normal = [row for row in rows if row['condition']=='normal']
|
| 49 |
+
values = [value for row in normal for _,value in row['records']]
|
| 50 |
+
targets = [int(row['answer']) for row in normal]
|
| 51 |
+
return {'pool_cardinality':sum(high-low for low,high in ranges),
|
| 52 |
+
'normal_binding_value_occurrences':len(values),'normal_target_value_occurrences':len(targets),
|
| 53 |
+
'unique_normal_values':len(set(values)),
|
| 54 |
+
'bands':[{'range_half_open':[low,high],'pool_cardinality':high-low,
|
| 55 |
+
'binding_value_occurrences':sum(low<=value<high for value in values),
|
| 56 |
+
'target_value_occurrences':sum(low<=value<high for value in targets)} for low,high in ranges],
|
| 57 |
+
'sampling':'Uniform without replacement within each prompt over the pooled bands; not exact per-prompt band balancing.',
|
| 58 |
+
'paired_removed_controls_included_in_draw_totals':False}
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def sha_bytes(value):
|
| 62 |
+
return hashlib.sha256(value).hexdigest()
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def sha_file(path):
|
| 66 |
+
digest = hashlib.sha256()
|
| 67 |
+
with Path(path).open('rb') as stream:
|
| 68 |
+
for chunk in iter(lambda:stream.read(1 << 20),b''):
|
| 69 |
+
digest.update(chunk)
|
| 70 |
+
return digest.hexdigest()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def canonical_bytes(value):
|
| 74 |
+
return (json.dumps(value,sort_keys=True,separators=(',',':'),ensure_ascii=False,allow_nan=False)+'\n').encode('utf-8')
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def token_digest(ids):
|
| 78 |
+
if not isinstance(ids,list) or any(type(x) is not int or not 0 <= x < 256000 for x in ids):
|
| 79 |
+
raise ValueError('Expected a plain list of valid native256K integer token ids')
|
| 80 |
+
return sha_bytes(b''.join(x.to_bytes(8,'little',signed=True) for x in ids))
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def render(records, key, template):
|
| 84 |
+
"""The three public-v1 surface forms; no answer appended to the prompt."""
|
| 85 |
+
if template == 0:
|
| 86 |
+
body = '\n'.join(f'{k}: {v}' for k,v in records)
|
| 87 |
+
return f'Key-value records:\n{body}\n\nLookup the value for key {key}.\nValue:'
|
| 88 |
+
if template == 1:
|
| 89 |
+
body = '\n'.join(f'Key {k} has value {v}.' for k,v in records)
|
| 90 |
+
return f'{body}\n\nQuestion: What is the value of key {key}?\nAnswer:'
|
| 91 |
+
if template == 2:
|
| 92 |
+
body = '\n'.join(f'{k} -> {v}' for k,v in records)
|
| 93 |
+
return f'Dictionary:\n{body}\n\nReturn the stored value.\n{key} ->'
|
| 94 |
+
raise ValueError('Unsupported public template')
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def parse_records(prompt, template):
|
| 98 |
+
if template == 0:
|
| 99 |
+
body = prompt.removeprefix('Key-value records:\n').split('\n\nLookup the value for key ',1)[0]
|
| 100 |
+
pattern = r'([0-9]{6}): ([0-9]{6})'
|
| 101 |
+
elif template == 1:
|
| 102 |
+
body = prompt.split('\n\nQuestion: What is the value of key ',1)[0]
|
| 103 |
+
pattern = r'Key ([0-9]{6}) has value ([0-9]{6})\.'
|
| 104 |
+
elif template == 2:
|
| 105 |
+
body = prompt.removeprefix('Dictionary:\n').split('\n\nReturn the stored value.\n',1)[0]
|
| 106 |
+
pattern = r'([0-9]{6}) -> ([0-9]{6})'
|
| 107 |
+
else:
|
| 108 |
+
raise ValueError('Unsupported public template')
|
| 109 |
+
records = []
|
| 110 |
+
for line in body.splitlines():
|
| 111 |
+
match = re.fullmatch(pattern,line)
|
| 112 |
+
if match is None:
|
| 113 |
+
raise ValueError('Malformed record text')
|
| 114 |
+
records.append([int(match[1]),int(match[2])])
|
| 115 |
+
return records
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def _finish_row(row, records, split, sample):
|
| 119 |
+
result = {**row,'split':split,'sample':sample,'records':[list(pair) for pair in records]}
|
| 120 |
+
result['prompt_sha256_utf8'] = sha_bytes(result['prompt'].encode('utf-8'))
|
| 121 |
+
result['row_sha256'] = sha_bytes(canonical_bytes(result))
|
| 122 |
+
return result
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def generate_cases(split):
|
| 126 |
+
"""Explicit lazy generation; train and confirm are independent RNG streams."""
|
| 127 |
+
if split not in ('train','confirm'):
|
| 128 |
+
raise ValueError('Use frozen_development_cases() for the immutable public development suite')
|
| 129 |
+
spec = CONTRACT[split]
|
| 130 |
+
rng = random.Random(spec['seed'])
|
| 131 |
+
value_pool = [value for low,high in spec['value_ranges'] for value in range(low,high)]
|
| 132 |
+
rows = []
|
| 133 |
+
for size in SIZES:
|
| 134 |
+
for template in TEMPLATES:
|
| 135 |
+
for sample in range(spec['samples_per_cell']):
|
| 136 |
+
keys = rng.sample(range(*spec['key_range']),size)
|
| 137 |
+
values = rng.sample(value_pool,size)
|
| 138 |
+
records = list(zip(keys,values))
|
| 139 |
+
position = (rng.randrange(size) if split=='train'
|
| 140 |
+
else sample*(size-1)//(spec['samples_per_cell']-1))
|
| 141 |
+
key,value = records[position]
|
| 142 |
+
row = {'id':f'resurface-{split}-n{size}-t{template}-s{sample}',
|
| 143 |
+
'N':size,'template':template,'query_position':position,'key':key,
|
| 144 |
+
'answer':str(value),'prompt':render(records,key,template),'condition':'normal'}
|
| 145 |
+
rows.append(_finish_row(row,records,split,sample))
|
| 146 |
+
if split == 'confirm':
|
| 147 |
+
removed = records.copy()
|
| 148 |
+
removed[position] = (spec['control_key_base']+sample,spec['control_value_base']+sample)
|
| 149 |
+
control = {**row,'id':row['id']+'-removed','condition':'target_removed',
|
| 150 |
+
'prompt':render(removed,key,template)}
|
| 151 |
+
rows.append(_finish_row(control,removed,split,sample))
|
| 152 |
+
validate_cases(rows,split)
|
| 153 |
+
return rows
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def frozen_development_cases():
|
| 157 |
+
"""Called by preparation/evaluation only, never by training loaders."""
|
| 158 |
+
path = Path(__file__).with_name('evaluation.py')
|
| 159 |
+
if sha_file(path) != PUBLIC_EVALUATION_SHA:
|
| 160 |
+
raise ValueError('Frozen public-v1 generator changed')
|
| 161 |
+
from .evaluation import synthetic_mk_cases
|
| 162 |
+
rows = []
|
| 163 |
+
for row in synthetic_mk_cases('validation',samples_per_cell=64,sizes=SIZES):
|
| 164 |
+
sample = int(re.search(r'-s(\d+)(?:-removed)?$',row['id'])[1])
|
| 165 |
+
rows.append(_finish_row(row,parse_records(row['prompt'],row['template']),'dev',sample))
|
| 166 |
+
validate_cases(rows,'dev')
|
| 167 |
+
return rows
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def validate_cases(rows, split):
|
| 171 |
+
if split not in CONTRACT or not isinstance(rows,list):
|
| 172 |
+
raise ValueError('Unknown split or malformed case list')
|
| 173 |
+
spec = CONTRACT[split]
|
| 174 |
+
if len(rows) != spec['normal_count']+spec['removed_count']:
|
| 175 |
+
raise ValueError('Declared split count differs')
|
| 176 |
+
identifiers, prompts, by_id, cells = set(),set(),{},Counter()
|
| 177 |
+
order = []
|
| 178 |
+
for size in SIZES:
|
| 179 |
+
for template in TEMPLATES:
|
| 180 |
+
for sample in range(spec['samples_per_cell']):
|
| 181 |
+
prefix = 'validation' if split=='dev' else f'resurface-{split}'
|
| 182 |
+
normal = f'{prefix}-n{size}-t{template}-s{sample}'
|
| 183 |
+
order.append(normal)
|
| 184 |
+
if split!='train':
|
| 185 |
+
order.append(normal+'-removed')
|
| 186 |
+
if [row.get('id') for row in rows] != order:
|
| 187 |
+
raise ValueError('Case ids/order/cell balancing differ')
|
| 188 |
+
for row in rows:
|
| 189 |
+
if row.get('split') != split or row['id'] in identifiers or row['prompt'] in prompts:
|
| 190 |
+
raise ValueError('Wrong split or duplicate case/prompt')
|
| 191 |
+
identifiers.add(row['id']);prompts.add(row['prompt']);by_id[row['id']] = row
|
| 192 |
+
for name in ('N','template','sample','query_position','key'):
|
| 193 |
+
if type(row.get(name)) is not int:
|
| 194 |
+
raise ValueError('Case integers must not be floats or booleans')
|
| 195 |
+
size,template,sample,position = [row[k] for k in ('N','template','sample','query_position')]
|
| 196 |
+
if size not in SIZES or template not in TEMPLATES or not 0<=sample<spec['samples_per_cell'] or not 0<=position<size:
|
| 197 |
+
raise ValueError('Case geometry differs')
|
| 198 |
+
if split!='train' and position != sample*(size-1)//(spec['samples_per_cell']-1):
|
| 199 |
+
raise ValueError('Evaluation query positions must spread across the whole sequence')
|
| 200 |
+
if not isinstance(row.get('answer'),str) or re.fullmatch(r'[0-9]{6}',row['answer']) is None:
|
| 201 |
+
raise ValueError('Expected a six-digit answer string')
|
| 202 |
+
answer = int(row['answer'])
|
| 203 |
+
if not spec['key_range'][0]<=row['key']<spec['key_range'][1] or not in_value_pool(answer,spec):
|
| 204 |
+
raise ValueError('Query/answer split range differs')
|
| 205 |
+
records = row.get('records')
|
| 206 |
+
if (not isinstance(records,list) or len(records)!=size
|
| 207 |
+
or any(not isinstance(pair,list) or len(pair)!=2 or any(type(v) is not int for v in pair) for pair in records)
|
| 208 |
+
or len({k for k,_ in records})!=size or len({v for _,v in records})!=size):
|
| 209 |
+
raise ValueError('Unique integral bindings required')
|
| 210 |
+
condition = row['condition']
|
| 211 |
+
if condition not in ('normal','target_removed') or (split=='train' and condition!='normal'):
|
| 212 |
+
raise ValueError('Training permits normal binding CE only')
|
| 213 |
+
for index,(key,value) in enumerate(records):
|
| 214 |
+
control = condition=='target_removed' and index==position
|
| 215 |
+
if control:
|
| 216 |
+
if [key,value]!=[spec['control_key_base']+sample,spec['control_value_base']+sample]:
|
| 217 |
+
raise ValueError('Control must replace only the target binding')
|
| 218 |
+
elif not spec['key_range'][0]<=key<spec['key_range'][1] or not in_value_pool(value,spec):
|
| 219 |
+
raise ValueError('Record key/value split range differs')
|
| 220 |
+
if row['prompt'] != render(records,row['key'],template) or parse_records(row['prompt'],template)!=records:
|
| 221 |
+
raise ValueError('Prompt is not the exact reconstruction of declared bindings')
|
| 222 |
+
if row['prompt_sha256_utf8']!=sha_bytes(row['prompt'].encode('utf-8')):
|
| 223 |
+
raise ValueError('Prompt text hash differs')
|
| 224 |
+
content = {k:v for k,v in row.items() if k!='row_sha256'}
|
| 225 |
+
if row['row_sha256']!=sha_bytes(canonical_bytes(content)):
|
| 226 |
+
raise ValueError('Raw row hash differs')
|
| 227 |
+
if condition=='normal':
|
| 228 |
+
if records[position]!=[row['key'],answer]:
|
| 229 |
+
raise ValueError('Queried key is not bound to the exact supervised answer')
|
| 230 |
+
else:
|
| 231 |
+
if row['key'] in {k for k,_ in records} or answer in {v for _,v in records}:
|
| 232 |
+
raise ValueError('Removed binding/answer remains in records')
|
| 233 |
+
if re.search(r'(?<!\d)'+re.escape(row['answer'])+r'(?!\d)',row['prompt']):
|
| 234 |
+
raise ValueError('Removed answer still appears in rendered prompt')
|
| 235 |
+
normal = by_id[row['id'].removesuffix('-removed')]
|
| 236 |
+
if (any(row[k]!=normal[k] for k in ('N','template','sample','query_position','key','answer'))
|
| 237 |
+
or [i for i,(a,b) in enumerate(zip(normal['records'],records)) if a!=b]!=[position]):
|
| 238 |
+
raise ValueError('Control is not paired to its normal case')
|
| 239 |
+
cells[size,template,condition] += 1
|
| 240 |
+
expected = {(size,template,condition):spec['samples_per_cell'] for size in SIZES for template in TEMPLATES
|
| 241 |
+
for condition in (('normal',) if split=='train' else ('normal','target_removed'))}
|
| 242 |
+
if dict(cells)!=expected:
|
| 243 |
+
raise ValueError('Unbalanced split cells')
|
| 244 |
+
return {'split':split,'normal_count':spec['normal_count'],'removed_count':spec['removed_count'],
|
| 245 |
+
'unique_prompts':len(prompts),'exact_binding_and_control_absence':True,
|
| 246 |
+
'raw_rows_sha256':sha_bytes(b''.join(canonical_bytes(row) for row in rows)),
|
| 247 |
+
'template_scope':'Same three template families; only instances/key-value ranges are separated.'}
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def _encode(tokenizer, text):
|
| 251 |
+
ids = list(tokenizer.encode(text))
|
| 252 |
+
token_digest(ids)
|
| 253 |
+
if not ids:
|
| 254 |
+
raise ValueError('Empty encoded sequence')
|
| 255 |
+
return ids
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def tokenize_case(row, tokenizer):
|
| 259 |
+
"""Use answer suffix labels only for TRAIN, never for control/evaluation rows."""
|
| 260 |
+
prompt_ids = _encode(tokenizer,row['prompt'])
|
| 261 |
+
if len(prompt_ids)+12>4096:
|
| 262 |
+
raise ValueError('Prompt plus frozen12-token generation exceeds native4K context')
|
| 263 |
+
result = {'id':row['id'],'split':row['split'],'raw_row_sha256':row['row_sha256'],
|
| 264 |
+
'prompt_ids':prompt_ids,'prompt_tokens':len(prompt_ids),
|
| 265 |
+
'prompt_token_sha256_int64le':token_digest(prompt_ids)}
|
| 266 |
+
if row['split']=='train':
|
| 267 |
+
if row['condition']!='normal':
|
| 268 |
+
raise ValueError('Removed controls are never supervised training answers')
|
| 269 |
+
full_text = row['prompt']+' '+row['answer']
|
| 270 |
+
full = _encode(tokenizer,full_text)
|
| 271 |
+
length = len(prompt_ids)
|
| 272 |
+
if full[:length]!=prompt_ids or not length<len(full)<=4096:
|
| 273 |
+
raise ValueError('Prompt+answer tokenization is not prefix-stable within native4K context')
|
| 274 |
+
suffix = full[length:]
|
| 275 |
+
if tokenizer.decode(suffix).strip()!=row['answer']:
|
| 276 |
+
raise ValueError('Token suffix does not decode to the whole six-digit answer')
|
| 277 |
+
result.update(full_ids=full,full_text_sha256_utf8=sha_bytes(full_text.encode('utf-8')),
|
| 278 |
+
full_token_sha256_int64le=token_digest(full),answer_ids=suffix,answer_target_count=len(suffix),
|
| 279 |
+
answer_token_positions=list(range(length,len(full))),
|
| 280 |
+
ce_hidden_positions=list(range(length-1,len(full)-1)),
|
| 281 |
+
prefix_stability_verified=True,
|
| 282 |
+
loss_scope='Full256K CE on every answer-suffix token only; no EOS or prompt-token CE.')
|
| 283 |
+
return result
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def prepare_split(dataset_root, split, tokenizer, *, protocol_path, protocol_sha256, tokenizer_sha256):
|
| 287 |
+
"""Write one explicit new split, only after a caller-pinned protocol exists.
|
| 288 |
+
|
| 289 |
+
This function is never called at import. TRAIN preparation does not generate
|
| 290 |
+
or read DEV/CONFIRM; the caller invokes their preparations separately.
|
| 291 |
+
"""
|
| 292 |
+
if (split not in CONTRACT or tokenizer_sha256!=TOKENIZER_SHA
|
| 293 |
+
or getattr(tokenizer,'sha256',None)!=TOKENIZER_SHA):
|
| 294 |
+
raise ValueError('Declared split and pinned native tokenizer required')
|
| 295 |
+
protocol_path = Path(protocol_path)
|
| 296 |
+
if (not re.fullmatch(r'[0-9a-f]{64}',protocol_sha256) or not protocol_path.is_file()
|
| 297 |
+
or sha_file(protocol_path)!=protocol_sha256):
|
| 298 |
+
raise ValueError('A frozen existing protocol with exactSHA is required before generation')
|
| 299 |
+
output = Path(dataset_root)/split
|
| 300 |
+
if output.exists() or output.is_symlink():
|
| 301 |
+
raise FileExistsError('Fresh split directory only; preserve existing preparations')
|
| 302 |
+
rows = frozen_development_cases() if split=='dev' else generate_cases(split)
|
| 303 |
+
proof = validate_cases(rows,split)
|
| 304 |
+
tokens = [tokenize_case(row,tokenizer) for row in rows]
|
| 305 |
+
prompt_hashes = [row['prompt_token_sha256_int64le'] for row in tokens]
|
| 306 |
+
if len(set(prompt_hashes))!=len(prompt_hashes):
|
| 307 |
+
raise ValueError('Duplicate prompt tokens within a split')
|
| 308 |
+
raw = b''.join(canonical_bytes(row) for row in rows)
|
| 309 |
+
encoded = b''.join(canonical_bytes(row) for row in tokens)
|
| 310 |
+
output.mkdir(parents=True,exist_ok=False)
|
| 311 |
+
(output/'raw.jsonl').write_bytes(raw)
|
| 312 |
+
(output/'tokens.jsonl').write_bytes(encoded)
|
| 313 |
+
manifest = {'format':FORMAT,'complete':True,'split':split,'contract':CONTRACT[split],
|
| 314 |
+
'sizes':list(SIZES),'templates':list(TEMPLATES),'proof':proof,
|
| 315 |
+
'protocol_sha256':protocol_sha256,'tokenizer_sha256':tokenizer_sha256,
|
| 316 |
+
'helper_source_sha256':sha_file(__file__),'python_version':sys.version,
|
| 317 |
+
'value_pool_statistics':value_pool_statistics(rows,split),
|
| 318 |
+
'public_generator_sha256':PUBLIC_EVALUATION_SHA if split=='dev' else None,
|
| 319 |
+
'files':{'raw.jsonl':{'bytes':len(raw),'sha256':sha_bytes(raw)},
|
| 320 |
+
'tokens.jsonl':{'bytes':len(encoded),'sha256':sha_bytes(encoded)}},
|
| 321 |
+
'row_count':len(rows),'prompt_tokens_total':sum(t['prompt_tokens'] for t in tokens),
|
| 322 |
+
'prompt_tokens_max':max(t['prompt_tokens'] for t in tokens),
|
| 323 |
+
'answer_target_tokens':sum(t.get('answer_target_count',0) for t in tokens),
|
| 324 |
+
'answer_token_count_histogram':{str(k):v for k,v in sorted(Counter(t['answer_target_count'] for t in tokens if split=='train').items())},
|
| 325 |
+
'automatic_bos_eos':False,'full_vocabulary':256000,
|
| 326 |
+
'evaluation_supervised_targets_stored':False,
|
| 327 |
+
'confirmation_loaded_for_training':False}
|
| 328 |
+
(output/'manifest.json').write_bytes(canonical_bytes(manifest))
|
| 329 |
+
return manifest
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def _load_split(dataset_root, split, expected_manifest_sha256, tokenizer):
|
| 333 |
+
if getattr(tokenizer,'sha256',None)!=TOKENIZER_SHA:
|
| 334 |
+
raise ValueError('Actual native tokenizer identity differs')
|
| 335 |
+
directory = Path(dataset_root)/split
|
| 336 |
+
if directory.is_symlink() or {p.name for p in directory.iterdir()}!={'manifest.json','raw.jsonl','tokens.jsonl'}:
|
| 337 |
+
raise ValueError('Expected one complete isolated split directory')
|
| 338 |
+
mp = directory/'manifest.json'
|
| 339 |
+
if mp.is_symlink() or sha_file(mp)!=expected_manifest_sha256:
|
| 340 |
+
raise ValueError('Pinned split manifest differs')
|
| 341 |
+
manifest = json.loads(mp.read_text())
|
| 342 |
+
if (manifest.get('format')!=FORMAT or manifest.get('complete') is not True or manifest.get('split')!=split
|
| 343 |
+
or manifest.get('contract')!=CONTRACT[split] or manifest.get('tokenizer_sha256')!=TOKENIZER_SHA
|
| 344 |
+
or manifest.get('helper_source_sha256')!=sha_file(__file__)
|
| 345 |
+
or set(manifest.get('files',{}))!={'raw.jsonl','tokens.jsonl'}):
|
| 346 |
+
raise ValueError('Prepared split provenance/format differs')
|
| 347 |
+
parsed = {}
|
| 348 |
+
for name,entry in manifest['files'].items():
|
| 349 |
+
path = directory/name
|
| 350 |
+
if (path.is_symlink() or not path.is_file() or type(entry.get('bytes')) is not int
|
| 351 |
+
or path.stat().st_size!=entry['bytes'] or sha_file(path)!=entry['sha256']):
|
| 352 |
+
raise ValueError('Prepared split file identity differs')
|
| 353 |
+
parsed[name] = [json.loads(line) for line in path.read_text().splitlines()]
|
| 354 |
+
rows,tokens = parsed['raw.jsonl'],parsed['tokens.jsonl']
|
| 355 |
+
if validate_cases(rows,split)!=manifest['proof'] or len(tokens)!=len(rows):
|
| 356 |
+
raise ValueError('Prepared raw case proof differs')
|
| 357 |
+
expected_rows = frozen_development_cases() if split=='dev' else generate_cases(split)
|
| 358 |
+
if rows!=expected_rows:
|
| 359 |
+
raise ValueError('Prepared cases differ from the exact frozen seed/generator')
|
| 360 |
+
if manifest.get('value_pool_statistics')!=value_pool_statistics(rows,split):
|
| 361 |
+
raise ValueError('Declared/observed pooled value distribution differs')
|
| 362 |
+
if [tokenize_case(row,tokenizer) for row in rows]!=tokens:
|
| 363 |
+
raise ValueError('Actual tokenizer/prefix/answer-label reconstruction differs')
|
| 364 |
+
return manifest,rows,tokens
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
def load_training(dataset_root, expected_manifest_sha256, tokenizer):
|
| 368 |
+
"""Literal TRAIN-only path; never opens any development or confirmation file."""
|
| 369 |
+
return _load_split(dataset_root,'train',expected_manifest_sha256,tokenizer)
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
def load_evaluation(dataset_root, split, expected_manifest_sha256, tokenizer):
|
| 373 |
+
if split not in ('dev','confirm'):
|
| 374 |
+
raise ValueError('Explicit dev or confirm evaluation split required')
|
| 375 |
+
return _load_split(dataset_root,split,expected_manifest_sha256,tokenizer)
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
def audit_split_overlap(*split_rows):
|
| 379 |
+
"""Preparation/evaluation audit only; never called by load_training."""
|
| 380 |
+
seen_ids,seen_text,seen_tokens = set(),set(),set()
|
| 381 |
+
for rows,tokens in split_rows:
|
| 382 |
+
if len(rows)!=len(tokens):
|
| 383 |
+
raise ValueError('Raw/token row counts differ')
|
| 384 |
+
current_ids = {row['id'] for row in rows}
|
| 385 |
+
current_text = {row['prompt_sha256_utf8'] for row in rows}
|
| 386 |
+
current_tokens = {row['prompt_token_sha256_int64le'] for row in tokens}
|
| 387 |
+
if seen_ids¤t_ids or seen_text¤t_text or seen_tokens¤t_tokens:
|
| 388 |
+
raise ValueError('Cross-split id/text/token input overlap')
|
| 389 |
+
seen_ids.update(current_ids);seen_text.update(current_text);seen_tokens.update(current_tokens)
|
| 390 |
+
return {'splits':len(split_rows),'unique_cases':len(seen_ids),'id_overlap':0,'text_overlap':0,'token_overlap':0,
|
| 391 |
+
'scope':'Exact prompt identity plus declared disjoint key/value ranges; shared template families are intentional.'}
|
mamba2_recall/resurface_loss.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Full-vocabulary staged head gradients plus one joint backbone/gate backward.
|
| 2 |
+
|
| 3 |
+
MK selects every answer-suffix target with an explicit bool mask; prose selects
|
| 4 |
+
all targets. Only loss-position selection uses the mask: it is never a router
|
| 5 |
+
input. Chunk sums divide by the complete selected target count. Head GEMMs are
|
| 6 |
+
FP16, CE/KL are FP32, temperature is one, teacher is detached. The scaler applies
|
| 7 |
+
once to the hidden derivative and once to the separate gate-auxiliary branch.
|
| 8 |
+
"""
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
import argparse
|
| 11 |
+
import json
|
| 12 |
+
import math
|
| 13 |
+
import torch
|
| 14 |
+
import torch.nn.functional as F
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def staged_loss_backward(student_hidden, targets, student_head, *, gates=None,
|
| 18 |
+
scaler=None, teacher_hidden=None, teacher_head=None,
|
| 19 |
+
answer_mask=None, ce_weight=1., kl_weight=0.,
|
| 20 |
+
closure_weight=0., opening_mask=None, opening_weight=0.,
|
| 21 |
+
chunk_tokens=64):
|
| 22 |
+
weights = (ce_weight, kl_weight, closure_weight, opening_weight)
|
| 23 |
+
if any(not math.isfinite(x) or x < 0 for x in weights) or sum(weights) <= 0:
|
| 24 |
+
raise ValueError('Invalid objective coefficients')
|
| 25 |
+
if (student_hidden.ndim != 3 or student_hidden.dtype != torch.float16
|
| 26 |
+
or targets.dtype != torch.int64 or targets.shape != student_hidden.shape[:2]
|
| 27 |
+
or targets.device != student_hidden.device or not student_hidden.requires_grad
|
| 28 |
+
or type(chunk_tokens) is not int or chunk_tokens < 1):
|
| 29 |
+
raise ValueError('Invalid native FP16 hidden/target/chunk geometry')
|
| 30 |
+
if answer_mask is None:
|
| 31 |
+
answer_mask = torch.ones_like(targets, dtype=torch.bool)
|
| 32 |
+
if (answer_mask.dtype != torch.bool or answer_mask.shape != targets.shape
|
| 33 |
+
or answer_mask.device != targets.device or not bool(answer_mask.any())):
|
| 34 |
+
raise ValueError('Answer selection must be nonempty bool[batch,tokens]')
|
| 35 |
+
count = int(answer_mask.sum())
|
| 36 |
+
if not torch.isfinite(student_hidden).all():
|
| 37 |
+
raise FloatingPointError('Nonfinite student hidden')
|
| 38 |
+
if any(p.requires_grad for p in student_head.parameters()):
|
| 39 |
+
raise ValueError('Student vocabulary head must be frozen')
|
| 40 |
+
if kl_weight:
|
| 41 |
+
if (teacher_hidden is None or teacher_head is None or teacher_hidden.shape != student_hidden.shape
|
| 42 |
+
or teacher_hidden.dtype != torch.float16 or teacher_hidden.device != student_hidden.device
|
| 43 |
+
or not torch.isfinite(teacher_hidden).all()
|
| 44 |
+
or any(p.requires_grad for p in teacher_head.parameters())):
|
| 45 |
+
raise ValueError('Invalid frozen teacher')
|
| 46 |
+
if (closure_weight or opening_weight) and gates is None:
|
| 47 |
+
raise ValueError('Gate objective requires same-invocation capture')
|
| 48 |
+
if gates is not None and (gates.logits.shape[1:] != targets.shape or gates.logits.device != targets.device):
|
| 49 |
+
raise ValueError('Gate capture does not correspond to this hidden sequence')
|
| 50 |
+
if gates is not None and not torch.isfinite(gates.logits).all():
|
| 51 |
+
raise FloatingPointError('Nonfinite router logits, including sigmoid-saturated values')
|
| 52 |
+
gradient = torch.zeros_like(student_hidden)
|
| 53 |
+
ce_parts, kl_parts, sizes = [], [], []
|
| 54 |
+
with torch.autocast(device_type=student_hidden.device.type, enabled=False):
|
| 55 |
+
for first in range(0, student_hidden.shape[1], chunk_tokens):
|
| 56 |
+
last = min(first+chunk_tokens, student_hidden.shape[1])
|
| 57 |
+
mask = answer_mask[:, first:last]
|
| 58 |
+
selected = int(mask.sum())
|
| 59 |
+
if not selected:
|
| 60 |
+
continue
|
| 61 |
+
chunk = student_hidden[:, first:last].detach().requires_grad_(True)
|
| 62 |
+
logits16 = student_head(chunk[mask])
|
| 63 |
+
if logits16.dtype != torch.float16 or not torch.isfinite(logits16).all():
|
| 64 |
+
raise FloatingPointError('Invalid native student head output')
|
| 65 |
+
logits = logits16.float()
|
| 66 |
+
ce = F.cross_entropy(logits, targets[:, first:last][mask], reduction='sum')
|
| 67 |
+
kl = logits.new_zeros(())
|
| 68 |
+
if kl_weight:
|
| 69 |
+
with torch.no_grad():
|
| 70 |
+
teacher_logits16 = teacher_head(teacher_hidden[:, first:last][mask])
|
| 71 |
+
if (teacher_logits16.dtype != torch.float16 or teacher_logits16.shape != logits16.shape
|
| 72 |
+
or not torch.isfinite(teacher_logits16).all()):
|
| 73 |
+
raise FloatingPointError('Invalid native teacher head output')
|
| 74 |
+
teacher_logp = F.log_softmax(teacher_logits16.float(), dim=-1)
|
| 75 |
+
kl = F.kl_div(F.log_softmax(logits, dim=-1), teacher_logp, reduction='sum', log_target=True)
|
| 76 |
+
loss = (ce_weight*ce+kl_weight*kl)/count
|
| 77 |
+
if not torch.isfinite(loss):
|
| 78 |
+
raise FloatingPointError('Nonfinite chunk objective')
|
| 79 |
+
scaled = scaler.scale(loss) if scaler is not None else loss
|
| 80 |
+
grad, = torch.autograd.grad(scaled, chunk)
|
| 81 |
+
gradient[:, first:last].copy_(grad)
|
| 82 |
+
ce_parts.append(float(ce.detach())); kl_parts.append(float(kl.detach())); sizes.append(selected)
|
| 83 |
+
auxiliary, close, opening = None, 0., 0.
|
| 84 |
+
if closure_weight:
|
| 85 |
+
term = gates.closure_loss()
|
| 86 |
+
close = float(term.detach())
|
| 87 |
+
auxiliary = closure_weight*term
|
| 88 |
+
if opening_weight:
|
| 89 |
+
term = gates.opening_loss(opening_mask)
|
| 90 |
+
opening = float(term.detach())
|
| 91 |
+
term = opening_weight*term
|
| 92 |
+
auxiliary = term if auxiliary is None else auxiliary+term
|
| 93 |
+
if auxiliary is not None:
|
| 94 |
+
if not torch.isfinite(auxiliary):
|
| 95 |
+
raise FloatingPointError('Nonfinite gate objective')
|
| 96 |
+
scaled_auxiliary = scaler.scale(auxiliary) if scaler is not None else auxiliary
|
| 97 |
+
torch.autograd.backward((student_hidden, scaled_auxiliary), (gradient, None))
|
| 98 |
+
else:
|
| 99 |
+
student_hidden.backward(gradient)
|
| 100 |
+
ce_mean, kl_mean = math.fsum(ce_parts)/count, math.fsum(kl_parts)/count
|
| 101 |
+
return {'targets': count, 'forward_positions': targets.numel(), 'chunks': len(sizes),
|
| 102 |
+
'chunk_selected_targets': sizes, 'ce': ce_mean, 'teacher_to_student_kl': kl_mean,
|
| 103 |
+
'closure': close, 'opening': opening, 'weighted_closure': closure_weight*close,
|
| 104 |
+
'weighted_opening': opening_weight*opening,
|
| 105 |
+
'loss': ce_weight*ce_mean+kl_weight*kl_mean+closure_weight*close+opening_weight*opening,
|
| 106 |
+
'ce_coefficient': ce_weight, 'kl_coefficient': kl_weight, 'temperature': 1.,
|
| 107 |
+
'scaled_hidden_gradient_finite': bool(torch.isfinite(gradient).all()),
|
| 108 |
+
'scaled_hidden_gradient_nonzero': int(torch.count_nonzero(gradient)),
|
| 109 |
+
'scaled_hidden_gradient_elements': gradient.numel(),
|
| 110 |
+
'backbone_backward_calls': 1, 'gate_and_hidden_backward_joint': auxiliary is not None}
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def self_test():
|
| 114 |
+
from .resurface_native import GateCapture
|
| 115 |
+
torch.manual_seed(3289)
|
| 116 |
+
torch.set_num_threads(8)
|
| 117 |
+
head = torch.nn.Linear(5, 19, bias=False, dtype=torch.float16).requires_grad_(False)
|
| 118 |
+
targets = torch.tensor([[1, 2, 3, 4, 5, 6, 7]])
|
| 119 |
+
seed = torch.randn(1, 7, 5)*.25
|
| 120 |
+
teacher = (seed+.1).half()
|
| 121 |
+
mask = torch.tensor([[False, False, True, True, False, True, True]])
|
| 122 |
+
opening_mask = torch.tensor([[False, False, False, False, False, True, True]])
|
| 123 |
+
class Scale:
|
| 124 |
+
def scale(self, loss): return 8*loss
|
| 125 |
+
tests = []
|
| 126 |
+
for label, selected, klw, closew, openw in [('masked MK', mask, 0., 0., .02),
|
| 127 |
+
('prose', torch.ones_like(mask), .5, 3., 0.)]:
|
| 128 |
+
gradients, losses = [], []
|
| 129 |
+
cew = .5 if klw else 1.
|
| 130 |
+
for staged in (False, True):
|
| 131 |
+
master = seed.clone().requires_grad_()
|
| 132 |
+
hidden = master.half()
|
| 133 |
+
gates = GateCapture(master.mean(-1).unsqueeze(0))
|
| 134 |
+
if staged:
|
| 135 |
+
row = staged_loss_backward(hidden, targets, head, gates=gates, scaler=Scale(),
|
| 136 |
+
teacher_hidden=teacher, teacher_head=head, answer_mask=selected, ce_weight=cew,
|
| 137 |
+
kl_weight=klw, closure_weight=closew, opening_mask=opening_mask,
|
| 138 |
+
opening_weight=openw, chunk_tokens=3)
|
| 139 |
+
losses.append(row['loss'])
|
| 140 |
+
assert row['targets'] == int(selected.sum()) and row['chunk_selected_targets'][-1] == 1
|
| 141 |
+
assert row['backbone_backward_calls'] == 1 and row['scaled_hidden_gradient_finite']
|
| 142 |
+
else:
|
| 143 |
+
logits = head(hidden[selected]).float()
|
| 144 |
+
ce = F.cross_entropy(logits, targets[selected], reduction='sum')/selected.sum()
|
| 145 |
+
with torch.no_grad(): teacher_logp = F.log_softmax(head(teacher[selected]).float(), -1)
|
| 146 |
+
kl = F.kl_div(F.log_softmax(logits, -1), teacher_logp, reduction='sum', log_target=True)/selected.sum()
|
| 147 |
+
loss = cew*ce+klw*kl+closew*gates.closure_loss()+openw*gates.opening_loss(opening_mask)
|
| 148 |
+
(8*loss).backward(); losses.append(float(loss.detach()))
|
| 149 |
+
gradients.append(master.grad)
|
| 150 |
+
torch.testing.assert_close(gradients[0], gradients[1], rtol=.002, atol=.0001)
|
| 151 |
+
assert abs(losses[0]-losses[1]) < 2e-6
|
| 152 |
+
tests.append(label+': direct gradient, short tail, gate branch and scale once')
|
| 153 |
+
# Non-answer labels cannot affect masked-MK objective or gradient.
|
| 154 |
+
rows = []
|
| 155 |
+
for changed in (False, True):
|
| 156 |
+
master = seed.clone().requires_grad_()
|
| 157 |
+
modified = targets.clone()
|
| 158 |
+
if changed: modified[~mask] = (modified[~mask]+4)%19
|
| 159 |
+
receipt = staged_loss_backward(master.half(), modified, head, answer_mask=mask, chunk_tokens=3)
|
| 160 |
+
rows.append((receipt['loss'], master.grad))
|
| 161 |
+
assert rows[0][0] == rows[1][0] and torch.equal(rows[0][1], rows[1][1])
|
| 162 |
+
tests.append('Prompt-label changes cannot affect answer-only CE')
|
| 163 |
+
invalid = GateCapture(torch.full((1, 1, 7), float('inf')))
|
| 164 |
+
try:
|
| 165 |
+
staged_loss_backward(seed.clone().requires_grad_().half(), targets, head, gates=invalid, answer_mask=mask)
|
| 166 |
+
except FloatingPointError:
|
| 167 |
+
pass
|
| 168 |
+
else:
|
| 169 |
+
raise AssertionError('Nonfinite gate logits accepted by MK with zero closure weight')
|
| 170 |
+
tests.append('Reject nonfinite router logits even when MK closure coefficient is zero')
|
| 171 |
+
return {'complete': True, 'tests': tests, 'passed': len(tests),
|
| 172 |
+
'cuda_initialized': torch.cuda.is_initialized(), 'scope': 'CPU small vocabulary loss algebra only'}
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
if __name__ == '__main__':
|
| 176 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 177 |
+
parser.add_argument('--self-test', action='store_true', required=True)
|
| 178 |
+
parser.parse_args()
|
| 179 |
+
print(json.dumps(self_test(), indent=2))
|
mamba2_recall/resurface_native.py
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Experimental post-D Resurface-inspired adapter for the frozen native runtime.
|
| 2 |
+
|
| 3 |
+
This is NOT the original pre-D Resurface insertion: native SSD already includes
|
| 4 |
+
D*x when norm's prehook sees y. No scan, norm, projection or cache is replaced.
|
| 5 |
+
Each layer applies y + sigmoid(w*u+b)*g*(V@y), without EMA or any extra state.
|
| 6 |
+
|
| 7 |
+
Usage (keep the bank alive through backward, including checkpoint replay):
|
| 8 |
+
bank = ResurfaceNative(model, gate_mode='soft', expected_base_hashes=hashes)
|
| 9 |
+
hidden, gates = bank.forward_hidden(ids, use_checkpoint=True)
|
| 10 |
+
loss = task_loss(hidden) + gates.closure_loss() + gates.opening_loss(mask)
|
| 11 |
+
loss.backward()
|
| 12 |
+
bank.export_fp16(path, binding={'base_manifest_sha256': ...})
|
| 13 |
+
bank.close()
|
| 14 |
+
with install_fp16(model, path, expected_base_hashes=hashes) as deployed:
|
| 15 |
+
logits = model(ids).logits # Same gate mode for every evaluation task.
|
| 16 |
+
|
| 17 |
+
The external ModuleDict never becomes a child of the base model. Hooks support
|
| 18 |
+
native prefill and native model(..., inference_params=...) recurrent decoding;
|
| 19 |
+
calling mixer.step() directly bypasses the mixer-input hook and is unsupported.
|
| 20 |
+
Gate capture is returned by EACH checkpoint invocation, never appended during
|
| 21 |
+
replay. Hooks are synchronous/non-reentrant; concurrent forwards fail closed.
|
| 22 |
+
Hard mode uses threshold(logit > 0), with a sigmoid STE only during training.
|
| 23 |
+
V=0 plus a closed hard gate is a dead point for answer CE alone: explicit opening
|
| 24 |
+
loss or an independently declared soft warmup is required. This module chooses
|
| 25 |
+
neither a training recipe nor a quality gate.
|
| 26 |
+
"""
|
| 27 |
+
from __future__ import annotations
|
| 28 |
+
|
| 29 |
+
import argparse
|
| 30 |
+
from contextlib import contextmanager
|
| 31 |
+
from dataclasses import dataclass
|
| 32 |
+
import hashlib
|
| 33 |
+
import json
|
| 34 |
+
from pathlib import Path
|
| 35 |
+
import tempfile
|
| 36 |
+
import weakref
|
| 37 |
+
|
| 38 |
+
import torch
|
| 39 |
+
from torch import nn
|
| 40 |
+
import torch.nn.functional as F
|
| 41 |
+
from torch.utils.checkpoint import checkpoint
|
| 42 |
+
|
| 43 |
+
FORMAT = 'MAMBA2_POST_D_RESURFACE_FP16_V1'
|
| 44 |
+
FIELDS = ('V_read', 'g_read', 'router_w', 'router_b')
|
| 45 |
+
VARIANT = 'post-D native norm-prehook; memoryless cross-head mixing'
|
| 46 |
+
_OWNERS = weakref.WeakKeyDictionary()
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def tensor_hash(value):
|
| 50 |
+
value = value.detach()
|
| 51 |
+
digest = hashlib.sha256()
|
| 52 |
+
if value.ndim == 0:
|
| 53 |
+
digest.update(value.cpu().contiguous().numpy().tobytes())
|
| 54 |
+
else:
|
| 55 |
+
for first in range(0, value.shape[0], 128):
|
| 56 |
+
digest.update(value[first:first+128].cpu().contiguous().numpy().tobytes())
|
| 57 |
+
return digest.hexdigest()
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def file_hash(path):
|
| 61 |
+
digest = hashlib.sha256()
|
| 62 |
+
with Path(path).open('rb') as stream:
|
| 63 |
+
for block in iter(lambda: stream.read(8*1024*1024), b''):
|
| 64 |
+
digest.update(block)
|
| 65 |
+
return digest.hexdigest()
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@dataclass(frozen=True)
|
| 69 |
+
class GateCapture:
|
| 70 |
+
"""FP32 logits [layers,batch,tokens]; all terms are differentiable."""
|
| 71 |
+
logits: torch.Tensor
|
| 72 |
+
|
| 73 |
+
def soft_probabilities(self):
|
| 74 |
+
return torch.sigmoid(self.logits)
|
| 75 |
+
|
| 76 |
+
def closure_loss(self, budget=0.006, budget_coefficient=10.0):
|
| 77 |
+
if not 0 <= budget <= 1 or budget_coefficient < 0:
|
| 78 |
+
raise ValueError('Invalid closure budget/coefficient')
|
| 79 |
+
# Mean BCE and per-layer mean-openness penalty, then mean over layers.
|
| 80 |
+
close = F.softplus(self.logits).mean(dim=(1, 2))
|
| 81 |
+
openness = self.soft_probabilities().mean(dim=(1, 2))
|
| 82 |
+
return (close + budget_coefficient * F.relu(openness-budget)).mean()
|
| 83 |
+
|
| 84 |
+
def opening_loss(self, mask):
|
| 85 |
+
"""Mean BCE(logit,1) only at explicit TRAIN query-token positions."""
|
| 86 |
+
if mask.dtype != torch.bool or tuple(mask.shape) != tuple(self.logits.shape[1:]):
|
| 87 |
+
raise ValueError('Opening mask must be bool[batch,tokens]')
|
| 88 |
+
if mask.device != self.logits.device or not bool(mask.any()):
|
| 89 |
+
raise ValueError('Opening mask must share device and select tokens')
|
| 90 |
+
return F.softplus(-self.logits[:, mask]).mean()
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class _Adapter(nn.Module):
|
| 94 |
+
def __init__(self, width, heads, *, device, trainable):
|
| 95 |
+
super().__init__()
|
| 96 |
+
dtype = torch.float32 if trainable else torch.float16
|
| 97 |
+
for name, value in {
|
| 98 |
+
'V_read': torch.zeros(heads, heads, device=device, dtype=dtype),
|
| 99 |
+
'g_read': torch.ones(heads, device=device, dtype=dtype),
|
| 100 |
+
'router_w': torch.zeros(width, device=device, dtype=dtype),
|
| 101 |
+
'router_b': torch.tensor(-4.0, device=device, dtype=dtype),
|
| 102 |
+
}.items():
|
| 103 |
+
self.register_parameter(name, nn.Parameter(value, requires_grad=trainable))
|
| 104 |
+
|
| 105 |
+
def forward(self, y, u, heads, head_dim, mode, trainable):
|
| 106 |
+
# Cast INSIDE the hook, hence inside every checkpoint replay.
|
| 107 |
+
V, g, w, b = (getattr(self, name).to(torch.float16) for name in FIELDS)
|
| 108 |
+
logits = (torch.einsum('...d,d->...', u, w) + b).float()
|
| 109 |
+
soft = torch.sigmoid(logits)
|
| 110 |
+
if mode == 'soft':
|
| 111 |
+
gate = soft
|
| 112 |
+
else:
|
| 113 |
+
hard = (logits > 0).to(soft.dtype)
|
| 114 |
+
gate = hard + (soft-soft.detach()) if trainable and torch.is_grad_enabled() else hard
|
| 115 |
+
yh = y.reshape(*y.shape[:-1], heads, head_dim)
|
| 116 |
+
mix = torch.einsum('ij,...jp->...ip', V, yh)
|
| 117 |
+
correction = gate.to(y.dtype)[..., None, None] * g[..., None] * mix
|
| 118 |
+
return (yh+correction).reshape_as(y), logits
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
class ResurfaceNative:
|
| 122 |
+
"""Separate adapter parameters; original model keeps its exact parameter set."""
|
| 123 |
+
def __init__(self, model, gate_mode='soft', *, expected_base_hashes=None,
|
| 124 |
+
trainable=True, production=True):
|
| 125 |
+
if gate_mode not in ('soft', 'hard'):
|
| 126 |
+
raise ValueError('Gate mode must be explicitly soft or hard')
|
| 127 |
+
if model in _OWNERS and _OWNERS[model]() is not None:
|
| 128 |
+
raise RuntimeError('A Resurface adapter is already attached to this model')
|
| 129 |
+
self.model, self._gate_mode = model, gate_mode
|
| 130 |
+
self.trainable, self.production = bool(trainable), bool(production)
|
| 131 |
+
self.adapters = nn.ModuleDict()
|
| 132 |
+
self._frames, self._requests, self._handles = {}, {}, []
|
| 133 |
+
self.closed = False
|
| 134 |
+
self._base = dict(model.named_parameters())
|
| 135 |
+
if any(p.dtype != torch.float16 or p.requires_grad or p.grad is not None for p in self._base.values()):
|
| 136 |
+
raise ValueError('Load an already-frozen FP16 base with no gradients')
|
| 137 |
+
if production and (len(self._base) != 507 or sum(p.numel() for p in self._base.values()) != 8236999680):
|
| 138 |
+
raise ValueError('Production base must cover507 tensors/8,236,999,680 parameters')
|
| 139 |
+
self._identities = {name: (id(p), p.data_ptr(), p._version) for name, p in self._base.items()}
|
| 140 |
+
self._base_hashes = dict(expected_base_hashes) if expected_base_hashes is not None else None
|
| 141 |
+
if self._base_hashes is not None and set(self._base_hashes) != set(self._base):
|
| 142 |
+
raise ValueError('Expected base ledger must cover every original parameter')
|
| 143 |
+
backbone = model.backbone
|
| 144 |
+
if backbone.fused_add_norm or backbone.residual_in_fp32:
|
| 145 |
+
raise ValueError('Only frozen unfused FP16 residual orchestration is supported')
|
| 146 |
+
if production and len(backbone.layers) != 56:
|
| 147 |
+
raise ValueError('Production layer count must be56')
|
| 148 |
+
self.geometry = []
|
| 149 |
+
for index, layer in enumerate(backbone.layers):
|
| 150 |
+
mx = layer.mixer
|
| 151 |
+
if layer.fused_add_norm or layer.residual_in_fp32 or layer.mlp is not None:
|
| 152 |
+
raise ValueError('Unsupported native block')
|
| 153 |
+
if mx.use_mem_eff_path or not mx.rmsnorm:
|
| 154 |
+
raise ValueError('Native explicit gated norm must execute on every call')
|
| 155 |
+
width, heads, head_dim = mx.d_model, mx.nheads, mx.headdim
|
| 156 |
+
if mx.d_ssm != heads*head_dim:
|
| 157 |
+
raise ValueError('Unsupported head geometry')
|
| 158 |
+
if production and (width, heads, head_dim, mx.ngroups) != (4096, 128, 64, 8):
|
| 159 |
+
raise ValueError('Production Mamba2 geometry differs')
|
| 160 |
+
self.geometry.append({'width': width, 'heads': heads, 'head_dim': head_dim})
|
| 161 |
+
self.adapters[f'layer{index}'] = _Adapter(width, heads, device=mx.in_proj.weight.device,
|
| 162 |
+
trainable=self.trainable)
|
| 163 |
+
self.masters = {f'{key}.{name}': p for key, module in self.adapters.items()
|
| 164 |
+
for name, p in module.named_parameters()}
|
| 165 |
+
_OWNERS[model] = weakref.ref(self)
|
| 166 |
+
try:
|
| 167 |
+
for index, layer in enumerate(backbone.layers):
|
| 168 |
+
self._handles.append(layer.mixer.register_forward_pre_hook(self._input_hook(index), with_kwargs=True))
|
| 169 |
+
self._handles.append(layer.mixer.norm.register_forward_pre_hook(self._norm_hook(index), with_kwargs=True))
|
| 170 |
+
self._handles.append(layer.mixer.register_forward_hook(self._end_hook(index), with_kwargs=True, always_call=True))
|
| 171 |
+
except Exception:
|
| 172 |
+
self.close()
|
| 173 |
+
raise
|
| 174 |
+
|
| 175 |
+
def parameters(self):
|
| 176 |
+
return list(self.masters.values())
|
| 177 |
+
|
| 178 |
+
@property
|
| 179 |
+
def gate_mode(self):
|
| 180 |
+
return self._gate_mode
|
| 181 |
+
|
| 182 |
+
def _require_open(self):
|
| 183 |
+
if self.closed:
|
| 184 |
+
raise RuntimeError('Adapter was closed before this invocation/replay')
|
| 185 |
+
|
| 186 |
+
def _input_hook(self, index):
|
| 187 |
+
def hook(module, args, kwargs):
|
| 188 |
+
self._require_open()
|
| 189 |
+
if index in self._frames:
|
| 190 |
+
raise RuntimeError('Concurrent/reentrant mixer invocation is unsupported')
|
| 191 |
+
u = args[0] if args else kwargs.get('u')
|
| 192 |
+
if not isinstance(u, torch.Tensor) or u.ndim not in (2, 3):
|
| 193 |
+
raise ValueError('Mixer input must be rank2/3 tensor')
|
| 194 |
+
if u.dtype != torch.float16 or u.shape[-1] != self.geometry[index]['width']:
|
| 195 |
+
raise ValueError('Mixer input geometry/dtype differs')
|
| 196 |
+
frame = self._requests.get(index, {})
|
| 197 |
+
frame.update(u=u, logits=None, consumed=False)
|
| 198 |
+
self._frames[index] = frame
|
| 199 |
+
return hook
|
| 200 |
+
|
| 201 |
+
def _norm_hook(self, index):
|
| 202 |
+
def hook(module, args, kwargs):
|
| 203 |
+
frame = self._frames.get(index)
|
| 204 |
+
if frame is None or frame['consumed']:
|
| 205 |
+
raise RuntimeError('Norm hook has no unique corresponding mixer input')
|
| 206 |
+
y = args[0] if args else kwargs.get('x')
|
| 207 |
+
geo = self.geometry[index]
|
| 208 |
+
if not isinstance(y, torch.Tensor) or y.ndim not in (2, 3) or y.dtype != torch.float16:
|
| 209 |
+
raise ValueError('Native norm input must be rank2/3 FP16')
|
| 210 |
+
if y.shape[-1] != geo['heads']*geo['head_dim']:
|
| 211 |
+
raise ValueError('Native norm/head shape differs')
|
| 212 |
+
u = frame['u']
|
| 213 |
+
if u.numel()//geo['width'] != y.numel()//y.shape[-1]:
|
| 214 |
+
raise ValueError('Mixer input and readout token counts differ')
|
| 215 |
+
u = u.reshape(*y.shape[:-1], geo['width'])
|
| 216 |
+
adapted, logits = self.adapters[f'layer{index}'](y, u, geo['heads'], geo['head_dim'],
|
| 217 |
+
self.gate_mode, self.trainable)
|
| 218 |
+
frame.update(u=None, consumed=True, logits=logits)
|
| 219 |
+
if args:
|
| 220 |
+
return (adapted, *args[1:]), kwargs
|
| 221 |
+
return args, {**kwargs, 'x': adapted}
|
| 222 |
+
return hook
|
| 223 |
+
|
| 224 |
+
def _end_hook(self, index):
|
| 225 |
+
def hook(module, args, kwargs, output):
|
| 226 |
+
frame = self._frames.pop(index, None)
|
| 227 |
+
if frame is not None:
|
| 228 |
+
frame['u'] = None
|
| 229 |
+
if output is not None and not frame['consumed']:
|
| 230 |
+
raise RuntimeError('Native mixer bypassed adapter injection')
|
| 231 |
+
return hook
|
| 232 |
+
|
| 233 |
+
@contextmanager
|
| 234 |
+
def _capture(self, index):
|
| 235 |
+
self._require_open()
|
| 236 |
+
if index in self._requests or index in self._frames:
|
| 237 |
+
raise RuntimeError('Overlapping gate capture')
|
| 238 |
+
frame = {}
|
| 239 |
+
self._requests[index] = frame
|
| 240 |
+
try:
|
| 241 |
+
yield frame
|
| 242 |
+
finally:
|
| 243 |
+
self._requests.pop(index, None)
|
| 244 |
+
active = self._frames.pop(index, None)
|
| 245 |
+
if active is not None:
|
| 246 |
+
active['u'] = None
|
| 247 |
+
frame.pop('u', None)
|
| 248 |
+
|
| 249 |
+
def forward_hidden(self, input_ids, use_checkpoint=True):
|
| 250 |
+
"""Native blocks/final norm; only adapter leaves receive gradients."""
|
| 251 |
+
self._require_open()
|
| 252 |
+
hidden = self.model.backbone.embedding(input_ids)
|
| 253 |
+
residual, all_logits = None, []
|
| 254 |
+
for index, layer in enumerate(self.model.backbone.layers):
|
| 255 |
+
def run(h, r, index=index, layer=layer):
|
| 256 |
+
with self._capture(index) as frame:
|
| 257 |
+
h, r = layer(h, r, inference_params=None)
|
| 258 |
+
if frame.get('logits') is None:
|
| 259 |
+
raise RuntimeError('Gate capture missing from this block invocation')
|
| 260 |
+
return h, r, frame['logits']
|
| 261 |
+
if use_checkpoint and torch.is_grad_enabled():
|
| 262 |
+
hidden, residual, logits = checkpoint(run, hidden, residual, use_reentrant=False,
|
| 263 |
+
preserve_rng_state=True)
|
| 264 |
+
else:
|
| 265 |
+
hidden, residual, logits = run(hidden, residual)
|
| 266 |
+
all_logits.append(logits) # Once per OUTER layer, never inside replay.
|
| 267 |
+
residual = hidden+residual if residual is not None else hidden
|
| 268 |
+
hidden = self.model.backbone.norm_f(residual.to(self.model.backbone.norm_f.weight.dtype))
|
| 269 |
+
return hidden, GateCapture(torch.stack(all_logits))
|
| 270 |
+
|
| 271 |
+
def state_dict(self):
|
| 272 |
+
return {name: p.detach().cpu().clone() for name, p in self.masters.items()}
|
| 273 |
+
|
| 274 |
+
def load_state_dict(self, values):
|
| 275 |
+
dtype = torch.float32 if self.trainable else torch.float16
|
| 276 |
+
if set(values) != set(self.masters):
|
| 277 |
+
raise ValueError('Adapter keys differ')
|
| 278 |
+
for name, value in values.items():
|
| 279 |
+
if value.shape != self.masters[name].shape or value.dtype != dtype or not torch.isfinite(value).all():
|
| 280 |
+
raise ValueError(f'Invalid adapter tensor: {name}')
|
| 281 |
+
with torch.no_grad():
|
| 282 |
+
for name, value in values.items():
|
| 283 |
+
self.masters[name].copy_(value)
|
| 284 |
+
|
| 285 |
+
def assert_base_frozen(self, check_values=False):
|
| 286 |
+
now = dict(self.model.named_parameters())
|
| 287 |
+
if set(now) != set(self._base):
|
| 288 |
+
raise RuntimeError('Base parameter inventory changed')
|
| 289 |
+
for name, p in now.items():
|
| 290 |
+
if (id(p), p.data_ptr(), p._version) != self._identities[name] or p.requires_grad or p.grad is not None:
|
| 291 |
+
raise RuntimeError(f'Base identity/version/gradient changed: {name}')
|
| 292 |
+
if check_values:
|
| 293 |
+
if self._base_hashes is None:
|
| 294 |
+
raise ValueError('Content audit requires an independently supplied base hash ledger')
|
| 295 |
+
for name, p in now.items():
|
| 296 |
+
if tensor_hash(p) != self._base_hashes[name]:
|
| 297 |
+
raise RuntimeError(f'Base content changed: {name}')
|
| 298 |
+
return {'tensors': len(now), 'parameters': sum(p.numel() for p in now.values()),
|
| 299 |
+
'identity_version_gradients_unchanged': True, 'actual_content_checked': check_values}
|
| 300 |
+
|
| 301 |
+
def export_fp16(self, path, binding=None):
|
| 302 |
+
self.assert_base_frozen()
|
| 303 |
+
values = {name: p.detach().cpu().half() for name, p in self.masters.items()}
|
| 304 |
+
if not all(torch.isfinite(v).all() for v in values.values()):
|
| 305 |
+
raise FloatingPointError('Nonfinite FP16 export')
|
| 306 |
+
payload = {'format': FORMAT, 'variant': VARIANT, 'gate_mode': self.gate_mode,
|
| 307 |
+
'geometry': self.geometry, 'binding': dict(binding or {}), 'tensors': values}
|
| 308 |
+
path = Path(path)
|
| 309 |
+
with path.open('xb') as stream:
|
| 310 |
+
torch.save(payload, stream)
|
| 311 |
+
restored = read_fp16(path, expected_binding=payload['binding'])
|
| 312 |
+
hashes = {name: tensor_hash(value) for name, value in values.items()}
|
| 313 |
+
if hashes != {name: tensor_hash(value) for name, value in restored['tensors'].items()}:
|
| 314 |
+
raise RuntimeError('Actual FP16 file roundtrip differs')
|
| 315 |
+
return {'file': path.name, 'bytes': path.stat().st_size, 'sha256': file_hash(path),
|
| 316 |
+
'parameters': sum(v.numel() for v in values.values()),
|
| 317 |
+
'payload_bytes': sum(v.numel()*v.element_size() for v in values.values()),
|
| 318 |
+
'tensor_sha256': hashes, 'gate_mode': self.gate_mode, 'roundtrip_bitwise_equal': True}
|
| 319 |
+
|
| 320 |
+
def close(self):
|
| 321 |
+
for handle in self._handles:
|
| 322 |
+
handle.remove()
|
| 323 |
+
self._handles.clear()
|
| 324 |
+
self._frames.clear()
|
| 325 |
+
self._requests.clear()
|
| 326 |
+
if self.model in _OWNERS and _OWNERS[self.model]() is self:
|
| 327 |
+
del _OWNERS[self.model]
|
| 328 |
+
self.closed = True
|
| 329 |
+
|
| 330 |
+
def __enter__(self):
|
| 331 |
+
self._require_open()
|
| 332 |
+
return self
|
| 333 |
+
|
| 334 |
+
def __exit__(self, *exc):
|
| 335 |
+
self.close()
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
def read_fp16(path, expected_binding=None):
|
| 339 |
+
payload = torch.load(path, map_location='cpu', weights_only=True)
|
| 340 |
+
if (set(payload) != {'format', 'variant', 'gate_mode', 'geometry', 'binding', 'tensors'}
|
| 341 |
+
or payload['format'] != FORMAT or payload['variant'] != VARIANT
|
| 342 |
+
or payload['gate_mode'] not in ('soft', 'hard') or not isinstance(payload['binding'], dict)):
|
| 343 |
+
raise ValueError('Invalid Resurface export header')
|
| 344 |
+
if expected_binding is not None and payload['binding'] != expected_binding:
|
| 345 |
+
raise ValueError('Resurface binding differs')
|
| 346 |
+
expected = {}
|
| 347 |
+
for index, geo in enumerate(payload['geometry']):
|
| 348 |
+
if set(geo) != {'width', 'heads', 'head_dim'} or any(type(v) is not int or v <= 0 for v in geo.values()):
|
| 349 |
+
raise ValueError('Invalid export geometry')
|
| 350 |
+
expected.update({f'layer{index}.{name}': shape for name, shape in {
|
| 351 |
+
'V_read': (geo['heads'], geo['heads']), 'g_read': (geo['heads'],),
|
| 352 |
+
'router_w': (geo['width'],), 'router_b': (),
|
| 353 |
+
}.items()})
|
| 354 |
+
if not expected or set(payload['tensors']) != set(expected):
|
| 355 |
+
raise ValueError('Export tensor inventory differs')
|
| 356 |
+
for name, shape in expected.items():
|
| 357 |
+
v = payload['tensors'][name]
|
| 358 |
+
if not isinstance(v, torch.Tensor) or v.dtype != torch.float16 or tuple(v.shape) != shape or not torch.isfinite(v).all():
|
| 359 |
+
raise ValueError(f'Invalid exported tensor: {name}')
|
| 360 |
+
return payload
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
def install_fp16(model, path, *, expected_binding=None, expected_base_hashes=None, production=True):
|
| 364 |
+
"""Fresh eval-only adapter loaded from actual serialized half tensors."""
|
| 365 |
+
payload = read_fp16(path, expected_binding)
|
| 366 |
+
bank = ResurfaceNative(model, payload['gate_mode'], expected_base_hashes=expected_base_hashes,
|
| 367 |
+
trainable=False, production=production)
|
| 368 |
+
try:
|
| 369 |
+
if bank.geometry != payload['geometry']:
|
| 370 |
+
raise ValueError('Export does not fit actual native model')
|
| 371 |
+
bank.load_state_dict(payload['tensors'])
|
| 372 |
+
except Exception:
|
| 373 |
+
bank.close()
|
| 374 |
+
raise
|
| 375 |
+
return bank
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
def self_test():
|
| 379 |
+
"""Bounded CPU hook tests; not an 8B native-kernel or quality validation."""
|
| 380 |
+
torch.set_num_threads(8)
|
| 381 |
+
torch.manual_seed(9231)
|
| 382 |
+
|
| 383 |
+
class Norm(nn.Module):
|
| 384 |
+
def __init__(self, width):
|
| 385 |
+
super().__init__()
|
| 386 |
+
self.weight = nn.Parameter(torch.ones(width, dtype=torch.float16))
|
| 387 |
+
def forward(self, x, z=None):
|
| 388 |
+
if z is not None:
|
| 389 |
+
x = x*F.silu(z)
|
| 390 |
+
return (x.float()*torch.rsqrt(x.float().square().mean(-1, keepdim=True)+1e-5)).half()*self.weight
|
| 391 |
+
|
| 392 |
+
class Mixer(nn.Module):
|
| 393 |
+
d_model, d_ssm, nheads, headdim, ngroups = 4, 4, 2, 2, 1
|
| 394 |
+
use_mem_eff_path, rmsnorm = False, True
|
| 395 |
+
def __init__(self, index):
|
| 396 |
+
super().__init__()
|
| 397 |
+
self.index, self.fail = index, False
|
| 398 |
+
self.in_proj = nn.Linear(4, 8, bias=False, dtype=torch.float16)
|
| 399 |
+
self.norm = Norm(4)
|
| 400 |
+
self.out_proj = nn.Linear(4, 4, bias=False, dtype=torch.float16)
|
| 401 |
+
def forward(self, u, inference_params=None):
|
| 402 |
+
if self.fail:
|
| 403 |
+
raise RuntimeError('intentional toy mixer failure')
|
| 404 |
+
if inference_params is not None and u.shape[1] == 1:
|
| 405 |
+
return self.step(u, inference_params)
|
| 406 |
+
x, z = self.in_proj(u).chunk(2, -1)
|
| 407 |
+
if inference_params is not None:
|
| 408 |
+
inference_params[self.index] = x[:, -1].clone()
|
| 409 |
+
return self.out_proj(self.norm(x, z))
|
| 410 |
+
def step(self, u, cache):
|
| 411 |
+
x, z = self.in_proj(u[:, 0]).chunk(2, -1)
|
| 412 |
+
x = x+cache.get(self.index, torch.zeros_like(x))*0.125
|
| 413 |
+
cache[self.index] = x.clone()
|
| 414 |
+
return self.out_proj(self.norm(x, z)).unsqueeze(1)
|
| 415 |
+
|
| 416 |
+
class Block(nn.Module):
|
| 417 |
+
fused_add_norm, residual_in_fp32, mlp = False, False, None
|
| 418 |
+
def __init__(self, index):
|
| 419 |
+
super().__init__()
|
| 420 |
+
self.norm, self.mixer = Norm(4), Mixer(index)
|
| 421 |
+
def forward(self, hidden, residual=None, inference_params=None):
|
| 422 |
+
residual = hidden+residual if residual is not None else hidden
|
| 423 |
+
return self.mixer(self.norm(residual), inference_params=inference_params), residual
|
| 424 |
+
|
| 425 |
+
class Model(nn.Module):
|
| 426 |
+
def __init__(self):
|
| 427 |
+
super().__init__()
|
| 428 |
+
self.backbone = nn.Module()
|
| 429 |
+
self.backbone.fused_add_norm = self.backbone.residual_in_fp32 = False
|
| 430 |
+
self.backbone.embedding = nn.Embedding(17, 4, dtype=torch.float16)
|
| 431 |
+
self.backbone.layers = nn.ModuleList([Block(i) for i in range(2)])
|
| 432 |
+
self.backbone.norm_f = Norm(4)
|
| 433 |
+
self.lm_head = nn.Linear(4, 17, bias=False, dtype=torch.float16)
|
| 434 |
+
def forward(self, ids, inference_params=None):
|
| 435 |
+
h, r = self.backbone.embedding(ids), None
|
| 436 |
+
for layer in self.backbone.layers:
|
| 437 |
+
h, r = layer(h, r, inference_params=inference_params)
|
| 438 |
+
return self.lm_head(self.backbone.norm_f(h+r))
|
| 439 |
+
|
| 440 |
+
model = Model().eval().requires_grad_(False)
|
| 441 |
+
ids = torch.tensor([[1, 2, 3, 4, 5, 6, 7]])
|
| 442 |
+
hashes = {name: tensor_hash(p) for name, p in model.named_parameters()}
|
| 443 |
+
tests = []
|
| 444 |
+
def passed(name): tests.append(name)
|
| 445 |
+
def rejects(call):
|
| 446 |
+
try: call()
|
| 447 |
+
except (ValueError, RuntimeError, FileExistsError): return
|
| 448 |
+
raise AssertionError('Expected fail-closed rejection')
|
| 449 |
+
def zero_grads(bank):
|
| 450 |
+
for p in bank.parameters(): p.grad = None
|
| 451 |
+
def cached():
|
| 452 |
+
cache = {}
|
| 453 |
+
prefill = model(ids[:, :4], inference_params=cache)
|
| 454 |
+
step = model(ids[:, 4:5], inference_params=cache)
|
| 455 |
+
return tensor_hash(prefill), tensor_hash(step), {k: tensor_hash(v) for k, v in cache.items()}
|
| 456 |
+
|
| 457 |
+
with torch.no_grad():
|
| 458 |
+
baseline, base_cache = tensor_hash(model(ids)), cached()
|
| 459 |
+
bank = ResurfaceNative(model, expected_base_hashes=hashes, production=False)
|
| 460 |
+
with torch.no_grad():
|
| 461 |
+
assert tensor_hash(model(ids)) == baseline and cached() == base_cache
|
| 462 |
+
bank.assert_base_frozen(check_values=True)
|
| 463 |
+
passed('zero soft adapter native prefill/recurrent-call/cache parity; external inventory')
|
| 464 |
+
|
| 465 |
+
hidden, gates = bank.forward_hidden(ids, use_checkpoint=False)
|
| 466 |
+
model.lm_head(hidden).float().square().mean().backward()
|
| 467 |
+
for name, p in bank.masters.items():
|
| 468 |
+
assert p.grad is not None and torch.isfinite(p.grad).all()
|
| 469 |
+
assert bool(torch.count_nonzero(p.grad)) == name.endswith('.V_read'), name
|
| 470 |
+
passed('soft zero-V staggered gradients: V nonzero; router and amplitudes zero')
|
| 471 |
+
|
| 472 |
+
with torch.no_grad():
|
| 473 |
+
for key, adapter in bank.adapters.items():
|
| 474 |
+
adapter.V_read.copy_(torch.tensor([[.0713, -.0927], [.1319, .0423]]))
|
| 475 |
+
adapter.router_w.copy_(torch.tensor([.0371, -.0447, .0233, .0631]))
|
| 476 |
+
mask = torch.tensor([[False, False, False, False, False, True, True]])
|
| 477 |
+
outputs, gradients = [], []
|
| 478 |
+
for checkpointed in (False, True):
|
| 479 |
+
zero_grads(bank)
|
| 480 |
+
hidden, gates = bank.forward_hidden(ids, use_checkpoint=checkpointed)
|
| 481 |
+
assert gates.logits.shape == (2, 1, 7)
|
| 482 |
+
manual = F.binary_cross_entropy_with_logits(gates.logits[:, mask], torch.ones_like(gates.logits[:, mask]))
|
| 483 |
+
torch.testing.assert_close(gates.opening_loss(mask), manual, rtol=0, atol=0)
|
| 484 |
+
loss = model.lm_head(hidden).float().square().mean()+.03*gates.closure_loss()+.02*gates.opening_loss(mask)
|
| 485 |
+
loss.backward()
|
| 486 |
+
outputs.append((tensor_hash(hidden), tensor_hash(gates.logits)))
|
| 487 |
+
gradients.append({name: p.grad.detach().clone() for name, p in bank.masters.items()})
|
| 488 |
+
assert not bank._frames and not bank._requests
|
| 489 |
+
assert outputs[0] == outputs[1]
|
| 490 |
+
for name in gradients[0]:
|
| 491 |
+
torch.testing.assert_close(gradients[0][name], gradients[1][name], rtol=0, atol=0)
|
| 492 |
+
assert torch.isfinite(gradients[1][name]).all() and torch.count_nonzero(gradients[1][name]), name
|
| 493 |
+
with torch.no_grad():
|
| 494 |
+
hidden, _ = bank.forward_hidden(ids, use_checkpoint=False)
|
| 495 |
+
assert tensor_hash(model.lm_head(hidden)) == tensor_hash(model(ids))
|
| 496 |
+
passed('checkpoint/native outputs, returned capture and every adapter gradient exact')
|
| 497 |
+
|
| 498 |
+
model.backbone.layers[0].mixer.fail = True
|
| 499 |
+
rejects(lambda: bank.forward_hidden(ids))
|
| 500 |
+
assert not bank._frames and not bank._requests
|
| 501 |
+
model.backbone.layers[0].mixer.fail = False
|
| 502 |
+
rejects(lambda: gates.opening_loss(torch.zeros_like(mask)))
|
| 503 |
+
rejects(lambda: ResurfaceNative(model, production=False))
|
| 504 |
+
passed('exception cleanup, empty opening mask and duplicate attachment rejected')
|
| 505 |
+
|
| 506 |
+
with tempfile.TemporaryDirectory(prefix='resurface-native-cpu-') as temporary:
|
| 507 |
+
path = Path(temporary)/'adapter.pt'
|
| 508 |
+
with torch.no_grad(): expected = tensor_hash(model(ids))
|
| 509 |
+
receipt = bank.export_fp16(path, binding={'toy_base': 'fixed'})
|
| 510 |
+
expected_values = {name: p.detach().half().clone() for name, p in bank.masters.items()}
|
| 511 |
+
rejects(lambda: bank.export_fp16(path))
|
| 512 |
+
bank.close()
|
| 513 |
+
with install_fp16(model, path, expected_binding={'toy_base': 'fixed'}, expected_base_hashes=hashes,
|
| 514 |
+
production=False) as deployed:
|
| 515 |
+
assert not any(p.requires_grad for p in deployed.parameters())
|
| 516 |
+
assert all(p.dtype == torch.float16 for p in deployed.parameters())
|
| 517 |
+
for name, p in deployed.masters.items(): assert tensor_hash(p) == tensor_hash(expected_values[name])
|
| 518 |
+
with torch.no_grad(): assert tensor_hash(model(ids)) == expected
|
| 519 |
+
deployed.assert_base_frozen(check_values=True)
|
| 520 |
+
assert tensor_hash(model(ids)) == baseline
|
| 521 |
+
invalid = read_fp16(path)
|
| 522 |
+
invalid['tensors']['layer0.router_b'] = torch.tensor(float('nan'), dtype=torch.float16)
|
| 523 |
+
bad = Path(temporary)/'bad.pt'
|
| 524 |
+
torch.save(invalid, bad)
|
| 525 |
+
rejects(lambda: read_fp16(bad))
|
| 526 |
+
passed('real FP16 file roundtrip/native parity/no overwrite/nonfinite rejection/hook removal')
|
| 527 |
+
|
| 528 |
+
with ResurfaceNative(model, gate_mode='hard', expected_base_hashes=hashes, production=False) as hard:
|
| 529 |
+
hidden, gates = hard.forward_hidden(ids)
|
| 530 |
+
model.lm_head(hidden).float().square().mean().backward()
|
| 531 |
+
assert all(p.grad is not None and not torch.count_nonzero(p.grad) for p in hard.parameters())
|
| 532 |
+
zero_grads(hard)
|
| 533 |
+
_, gates = hard.forward_hidden(ids)
|
| 534 |
+
gates.opening_loss(mask).backward()
|
| 535 |
+
for name, p in hard.masters.items():
|
| 536 |
+
if '.router_' in name: assert p.grad is not None and torch.count_nonzero(p.grad)
|
| 537 |
+
with torch.no_grad():
|
| 538 |
+
for adapter in hard.adapters.values():
|
| 539 |
+
adapter.V_read.fill_(.25)
|
| 540 |
+
assert tensor_hash(model(ids)) == baseline
|
| 541 |
+
for adapter in hard.adapters.values(): adapter.router_b.fill_(1.)
|
| 542 |
+
assert tensor_hash(model(ids)) != baseline
|
| 543 |
+
hard.assert_base_frozen(check_values=True)
|
| 544 |
+
passed('hard closed-gate dead point, explicit opening gradients and threshold inference')
|
| 545 |
+
assert tensor_hash(model(ids)) == baseline and not _OWNERS
|
| 546 |
+
rejects(lambda: ResurfaceNative(model, gate_mode='task_detector', production=False))
|
| 547 |
+
passed('no task-specific gate mode; all base tensors/content unchanged')
|
| 548 |
+
return {'complete': True, 'tests': tests, 'passed': len(tests), 'cuda_initialized': torch.cuda.is_initialized(),
|
| 549 |
+
'production_trainables': 56*(128*128+128+4096+1), 'production_fp16_payload_bytes': 2308208,
|
| 550 |
+
'toy_export_bytes': receipt['bytes'], 'scope': 'CPU toy hooks only; native8B GPU parity/quality unmeasured'}
|
| 551 |
+
|
| 552 |
+
|
| 553 |
+
if __name__ == '__main__':
|
| 554 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 555 |
+
parser.add_argument('--self-test', action='store_true', required=True)
|
| 556 |
+
parser.parse_args()
|
| 557 |
+
print(json.dumps(self_test(), indent=2))
|
mamba2_recall/runtime.py
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pinned NVIDIA Mamba-2 8B source loader and exact tokenizer.
|
| 2 |
+
|
| 3 |
+
Execution uses state-spaces/mamba (Apache-2.0). The Megatron key mapping follows
|
| 4 |
+
NVIDIA's public checkpoint layout. Source BF16 weights are cast to FP16 for the
|
| 5 |
+
native quality reference; this is not native Megatron BF16 parity.
|
| 6 |
+
"""
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
import argparse
|
| 10 |
+
import enum
|
| 11 |
+
import gc
|
| 12 |
+
import hashlib
|
| 13 |
+
import importlib
|
| 14 |
+
import json
|
| 15 |
+
import platform
|
| 16 |
+
import re
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
|
| 19 |
+
import torch
|
| 20 |
+
from torch import nn
|
| 21 |
+
|
| 22 |
+
SOURCE_CHECKPOINT_SHA256 = "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb"
|
| 23 |
+
TOKENIZER_SHA256 = "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09"
|
| 24 |
+
TOKENIZER_FILENAME = "mt_nlg_plus_multilingual_ja_zh_the_stack_frac_015_256k.model"
|
| 25 |
+
MODEL_CONFIG = {
|
| 26 |
+
"d_model": 4096, "d_intermediate": 0, "n_layer": 56, "vocab_size": 256000,
|
| 27 |
+
"ssm_cfg": {"layer": "Mamba2", "d_state": 128, "d_conv": 4, "expand": 2,
|
| 28 |
+
"headdim": 64, "ngroups": 8, "chunk_size": 128,
|
| 29 |
+
"rmsnorm": True, "norm_before_gate": False,
|
| 30 |
+
"use_mem_eff_path": False},
|
| 31 |
+
"rms_norm": True, "residual_in_fp32": False, "fused_add_norm": False,
|
| 32 |
+
"pad_vocab_size_multiple": 128, "tie_embeddings": False,
|
| 33 |
+
}
|
| 34 |
+
_VERIFIED_FILES = {}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class _MegatronModelType(enum.Enum):
|
| 38 |
+
# Passive metadata enum from NVIDIA Megatron-LM core_r0.10.0/core/enums.py.
|
| 39 |
+
encoder_or_decoder = 1
|
| 40 |
+
encoder_and_decoder = 2
|
| 41 |
+
retro_encoder = 3
|
| 42 |
+
retro_decoder = 4
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def sha256_file(path):
|
| 46 |
+
digest = hashlib.sha256()
|
| 47 |
+
with Path(path).open("rb") as stream:
|
| 48 |
+
for chunk in iter(lambda: stream.read(8 * 1024 * 1024), b""):
|
| 49 |
+
digest.update(chunk)
|
| 50 |
+
return digest.hexdigest()
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def token_digest(ids):
|
| 54 |
+
import numpy as np
|
| 55 |
+
return hashlib.sha256(np.asarray(ids, dtype="<i8").tobytes()).hexdigest()
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def environment_receipt():
|
| 59 |
+
import importlib.metadata
|
| 60 |
+
packages = {}
|
| 61 |
+
for name in ("torch", "mamba-ssm", "numpy", "triton", "datasets", "sentencepiece"):
|
| 62 |
+
try:
|
| 63 |
+
packages[name] = importlib.metadata.version(name)
|
| 64 |
+
except importlib.metadata.PackageNotFoundError:
|
| 65 |
+
packages[name] = None
|
| 66 |
+
return {"python": platform.python_version(), "packages": packages,
|
| 67 |
+
"cuda_runtime": torch.version.cuda,
|
| 68 |
+
"gpu": torch.cuda.get_device_name() if torch.cuda.is_available() else None,
|
| 69 |
+
"tf32_matmul": torch.backends.cuda.matmul.allow_tf32}
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def gpu_memory_receipt():
|
| 73 |
+
if not torch.cuda.is_available():
|
| 74 |
+
return None
|
| 75 |
+
return {"peak_allocated_bytes": torch.cuda.max_memory_allocated(),
|
| 76 |
+
"peak_reserved_bytes": torch.cuda.max_memory_reserved(),
|
| 77 |
+
"current_allocated_bytes": torch.cuda.memory_allocated(),
|
| 78 |
+
"note": "Original BF16 source cast to native FP16 runtime"}
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def checkpoint_path(source_dir):
|
| 82 |
+
directory = Path(source_dir)
|
| 83 |
+
if directory.is_file():
|
| 84 |
+
return directory
|
| 85 |
+
for relative in ("model_optim_rng.pt", "release/mp_rank_00/model_optim_rng.pt"):
|
| 86 |
+
candidate = directory / relative
|
| 87 |
+
if candidate.is_file():
|
| 88 |
+
return candidate
|
| 89 |
+
raise FileNotFoundError(f"NVIDIA checkpoint missing under {directory}")
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def normalize_source_key(key):
|
| 93 |
+
"""Anchored mapping: decoder.layers.1 must never match layer 10 or 11."""
|
| 94 |
+
special = {"embedding.word_embeddings.weight": "backbone.embedding.weight",
|
| 95 |
+
"decoder.final_norm.weight": "backbone.norm_f.weight",
|
| 96 |
+
"output_layer.weight": "lm_head.weight"}
|
| 97 |
+
if key in special:
|
| 98 |
+
return special[key]
|
| 99 |
+
match = re.fullmatch(r"decoder\.layers\.(\d+)\.(.+)", key)
|
| 100 |
+
if match:
|
| 101 |
+
return f"backbone.layers.{int(match[1])}.{match[2]}"
|
| 102 |
+
# The loader can inspect an already mapped state without changing its keys.
|
| 103 |
+
if key.startswith("backbone.") or key == "lm_head.weight":
|
| 104 |
+
return key.replace("backbone.embeddings.", "backbone.embedding.", 1)
|
| 105 |
+
raise ValueError(f"Unrecognized model tensor key: {key}")
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def normalize_source_state(state):
|
| 109 |
+
result = {}
|
| 110 |
+
for name, value in state.items():
|
| 111 |
+
if not isinstance(value, torch.Tensor):
|
| 112 |
+
raise TypeError(f"Unexpected non-tensor model entry {name}: {type(value).__name__}")
|
| 113 |
+
target = normalize_source_key(name)
|
| 114 |
+
if target in result:
|
| 115 |
+
raise ValueError(f"Duplicate normalized tensor: {target}")
|
| 116 |
+
result[target] = value
|
| 117 |
+
return result
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def load_source_state(source_dir, expected_sha256=SOURCE_CHECKPOINT_SHA256):
|
| 121 |
+
"""Load a pinned official CPU checkpoint without an unrestricted unpickler.
|
| 122 |
+
|
| 123 |
+
Megatron stores an argparse namespace, a model-kind enum, and NumPy RNG state.
|
| 124 |
+
Only those inspected passive metadata types are additionally allowed.
|
| 125 |
+
Unexpected pickle globals fail closed. mmap avoids a second disk copy.
|
| 126 |
+
"""
|
| 127 |
+
path = checkpoint_path(source_dir)
|
| 128 |
+
stat = path.stat()
|
| 129 |
+
cache_key = (str(path.resolve()), stat.st_size, stat.st_mtime_ns)
|
| 130 |
+
digest = _VERIFIED_FILES.get(cache_key)
|
| 131 |
+
if digest is None:
|
| 132 |
+
digest = sha256_file(path)
|
| 133 |
+
_VERIFIED_FILES[cache_key] = digest
|
| 134 |
+
if digest != expected_sha256:
|
| 135 |
+
raise ValueError(f"Source checkpoint SHA-256 mismatch: {digest}")
|
| 136 |
+
import numpy as np
|
| 137 |
+
reconstruct = importlib.import_module("numpy.core.multiarray")._reconstruct
|
| 138 |
+
allowed = [argparse.Namespace, np.ndarray, np.dtype, type(np.dtype("uint32")),
|
| 139 |
+
(reconstruct, "numpy.core.multiarray._reconstruct"),
|
| 140 |
+
(_MegatronModelType, "megatron.core.enums.ModelType")]
|
| 141 |
+
try:
|
| 142 |
+
with torch.serialization.safe_globals(allowed):
|
| 143 |
+
checkpoint = torch.load(path, map_location="cpu", mmap=True, weights_only=True)
|
| 144 |
+
except Exception as error:
|
| 145 |
+
unsafe = torch.serialization.get_unsafe_globals_in_checkpoint(path)
|
| 146 |
+
raise RuntimeError(f"Safe checkpoint loading failed; inspect globals {unsafe}") from error
|
| 147 |
+
state = checkpoint["model"] if "model" in checkpoint else checkpoint
|
| 148 |
+
result = normalize_source_state(state)
|
| 149 |
+
del checkpoint
|
| 150 |
+
return result
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def make_model(config=None, device="meta", dtype=torch.float16):
|
| 154 |
+
from mamba_ssm.models.config_mamba import MambaConfig
|
| 155 |
+
from mamba_ssm.models.mixer_seq_simple import MambaLMHeadModel
|
| 156 |
+
config = json.loads(json.dumps(MODEL_CONFIG if config is None else config))
|
| 157 |
+
model = MambaLMHeadModel(MambaConfig(**config), device=device, dtype=dtype)
|
| 158 |
+
for block in model.backbone.layers:
|
| 159 |
+
block.mixer.use_mem_eff_path = False
|
| 160 |
+
expected_group_size = block.mixer.d_ssm // block.mixer.ngroups
|
| 161 |
+
if block.mixer.norm.group_size != expected_group_size:
|
| 162 |
+
raise RuntimeError("Runtime does not implement grouped gated RMSNorm")
|
| 163 |
+
return model.eval().requires_grad_(False)
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def load_source_model(source_dir, device="cuda", dtype=torch.float16,
|
| 167 |
+
expected_sha256=SOURCE_CHECKPOINT_SHA256):
|
| 168 |
+
model = make_model()
|
| 169 |
+
state = load_source_state(source_dir, expected_sha256=expected_sha256)
|
| 170 |
+
model.load_state_dict(state, strict=True, assign=True)
|
| 171 |
+
del state
|
| 172 |
+
model = model.to(device=device, dtype=dtype)
|
| 173 |
+
if model.backbone.embedding.weight.data_ptr() == model.lm_head.weight.data_ptr():
|
| 174 |
+
raise RuntimeError("8B source requires independent embedding and output head")
|
| 175 |
+
model._package_receipt = {"format": "original BF16 checkpoint cast to requested dtype",
|
| 176 |
+
"source_checkpoint_sha256": expected_sha256,
|
| 177 |
+
"parameter_count": sum(p.numel() for p in model.parameters())}
|
| 178 |
+
return model.eval().requires_grad_(False)
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
class SentencePieceTokenizer:
|
| 182 |
+
"""NVIDIA GPTSentencePiece token IDs without automatic BOS/EOS insertion."""
|
| 183 |
+
def __init__(self, path):
|
| 184 |
+
import sentencepiece as spm
|
| 185 |
+
path = Path(path)
|
| 186 |
+
if path.is_dir():
|
| 187 |
+
path = path / TOKENIZER_FILENAME
|
| 188 |
+
self.path = path
|
| 189 |
+
self.processor = spm.SentencePieceProcessor(model_file=str(path))
|
| 190 |
+
self.eos_token_id = self.processor.eos_id()
|
| 191 |
+
self.bos_token_id = self.processor.bos_id()
|
| 192 |
+
self.pad_token_id = self.processor.pad_id()
|
| 193 |
+
self.vocab_size = self.processor.vocab_size()
|
| 194 |
+
self.sha256 = sha256_file(path)
|
| 195 |
+
if self.sha256 != TOKENIZER_SHA256:
|
| 196 |
+
raise ValueError("Tokenizer does not match the pinned original NVIDIA SentencePiece model")
|
| 197 |
+
|
| 198 |
+
def encode(self, text, add_special_tokens=False):
|
| 199 |
+
if add_special_tokens:
|
| 200 |
+
raise ValueError("This protocol never inserts BOS/EOS automatically")
|
| 201 |
+
return self.processor.encode_as_ids(text)
|
| 202 |
+
|
| 203 |
+
def decode(self, ids, skip_special_tokens=False):
|
| 204 |
+
if isinstance(ids, torch.Tensor):
|
| 205 |
+
ids = ids.detach().cpu().tolist()
|
| 206 |
+
if skip_special_tokens:
|
| 207 |
+
ids = [i for i in ids if i not in (self.eos_token_id, self.bos_token_id, self.pad_token_id)]
|
| 208 |
+
return self.processor.decode_ids(ids)
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def make_cache(model, max_seqlen, batch_size=1, state_dtype=torch.float16):
|
| 212 |
+
"""Native one-token cache: state is rounded to the requested dtype each step."""
|
| 213 |
+
from mamba_ssm.utils.generation import InferenceParams
|
| 214 |
+
cache = InferenceParams(max_seqlen=max_seqlen, max_batch_size=batch_size)
|
| 215 |
+
cache.key_value_memory_dict = model.allocate_inference_cache(
|
| 216 |
+
batch_size, max_seqlen, dtype=state_dtype)
|
| 217 |
+
return cache
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def cache_bytes(cache):
|
| 221 |
+
return sum(tensor.numel() * tensor.element_size()
|
| 222 |
+
for pair in cache.key_value_memory_dict.values() for tensor in pair)
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
@torch.inference_mode()
|
| 226 |
+
def backbone_tokenwise(model, ids, state_dtype=torch.float16):
|
| 227 |
+
cache = make_cache(model, ids.shape[1], ids.shape[0], state_dtype)
|
| 228 |
+
result = []
|
| 229 |
+
for position in range(ids.shape[1]):
|
| 230 |
+
cache.seqlen_offset = position
|
| 231 |
+
result.append(model.backbone(ids[:, position:position+1], inference_params=cache))
|
| 232 |
+
return torch.cat(result, dim=1), cache
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
load_model = load_source_model
|
pyproject.toml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["setuptools>=68"]
|
| 3 |
+
build-backend = "setuptools.build_meta"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "mamb2-8b-recall"
|
| 7 |
+
version = "0.1.0"
|
| 8 |
+
description = "Full precision Mamba2-8B Resurface readout control"
|
| 9 |
+
requires-python = ">=3.10"
|
| 10 |
+
dependencies = ["numpy>=1.26", "torch>=2.6", "sentencepiece", "datasets", "huggingface-hub", "einops"]
|
| 11 |
+
|
| 12 |
+
[tool.setuptools.packages.find]
|
| 13 |
+
include = ["mamba2_recall*"]
|
reports/four_arm_comparison_v1.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "MAMBA2_SOURCE_COMPRESSED_FOUR_ARM_COMPARISON_V1",
|
| 3 |
+
"complete": true,
|
| 4 |
+
"source_report_sha256": "4c99694d66af1db71924bd9d3113f1ea2f0a9b93191ed229f3d26f2320c8c940",
|
| 5 |
+
"compressed_mk_report_sha256": "306ae9e8ed5e78756f7c8ea39c8db40dbebf3895ced3c5c279722be5100a344b",
|
| 6 |
+
"compressed_ppl_report_sha256": "06a71c11fc0a12a52add6e7bf5d28b8a8eb9f832b2ec1cb846d9acaf30afe961",
|
| 7 |
+
"exact_mk_prompt_identity": true,
|
| 8 |
+
"exact_ppl_window_identity": true,
|
| 9 |
+
"metrics": {
|
| 10 |
+
"source_fp16": {
|
| 11 |
+
"mk": {
|
| 12 |
+
"normal": {
|
| 13 |
+
"correct": 147,
|
| 14 |
+
"count": 384
|
| 15 |
+
},
|
| 16 |
+
"target_removed": {
|
| 17 |
+
"correct": 0,
|
| 18 |
+
"count": 384
|
| 19 |
+
}
|
| 20 |
+
},
|
| 21 |
+
"ppl": 7.334175947318572
|
| 22 |
+
},
|
| 23 |
+
"source_resurface": {
|
| 24 |
+
"mk": {
|
| 25 |
+
"normal": {
|
| 26 |
+
"correct": 365,
|
| 27 |
+
"count": 384
|
| 28 |
+
},
|
| 29 |
+
"target_removed": {
|
| 30 |
+
"correct": 0,
|
| 31 |
+
"count": 384
|
| 32 |
+
}
|
| 33 |
+
},
|
| 34 |
+
"ppl": 7.052063515606311
|
| 35 |
+
},
|
| 36 |
+
"compressed_base": {
|
| 37 |
+
"mk": {
|
| 38 |
+
"normal": {
|
| 39 |
+
"correct": 91,
|
| 40 |
+
"count": 384
|
| 41 |
+
},
|
| 42 |
+
"target_removed": {
|
| 43 |
+
"correct": 0,
|
| 44 |
+
"count": 384
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
"ppl": 7.622396587826496
|
| 48 |
+
},
|
| 49 |
+
"compressed_resurface": {
|
| 50 |
+
"mk": {
|
| 51 |
+
"normal": {
|
| 52 |
+
"correct": 340,
|
| 53 |
+
"count": 384
|
| 54 |
+
},
|
| 55 |
+
"target_removed": {
|
| 56 |
+
"correct": 0,
|
| 57 |
+
"count": 384
|
| 58 |
+
}
|
| 59 |
+
},
|
| 60 |
+
"ppl": 7.593163113563457
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"source_adapter_gain_pp": 56.77083333333333,
|
| 64 |
+
"compressed_adapter_gain_pp": 64.84375,
|
| 65 |
+
"difference_of_gains_pp": 8.072916666666671,
|
| 66 |
+
"interpretation": "Descriptive four-arm comparison on already observed numeric/template and validation data; the compressed base also received 448 small-tensor readaptation updates before adapter training, and each arm has its own unadapted-base KL teacher. Do not infer a causal quantization-only interaction or unseen-template generalization."
|
| 67 |
+
}
|
reports/source_resurface_v1_confirm_full.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
reports/source_resurface_v1_train.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
reports/verification_audit_v1.json
ADDED
|
@@ -0,0 +1,2175 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "MAMBA2_RESURFACE_REPLAY_AUDIT_V1",
|
| 3 |
+
"arithmetic_tolerance": {
|
| 4 |
+
"relative": 1e-12,
|
| 5 |
+
"absolute": 1e-09
|
| 6 |
+
},
|
| 7 |
+
"actual_adapter_sha256": "e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0",
|
| 8 |
+
"pins": {
|
| 9 |
+
"source_checkpoint_sha256": "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb",
|
| 10 |
+
"tokenizer_sha256": "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09",
|
| 11 |
+
"protocol_sha256": "dee9457bfaca067b63837dcd3bc94bf9ef9a3d805b1ab04227db05a4b92c54c2",
|
| 12 |
+
"adapter_sha256": "e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0"
|
| 13 |
+
},
|
| 14 |
+
"published_metadata_pins": {
|
| 15 |
+
"data_manifest_sha256": "227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c",
|
| 16 |
+
"dataset_fingerprint": "51d84d52d095f90d"
|
| 17 |
+
},
|
| 18 |
+
"scope": "Offline raw-report arithmetic, content identity, regex rescore, and fresh-report comparison. exact_replay covers scientific inputs and outputs; environment-dependent metadata equality is reported separately.",
|
| 19 |
+
"limitations": [
|
| 20 |
+
"The verifier does not run the model or independently recompute logits.",
|
| 21 |
+
"Token hashes are compared; raw prompt/PPL token bytes are not embedded in these reports.",
|
| 22 |
+
"SentencePiece decoding is not rerun. Equal generated IDs must have equal output text across reports.",
|
| 23 |
+
"Original frozen-base receipt checks identities, version counters, and gradients, not full tensor contents.",
|
| 24 |
+
"CONFIRM templates/instances and WikiText validation were previously observed."
|
| 25 |
+
],
|
| 26 |
+
"published": {
|
| 27 |
+
"baseline": {
|
| 28 |
+
"ppl": {
|
| 29 |
+
"windows": 130,
|
| 30 |
+
"target_tokens": 264764,
|
| 31 |
+
"nll_recomputed": 527554.2002649307,
|
| 32 |
+
"ppl_recomputed": 7.334175947318572,
|
| 33 |
+
"stored_nll_minus_recomputed": 0.0,
|
| 34 |
+
"stored_ppl_minus_recomputed": 0.0
|
| 35 |
+
},
|
| 36 |
+
"mk": {
|
| 37 |
+
"summary": {
|
| 38 |
+
"normal": {
|
| 39 |
+
"correct": 147,
|
| 40 |
+
"count": 384,
|
| 41 |
+
"accuracy": 0.3828125
|
| 42 |
+
},
|
| 43 |
+
"target_removed": {
|
| 44 |
+
"correct": 0,
|
| 45 |
+
"count": 384,
|
| 46 |
+
"accuracy": 0.0
|
| 47 |
+
}
|
| 48 |
+
},
|
| 49 |
+
"normal_by_N": {
|
| 50 |
+
"16": {
|
| 51 |
+
"correct": 113,
|
| 52 |
+
"count": 192,
|
| 53 |
+
"accuracy": 0.5885416666666666
|
| 54 |
+
},
|
| 55 |
+
"64": {
|
| 56 |
+
"correct": 34,
|
| 57 |
+
"count": 192,
|
| 58 |
+
"accuracy": 0.17708333333333334
|
| 59 |
+
}
|
| 60 |
+
},
|
| 61 |
+
"generated_length_histogram": {
|
| 62 |
+
"10": 3,
|
| 63 |
+
"12": 765
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
"adapter": {
|
| 68 |
+
"ppl": {
|
| 69 |
+
"windows": 130,
|
| 70 |
+
"target_tokens": 264764,
|
| 71 |
+
"nll_recomputed": 517168.8882961273,
|
| 72 |
+
"ppl_recomputed": 7.052063515606311,
|
| 73 |
+
"stored_nll_minus_recomputed": 0.0,
|
| 74 |
+
"stored_ppl_minus_recomputed": 0.0
|
| 75 |
+
},
|
| 76 |
+
"mk": {
|
| 77 |
+
"summary": {
|
| 78 |
+
"normal": {
|
| 79 |
+
"correct": 365,
|
| 80 |
+
"count": 384,
|
| 81 |
+
"accuracy": 0.9505208333333334
|
| 82 |
+
},
|
| 83 |
+
"target_removed": {
|
| 84 |
+
"correct": 0,
|
| 85 |
+
"count": 384,
|
| 86 |
+
"accuracy": 0.0
|
| 87 |
+
}
|
| 88 |
+
},
|
| 89 |
+
"normal_by_N": {
|
| 90 |
+
"16": {
|
| 91 |
+
"correct": 191,
|
| 92 |
+
"count": 192,
|
| 93 |
+
"accuracy": 0.9947916666666666
|
| 94 |
+
},
|
| 95 |
+
"64": {
|
| 96 |
+
"correct": 174,
|
| 97 |
+
"count": 192,
|
| 98 |
+
"accuracy": 0.90625
|
| 99 |
+
}
|
| 100 |
+
},
|
| 101 |
+
"generated_length_histogram": {
|
| 102 |
+
"12": 768
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
},
|
| 106 |
+
"mk_comparison": {
|
| 107 |
+
"normal": {
|
| 108 |
+
"both_correct": 143,
|
| 109 |
+
"both_wrong": 15,
|
| 110 |
+
"gained": 222,
|
| 111 |
+
"lost": 4,
|
| 112 |
+
"count": 384,
|
| 113 |
+
"baseline_correct": 147,
|
| 114 |
+
"adapter_correct": 365,
|
| 115 |
+
"delta_percentage_points": 56.770833333333336
|
| 116 |
+
},
|
| 117 |
+
"target_removed": {
|
| 118 |
+
"both_correct": 0,
|
| 119 |
+
"both_wrong": 384,
|
| 120 |
+
"gained": 0,
|
| 121 |
+
"lost": 0,
|
| 122 |
+
"count": 384,
|
| 123 |
+
"baseline_correct": 0,
|
| 124 |
+
"adapter_correct": 0,
|
| 125 |
+
"delta_percentage_points": 0.0
|
| 126 |
+
}
|
| 127 |
+
},
|
| 128 |
+
"ppl_delta_percent_recomputed": -3.846545729727191,
|
| 129 |
+
"restored_probe": {
|
| 130 |
+
"summary": {
|
| 131 |
+
"normal": {
|
| 132 |
+
"correct": 4,
|
| 133 |
+
"count": 4,
|
| 134 |
+
"accuracy": 1.0
|
| 135 |
+
},
|
| 136 |
+
"target_removed": {
|
| 137 |
+
"correct": 0,
|
| 138 |
+
"count": 4,
|
| 139 |
+
"accuracy": 0.0
|
| 140 |
+
}
|
| 141 |
+
},
|
| 142 |
+
"normal_by_N": {
|
| 143 |
+
"16": {
|
| 144 |
+
"correct": 4,
|
| 145 |
+
"count": 4,
|
| 146 |
+
"accuracy": 1.0
|
| 147 |
+
}
|
| 148 |
+
},
|
| 149 |
+
"generated_length_histogram": {
|
| 150 |
+
"12": 8
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
},
|
| 154 |
+
"replay": {
|
| 155 |
+
"baseline": {
|
| 156 |
+
"ppl": {
|
| 157 |
+
"windows": 130,
|
| 158 |
+
"target_tokens": 264764,
|
| 159 |
+
"nll_recomputed": 527554.2002649307,
|
| 160 |
+
"ppl_recomputed": 7.334175947318572,
|
| 161 |
+
"stored_nll_minus_recomputed": 0.0,
|
| 162 |
+
"stored_ppl_minus_recomputed": 0.0
|
| 163 |
+
},
|
| 164 |
+
"mk": {
|
| 165 |
+
"summary": {
|
| 166 |
+
"normal": {
|
| 167 |
+
"correct": 147,
|
| 168 |
+
"count": 384,
|
| 169 |
+
"accuracy": 0.3828125
|
| 170 |
+
},
|
| 171 |
+
"target_removed": {
|
| 172 |
+
"correct": 0,
|
| 173 |
+
"count": 384,
|
| 174 |
+
"accuracy": 0.0
|
| 175 |
+
}
|
| 176 |
+
},
|
| 177 |
+
"normal_by_N": {
|
| 178 |
+
"16": {
|
| 179 |
+
"correct": 113,
|
| 180 |
+
"count": 192,
|
| 181 |
+
"accuracy": 0.5885416666666666
|
| 182 |
+
},
|
| 183 |
+
"64": {
|
| 184 |
+
"correct": 34,
|
| 185 |
+
"count": 192,
|
| 186 |
+
"accuracy": 0.17708333333333334
|
| 187 |
+
}
|
| 188 |
+
},
|
| 189 |
+
"generated_length_histogram": {
|
| 190 |
+
"10": 3,
|
| 191 |
+
"12": 765
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
},
|
| 195 |
+
"adapter": {
|
| 196 |
+
"ppl": {
|
| 197 |
+
"windows": 130,
|
| 198 |
+
"target_tokens": 264764,
|
| 199 |
+
"nll_recomputed": 517168.8882961273,
|
| 200 |
+
"ppl_recomputed": 7.052063515606311,
|
| 201 |
+
"stored_nll_minus_recomputed": 0.0,
|
| 202 |
+
"stored_ppl_minus_recomputed": 0.0
|
| 203 |
+
},
|
| 204 |
+
"mk": {
|
| 205 |
+
"summary": {
|
| 206 |
+
"normal": {
|
| 207 |
+
"correct": 365,
|
| 208 |
+
"count": 384,
|
| 209 |
+
"accuracy": 0.9505208333333334
|
| 210 |
+
},
|
| 211 |
+
"target_removed": {
|
| 212 |
+
"correct": 0,
|
| 213 |
+
"count": 384,
|
| 214 |
+
"accuracy": 0.0
|
| 215 |
+
}
|
| 216 |
+
},
|
| 217 |
+
"normal_by_N": {
|
| 218 |
+
"16": {
|
| 219 |
+
"correct": 191,
|
| 220 |
+
"count": 192,
|
| 221 |
+
"accuracy": 0.9947916666666666
|
| 222 |
+
},
|
| 223 |
+
"64": {
|
| 224 |
+
"correct": 174,
|
| 225 |
+
"count": 192,
|
| 226 |
+
"accuracy": 0.90625
|
| 227 |
+
}
|
| 228 |
+
},
|
| 229 |
+
"generated_length_histogram": {
|
| 230 |
+
"12": 768
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
},
|
| 234 |
+
"mk_comparison": {
|
| 235 |
+
"normal": {
|
| 236 |
+
"both_correct": 143,
|
| 237 |
+
"both_wrong": 15,
|
| 238 |
+
"gained": 222,
|
| 239 |
+
"lost": 4,
|
| 240 |
+
"count": 384,
|
| 241 |
+
"baseline_correct": 147,
|
| 242 |
+
"adapter_correct": 365,
|
| 243 |
+
"delta_percentage_points": 56.770833333333336
|
| 244 |
+
},
|
| 245 |
+
"target_removed": {
|
| 246 |
+
"both_correct": 0,
|
| 247 |
+
"both_wrong": 384,
|
| 248 |
+
"gained": 0,
|
| 249 |
+
"lost": 0,
|
| 250 |
+
"count": 384,
|
| 251 |
+
"baseline_correct": 0,
|
| 252 |
+
"adapter_correct": 0,
|
| 253 |
+
"delta_percentage_points": 0.0
|
| 254 |
+
}
|
| 255 |
+
},
|
| 256 |
+
"ppl_delta_percent_recomputed": -3.846545729727191,
|
| 257 |
+
"restored_probe": {
|
| 258 |
+
"summary": {
|
| 259 |
+
"normal": {
|
| 260 |
+
"correct": 4,
|
| 261 |
+
"count": 4,
|
| 262 |
+
"accuracy": 1.0
|
| 263 |
+
},
|
| 264 |
+
"target_removed": {
|
| 265 |
+
"correct": 0,
|
| 266 |
+
"count": 4,
|
| 267 |
+
"accuracy": 0.0
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"normal_by_N": {
|
| 271 |
+
"16": {
|
| 272 |
+
"correct": 4,
|
| 273 |
+
"count": 4,
|
| 274 |
+
"accuracy": 1.0
|
| 275 |
+
}
|
| 276 |
+
},
|
| 277 |
+
"generated_length_histogram": {
|
| 278 |
+
"12": 8
|
| 279 |
+
}
|
| 280 |
+
}
|
| 281 |
+
},
|
| 282 |
+
"metadata_comparison": {
|
| 283 |
+
"manifests_equal": true,
|
| 284 |
+
"published_data_manifest_sha256": "227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c",
|
| 285 |
+
"replay_data_manifest_sha256": "227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c",
|
| 286 |
+
"dataset_fingerprints_equal": true,
|
| 287 |
+
"published_dataset_fingerprint": "51d84d52d095f90d",
|
| 288 |
+
"replay_dataset_fingerprint": "51d84d52d095f90d",
|
| 289 |
+
"interpretation": "The data manifest embeds Python version and dataset fingerprints depend on environment. These metadata may differ while all ordered prompt/token hashes, answers, dataset text/token digests, and revision remain identical."
|
| 290 |
+
},
|
| 291 |
+
"comparison": {
|
| 292 |
+
"baseline": {
|
| 293 |
+
"ppl": {
|
| 294 |
+
"aggregate_nll_exact": true,
|
| 295 |
+
"aggregate_ppl_exact": true,
|
| 296 |
+
"nll_delta": 0.0,
|
| 297 |
+
"ppl_delta": 0.0,
|
| 298 |
+
"max_abs_window_nll_error": 0.0,
|
| 299 |
+
"max_abs_window_ppl_error": 0.0,
|
| 300 |
+
"exact_nll_windows": 130,
|
| 301 |
+
"windows": [
|
| 302 |
+
{
|
| 303 |
+
"index": 0,
|
| 304 |
+
"start": 0,
|
| 305 |
+
"nll_delta": 0.0,
|
| 306 |
+
"ppl_delta": 0.0,
|
| 307 |
+
"nll_exact": true
|
| 308 |
+
},
|
| 309 |
+
{
|
| 310 |
+
"index": 1,
|
| 311 |
+
"start": 2048,
|
| 312 |
+
"nll_delta": 0.0,
|
| 313 |
+
"ppl_delta": 0.0,
|
| 314 |
+
"nll_exact": true
|
| 315 |
+
},
|
| 316 |
+
{
|
| 317 |
+
"index": 2,
|
| 318 |
+
"start": 4096,
|
| 319 |
+
"nll_delta": 0.0,
|
| 320 |
+
"ppl_delta": 0.0,
|
| 321 |
+
"nll_exact": true
|
| 322 |
+
},
|
| 323 |
+
{
|
| 324 |
+
"index": 3,
|
| 325 |
+
"start": 6144,
|
| 326 |
+
"nll_delta": 0.0,
|
| 327 |
+
"ppl_delta": 0.0,
|
| 328 |
+
"nll_exact": true
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"index": 4,
|
| 332 |
+
"start": 8192,
|
| 333 |
+
"nll_delta": 0.0,
|
| 334 |
+
"ppl_delta": 0.0,
|
| 335 |
+
"nll_exact": true
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"index": 5,
|
| 339 |
+
"start": 10240,
|
| 340 |
+
"nll_delta": 0.0,
|
| 341 |
+
"ppl_delta": 0.0,
|
| 342 |
+
"nll_exact": true
|
| 343 |
+
},
|
| 344 |
+
{
|
| 345 |
+
"index": 6,
|
| 346 |
+
"start": 12288,
|
| 347 |
+
"nll_delta": 0.0,
|
| 348 |
+
"ppl_delta": 0.0,
|
| 349 |
+
"nll_exact": true
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"index": 7,
|
| 353 |
+
"start": 14336,
|
| 354 |
+
"nll_delta": 0.0,
|
| 355 |
+
"ppl_delta": 0.0,
|
| 356 |
+
"nll_exact": true
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
"index": 8,
|
| 360 |
+
"start": 16384,
|
| 361 |
+
"nll_delta": 0.0,
|
| 362 |
+
"ppl_delta": 0.0,
|
| 363 |
+
"nll_exact": true
|
| 364 |
+
},
|
| 365 |
+
{
|
| 366 |
+
"index": 9,
|
| 367 |
+
"start": 18432,
|
| 368 |
+
"nll_delta": 0.0,
|
| 369 |
+
"ppl_delta": 0.0,
|
| 370 |
+
"nll_exact": true
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"index": 10,
|
| 374 |
+
"start": 20480,
|
| 375 |
+
"nll_delta": 0.0,
|
| 376 |
+
"ppl_delta": 0.0,
|
| 377 |
+
"nll_exact": true
|
| 378 |
+
},
|
| 379 |
+
{
|
| 380 |
+
"index": 11,
|
| 381 |
+
"start": 22528,
|
| 382 |
+
"nll_delta": 0.0,
|
| 383 |
+
"ppl_delta": 0.0,
|
| 384 |
+
"nll_exact": true
|
| 385 |
+
},
|
| 386 |
+
{
|
| 387 |
+
"index": 12,
|
| 388 |
+
"start": 24576,
|
| 389 |
+
"nll_delta": 0.0,
|
| 390 |
+
"ppl_delta": 0.0,
|
| 391 |
+
"nll_exact": true
|
| 392 |
+
},
|
| 393 |
+
{
|
| 394 |
+
"index": 13,
|
| 395 |
+
"start": 26624,
|
| 396 |
+
"nll_delta": 0.0,
|
| 397 |
+
"ppl_delta": 0.0,
|
| 398 |
+
"nll_exact": true
|
| 399 |
+
},
|
| 400 |
+
{
|
| 401 |
+
"index": 14,
|
| 402 |
+
"start": 28672,
|
| 403 |
+
"nll_delta": 0.0,
|
| 404 |
+
"ppl_delta": 0.0,
|
| 405 |
+
"nll_exact": true
|
| 406 |
+
},
|
| 407 |
+
{
|
| 408 |
+
"index": 15,
|
| 409 |
+
"start": 30720,
|
| 410 |
+
"nll_delta": 0.0,
|
| 411 |
+
"ppl_delta": 0.0,
|
| 412 |
+
"nll_exact": true
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"index": 16,
|
| 416 |
+
"start": 32768,
|
| 417 |
+
"nll_delta": 0.0,
|
| 418 |
+
"ppl_delta": 0.0,
|
| 419 |
+
"nll_exact": true
|
| 420 |
+
},
|
| 421 |
+
{
|
| 422 |
+
"index": 17,
|
| 423 |
+
"start": 34816,
|
| 424 |
+
"nll_delta": 0.0,
|
| 425 |
+
"ppl_delta": 0.0,
|
| 426 |
+
"nll_exact": true
|
| 427 |
+
},
|
| 428 |
+
{
|
| 429 |
+
"index": 18,
|
| 430 |
+
"start": 36864,
|
| 431 |
+
"nll_delta": 0.0,
|
| 432 |
+
"ppl_delta": 0.0,
|
| 433 |
+
"nll_exact": true
|
| 434 |
+
},
|
| 435 |
+
{
|
| 436 |
+
"index": 19,
|
| 437 |
+
"start": 38912,
|
| 438 |
+
"nll_delta": 0.0,
|
| 439 |
+
"ppl_delta": 0.0,
|
| 440 |
+
"nll_exact": true
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"index": 20,
|
| 444 |
+
"start": 40960,
|
| 445 |
+
"nll_delta": 0.0,
|
| 446 |
+
"ppl_delta": 0.0,
|
| 447 |
+
"nll_exact": true
|
| 448 |
+
},
|
| 449 |
+
{
|
| 450 |
+
"index": 21,
|
| 451 |
+
"start": 43008,
|
| 452 |
+
"nll_delta": 0.0,
|
| 453 |
+
"ppl_delta": 0.0,
|
| 454 |
+
"nll_exact": true
|
| 455 |
+
},
|
| 456 |
+
{
|
| 457 |
+
"index": 22,
|
| 458 |
+
"start": 45056,
|
| 459 |
+
"nll_delta": 0.0,
|
| 460 |
+
"ppl_delta": 0.0,
|
| 461 |
+
"nll_exact": true
|
| 462 |
+
},
|
| 463 |
+
{
|
| 464 |
+
"index": 23,
|
| 465 |
+
"start": 47104,
|
| 466 |
+
"nll_delta": 0.0,
|
| 467 |
+
"ppl_delta": 0.0,
|
| 468 |
+
"nll_exact": true
|
| 469 |
+
},
|
| 470 |
+
{
|
| 471 |
+
"index": 24,
|
| 472 |
+
"start": 49152,
|
| 473 |
+
"nll_delta": 0.0,
|
| 474 |
+
"ppl_delta": 0.0,
|
| 475 |
+
"nll_exact": true
|
| 476 |
+
},
|
| 477 |
+
{
|
| 478 |
+
"index": 25,
|
| 479 |
+
"start": 51200,
|
| 480 |
+
"nll_delta": 0.0,
|
| 481 |
+
"ppl_delta": 0.0,
|
| 482 |
+
"nll_exact": true
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"index": 26,
|
| 486 |
+
"start": 53248,
|
| 487 |
+
"nll_delta": 0.0,
|
| 488 |
+
"ppl_delta": 0.0,
|
| 489 |
+
"nll_exact": true
|
| 490 |
+
},
|
| 491 |
+
{
|
| 492 |
+
"index": 27,
|
| 493 |
+
"start": 55296,
|
| 494 |
+
"nll_delta": 0.0,
|
| 495 |
+
"ppl_delta": 0.0,
|
| 496 |
+
"nll_exact": true
|
| 497 |
+
},
|
| 498 |
+
{
|
| 499 |
+
"index": 28,
|
| 500 |
+
"start": 57344,
|
| 501 |
+
"nll_delta": 0.0,
|
| 502 |
+
"ppl_delta": 0.0,
|
| 503 |
+
"nll_exact": true
|
| 504 |
+
},
|
| 505 |
+
{
|
| 506 |
+
"index": 29,
|
| 507 |
+
"start": 59392,
|
| 508 |
+
"nll_delta": 0.0,
|
| 509 |
+
"ppl_delta": 0.0,
|
| 510 |
+
"nll_exact": true
|
| 511 |
+
},
|
| 512 |
+
{
|
| 513 |
+
"index": 30,
|
| 514 |
+
"start": 61440,
|
| 515 |
+
"nll_delta": 0.0,
|
| 516 |
+
"ppl_delta": 0.0,
|
| 517 |
+
"nll_exact": true
|
| 518 |
+
},
|
| 519 |
+
{
|
| 520 |
+
"index": 31,
|
| 521 |
+
"start": 63488,
|
| 522 |
+
"nll_delta": 0.0,
|
| 523 |
+
"ppl_delta": 0.0,
|
| 524 |
+
"nll_exact": true
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"index": 32,
|
| 528 |
+
"start": 65536,
|
| 529 |
+
"nll_delta": 0.0,
|
| 530 |
+
"ppl_delta": 0.0,
|
| 531 |
+
"nll_exact": true
|
| 532 |
+
},
|
| 533 |
+
{
|
| 534 |
+
"index": 33,
|
| 535 |
+
"start": 67584,
|
| 536 |
+
"nll_delta": 0.0,
|
| 537 |
+
"ppl_delta": 0.0,
|
| 538 |
+
"nll_exact": true
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"index": 34,
|
| 542 |
+
"start": 69632,
|
| 543 |
+
"nll_delta": 0.0,
|
| 544 |
+
"ppl_delta": 0.0,
|
| 545 |
+
"nll_exact": true
|
| 546 |
+
},
|
| 547 |
+
{
|
| 548 |
+
"index": 35,
|
| 549 |
+
"start": 71680,
|
| 550 |
+
"nll_delta": 0.0,
|
| 551 |
+
"ppl_delta": 0.0,
|
| 552 |
+
"nll_exact": true
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"index": 36,
|
| 556 |
+
"start": 73728,
|
| 557 |
+
"nll_delta": 0.0,
|
| 558 |
+
"ppl_delta": 0.0,
|
| 559 |
+
"nll_exact": true
|
| 560 |
+
},
|
| 561 |
+
{
|
| 562 |
+
"index": 37,
|
| 563 |
+
"start": 75776,
|
| 564 |
+
"nll_delta": 0.0,
|
| 565 |
+
"ppl_delta": 0.0,
|
| 566 |
+
"nll_exact": true
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"index": 38,
|
| 570 |
+
"start": 77824,
|
| 571 |
+
"nll_delta": 0.0,
|
| 572 |
+
"ppl_delta": 0.0,
|
| 573 |
+
"nll_exact": true
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"index": 39,
|
| 577 |
+
"start": 79872,
|
| 578 |
+
"nll_delta": 0.0,
|
| 579 |
+
"ppl_delta": 0.0,
|
| 580 |
+
"nll_exact": true
|
| 581 |
+
},
|
| 582 |
+
{
|
| 583 |
+
"index": 40,
|
| 584 |
+
"start": 81920,
|
| 585 |
+
"nll_delta": 0.0,
|
| 586 |
+
"ppl_delta": 0.0,
|
| 587 |
+
"nll_exact": true
|
| 588 |
+
},
|
| 589 |
+
{
|
| 590 |
+
"index": 41,
|
| 591 |
+
"start": 83968,
|
| 592 |
+
"nll_delta": 0.0,
|
| 593 |
+
"ppl_delta": 0.0,
|
| 594 |
+
"nll_exact": true
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"index": 42,
|
| 598 |
+
"start": 86016,
|
| 599 |
+
"nll_delta": 0.0,
|
| 600 |
+
"ppl_delta": 0.0,
|
| 601 |
+
"nll_exact": true
|
| 602 |
+
},
|
| 603 |
+
{
|
| 604 |
+
"index": 43,
|
| 605 |
+
"start": 88064,
|
| 606 |
+
"nll_delta": 0.0,
|
| 607 |
+
"ppl_delta": 0.0,
|
| 608 |
+
"nll_exact": true
|
| 609 |
+
},
|
| 610 |
+
{
|
| 611 |
+
"index": 44,
|
| 612 |
+
"start": 90112,
|
| 613 |
+
"nll_delta": 0.0,
|
| 614 |
+
"ppl_delta": 0.0,
|
| 615 |
+
"nll_exact": true
|
| 616 |
+
},
|
| 617 |
+
{
|
| 618 |
+
"index": 45,
|
| 619 |
+
"start": 92160,
|
| 620 |
+
"nll_delta": 0.0,
|
| 621 |
+
"ppl_delta": 0.0,
|
| 622 |
+
"nll_exact": true
|
| 623 |
+
},
|
| 624 |
+
{
|
| 625 |
+
"index": 46,
|
| 626 |
+
"start": 94208,
|
| 627 |
+
"nll_delta": 0.0,
|
| 628 |
+
"ppl_delta": 0.0,
|
| 629 |
+
"nll_exact": true
|
| 630 |
+
},
|
| 631 |
+
{
|
| 632 |
+
"index": 47,
|
| 633 |
+
"start": 96256,
|
| 634 |
+
"nll_delta": 0.0,
|
| 635 |
+
"ppl_delta": 0.0,
|
| 636 |
+
"nll_exact": true
|
| 637 |
+
},
|
| 638 |
+
{
|
| 639 |
+
"index": 48,
|
| 640 |
+
"start": 98304,
|
| 641 |
+
"nll_delta": 0.0,
|
| 642 |
+
"ppl_delta": 0.0,
|
| 643 |
+
"nll_exact": true
|
| 644 |
+
},
|
| 645 |
+
{
|
| 646 |
+
"index": 49,
|
| 647 |
+
"start": 100352,
|
| 648 |
+
"nll_delta": 0.0,
|
| 649 |
+
"ppl_delta": 0.0,
|
| 650 |
+
"nll_exact": true
|
| 651 |
+
},
|
| 652 |
+
{
|
| 653 |
+
"index": 50,
|
| 654 |
+
"start": 102400,
|
| 655 |
+
"nll_delta": 0.0,
|
| 656 |
+
"ppl_delta": 0.0,
|
| 657 |
+
"nll_exact": true
|
| 658 |
+
},
|
| 659 |
+
{
|
| 660 |
+
"index": 51,
|
| 661 |
+
"start": 104448,
|
| 662 |
+
"nll_delta": 0.0,
|
| 663 |
+
"ppl_delta": 0.0,
|
| 664 |
+
"nll_exact": true
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"index": 52,
|
| 668 |
+
"start": 106496,
|
| 669 |
+
"nll_delta": 0.0,
|
| 670 |
+
"ppl_delta": 0.0,
|
| 671 |
+
"nll_exact": true
|
| 672 |
+
},
|
| 673 |
+
{
|
| 674 |
+
"index": 53,
|
| 675 |
+
"start": 108544,
|
| 676 |
+
"nll_delta": 0.0,
|
| 677 |
+
"ppl_delta": 0.0,
|
| 678 |
+
"nll_exact": true
|
| 679 |
+
},
|
| 680 |
+
{
|
| 681 |
+
"index": 54,
|
| 682 |
+
"start": 110592,
|
| 683 |
+
"nll_delta": 0.0,
|
| 684 |
+
"ppl_delta": 0.0,
|
| 685 |
+
"nll_exact": true
|
| 686 |
+
},
|
| 687 |
+
{
|
| 688 |
+
"index": 55,
|
| 689 |
+
"start": 112640,
|
| 690 |
+
"nll_delta": 0.0,
|
| 691 |
+
"ppl_delta": 0.0,
|
| 692 |
+
"nll_exact": true
|
| 693 |
+
},
|
| 694 |
+
{
|
| 695 |
+
"index": 56,
|
| 696 |
+
"start": 114688,
|
| 697 |
+
"nll_delta": 0.0,
|
| 698 |
+
"ppl_delta": 0.0,
|
| 699 |
+
"nll_exact": true
|
| 700 |
+
},
|
| 701 |
+
{
|
| 702 |
+
"index": 57,
|
| 703 |
+
"start": 116736,
|
| 704 |
+
"nll_delta": 0.0,
|
| 705 |
+
"ppl_delta": 0.0,
|
| 706 |
+
"nll_exact": true
|
| 707 |
+
},
|
| 708 |
+
{
|
| 709 |
+
"index": 58,
|
| 710 |
+
"start": 118784,
|
| 711 |
+
"nll_delta": 0.0,
|
| 712 |
+
"ppl_delta": 0.0,
|
| 713 |
+
"nll_exact": true
|
| 714 |
+
},
|
| 715 |
+
{
|
| 716 |
+
"index": 59,
|
| 717 |
+
"start": 120832,
|
| 718 |
+
"nll_delta": 0.0,
|
| 719 |
+
"ppl_delta": 0.0,
|
| 720 |
+
"nll_exact": true
|
| 721 |
+
},
|
| 722 |
+
{
|
| 723 |
+
"index": 60,
|
| 724 |
+
"start": 122880,
|
| 725 |
+
"nll_delta": 0.0,
|
| 726 |
+
"ppl_delta": 0.0,
|
| 727 |
+
"nll_exact": true
|
| 728 |
+
},
|
| 729 |
+
{
|
| 730 |
+
"index": 61,
|
| 731 |
+
"start": 124928,
|
| 732 |
+
"nll_delta": 0.0,
|
| 733 |
+
"ppl_delta": 0.0,
|
| 734 |
+
"nll_exact": true
|
| 735 |
+
},
|
| 736 |
+
{
|
| 737 |
+
"index": 62,
|
| 738 |
+
"start": 126976,
|
| 739 |
+
"nll_delta": 0.0,
|
| 740 |
+
"ppl_delta": 0.0,
|
| 741 |
+
"nll_exact": true
|
| 742 |
+
},
|
| 743 |
+
{
|
| 744 |
+
"index": 63,
|
| 745 |
+
"start": 129024,
|
| 746 |
+
"nll_delta": 0.0,
|
| 747 |
+
"ppl_delta": 0.0,
|
| 748 |
+
"nll_exact": true
|
| 749 |
+
},
|
| 750 |
+
{
|
| 751 |
+
"index": 64,
|
| 752 |
+
"start": 131072,
|
| 753 |
+
"nll_delta": 0.0,
|
| 754 |
+
"ppl_delta": 0.0,
|
| 755 |
+
"nll_exact": true
|
| 756 |
+
},
|
| 757 |
+
{
|
| 758 |
+
"index": 65,
|
| 759 |
+
"start": 133120,
|
| 760 |
+
"nll_delta": 0.0,
|
| 761 |
+
"ppl_delta": 0.0,
|
| 762 |
+
"nll_exact": true
|
| 763 |
+
},
|
| 764 |
+
{
|
| 765 |
+
"index": 66,
|
| 766 |
+
"start": 135168,
|
| 767 |
+
"nll_delta": 0.0,
|
| 768 |
+
"ppl_delta": 0.0,
|
| 769 |
+
"nll_exact": true
|
| 770 |
+
},
|
| 771 |
+
{
|
| 772 |
+
"index": 67,
|
| 773 |
+
"start": 137216,
|
| 774 |
+
"nll_delta": 0.0,
|
| 775 |
+
"ppl_delta": 0.0,
|
| 776 |
+
"nll_exact": true
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"index": 68,
|
| 780 |
+
"start": 139264,
|
| 781 |
+
"nll_delta": 0.0,
|
| 782 |
+
"ppl_delta": 0.0,
|
| 783 |
+
"nll_exact": true
|
| 784 |
+
},
|
| 785 |
+
{
|
| 786 |
+
"index": 69,
|
| 787 |
+
"start": 141312,
|
| 788 |
+
"nll_delta": 0.0,
|
| 789 |
+
"ppl_delta": 0.0,
|
| 790 |
+
"nll_exact": true
|
| 791 |
+
},
|
| 792 |
+
{
|
| 793 |
+
"index": 70,
|
| 794 |
+
"start": 143360,
|
| 795 |
+
"nll_delta": 0.0,
|
| 796 |
+
"ppl_delta": 0.0,
|
| 797 |
+
"nll_exact": true
|
| 798 |
+
},
|
| 799 |
+
{
|
| 800 |
+
"index": 71,
|
| 801 |
+
"start": 145408,
|
| 802 |
+
"nll_delta": 0.0,
|
| 803 |
+
"ppl_delta": 0.0,
|
| 804 |
+
"nll_exact": true
|
| 805 |
+
},
|
| 806 |
+
{
|
| 807 |
+
"index": 72,
|
| 808 |
+
"start": 147456,
|
| 809 |
+
"nll_delta": 0.0,
|
| 810 |
+
"ppl_delta": 0.0,
|
| 811 |
+
"nll_exact": true
|
| 812 |
+
},
|
| 813 |
+
{
|
| 814 |
+
"index": 73,
|
| 815 |
+
"start": 149504,
|
| 816 |
+
"nll_delta": 0.0,
|
| 817 |
+
"ppl_delta": 0.0,
|
| 818 |
+
"nll_exact": true
|
| 819 |
+
},
|
| 820 |
+
{
|
| 821 |
+
"index": 74,
|
| 822 |
+
"start": 151552,
|
| 823 |
+
"nll_delta": 0.0,
|
| 824 |
+
"ppl_delta": 0.0,
|
| 825 |
+
"nll_exact": true
|
| 826 |
+
},
|
| 827 |
+
{
|
| 828 |
+
"index": 75,
|
| 829 |
+
"start": 153600,
|
| 830 |
+
"nll_delta": 0.0,
|
| 831 |
+
"ppl_delta": 0.0,
|
| 832 |
+
"nll_exact": true
|
| 833 |
+
},
|
| 834 |
+
{
|
| 835 |
+
"index": 76,
|
| 836 |
+
"start": 155648,
|
| 837 |
+
"nll_delta": 0.0,
|
| 838 |
+
"ppl_delta": 0.0,
|
| 839 |
+
"nll_exact": true
|
| 840 |
+
},
|
| 841 |
+
{
|
| 842 |
+
"index": 77,
|
| 843 |
+
"start": 157696,
|
| 844 |
+
"nll_delta": 0.0,
|
| 845 |
+
"ppl_delta": 0.0,
|
| 846 |
+
"nll_exact": true
|
| 847 |
+
},
|
| 848 |
+
{
|
| 849 |
+
"index": 78,
|
| 850 |
+
"start": 159744,
|
| 851 |
+
"nll_delta": 0.0,
|
| 852 |
+
"ppl_delta": 0.0,
|
| 853 |
+
"nll_exact": true
|
| 854 |
+
},
|
| 855 |
+
{
|
| 856 |
+
"index": 79,
|
| 857 |
+
"start": 161792,
|
| 858 |
+
"nll_delta": 0.0,
|
| 859 |
+
"ppl_delta": 0.0,
|
| 860 |
+
"nll_exact": true
|
| 861 |
+
},
|
| 862 |
+
{
|
| 863 |
+
"index": 80,
|
| 864 |
+
"start": 163840,
|
| 865 |
+
"nll_delta": 0.0,
|
| 866 |
+
"ppl_delta": 0.0,
|
| 867 |
+
"nll_exact": true
|
| 868 |
+
},
|
| 869 |
+
{
|
| 870 |
+
"index": 81,
|
| 871 |
+
"start": 165888,
|
| 872 |
+
"nll_delta": 0.0,
|
| 873 |
+
"ppl_delta": 0.0,
|
| 874 |
+
"nll_exact": true
|
| 875 |
+
},
|
| 876 |
+
{
|
| 877 |
+
"index": 82,
|
| 878 |
+
"start": 167936,
|
| 879 |
+
"nll_delta": 0.0,
|
| 880 |
+
"ppl_delta": 0.0,
|
| 881 |
+
"nll_exact": true
|
| 882 |
+
},
|
| 883 |
+
{
|
| 884 |
+
"index": 83,
|
| 885 |
+
"start": 169984,
|
| 886 |
+
"nll_delta": 0.0,
|
| 887 |
+
"ppl_delta": 0.0,
|
| 888 |
+
"nll_exact": true
|
| 889 |
+
},
|
| 890 |
+
{
|
| 891 |
+
"index": 84,
|
| 892 |
+
"start": 172032,
|
| 893 |
+
"nll_delta": 0.0,
|
| 894 |
+
"ppl_delta": 0.0,
|
| 895 |
+
"nll_exact": true
|
| 896 |
+
},
|
| 897 |
+
{
|
| 898 |
+
"index": 85,
|
| 899 |
+
"start": 174080,
|
| 900 |
+
"nll_delta": 0.0,
|
| 901 |
+
"ppl_delta": 0.0,
|
| 902 |
+
"nll_exact": true
|
| 903 |
+
},
|
| 904 |
+
{
|
| 905 |
+
"index": 86,
|
| 906 |
+
"start": 176128,
|
| 907 |
+
"nll_delta": 0.0,
|
| 908 |
+
"ppl_delta": 0.0,
|
| 909 |
+
"nll_exact": true
|
| 910 |
+
},
|
| 911 |
+
{
|
| 912 |
+
"index": 87,
|
| 913 |
+
"start": 178176,
|
| 914 |
+
"nll_delta": 0.0,
|
| 915 |
+
"ppl_delta": 0.0,
|
| 916 |
+
"nll_exact": true
|
| 917 |
+
},
|
| 918 |
+
{
|
| 919 |
+
"index": 88,
|
| 920 |
+
"start": 180224,
|
| 921 |
+
"nll_delta": 0.0,
|
| 922 |
+
"ppl_delta": 0.0,
|
| 923 |
+
"nll_exact": true
|
| 924 |
+
},
|
| 925 |
+
{
|
| 926 |
+
"index": 89,
|
| 927 |
+
"start": 182272,
|
| 928 |
+
"nll_delta": 0.0,
|
| 929 |
+
"ppl_delta": 0.0,
|
| 930 |
+
"nll_exact": true
|
| 931 |
+
},
|
| 932 |
+
{
|
| 933 |
+
"index": 90,
|
| 934 |
+
"start": 184320,
|
| 935 |
+
"nll_delta": 0.0,
|
| 936 |
+
"ppl_delta": 0.0,
|
| 937 |
+
"nll_exact": true
|
| 938 |
+
},
|
| 939 |
+
{
|
| 940 |
+
"index": 91,
|
| 941 |
+
"start": 186368,
|
| 942 |
+
"nll_delta": 0.0,
|
| 943 |
+
"ppl_delta": 0.0,
|
| 944 |
+
"nll_exact": true
|
| 945 |
+
},
|
| 946 |
+
{
|
| 947 |
+
"index": 92,
|
| 948 |
+
"start": 188416,
|
| 949 |
+
"nll_delta": 0.0,
|
| 950 |
+
"ppl_delta": 0.0,
|
| 951 |
+
"nll_exact": true
|
| 952 |
+
},
|
| 953 |
+
{
|
| 954 |
+
"index": 93,
|
| 955 |
+
"start": 190464,
|
| 956 |
+
"nll_delta": 0.0,
|
| 957 |
+
"ppl_delta": 0.0,
|
| 958 |
+
"nll_exact": true
|
| 959 |
+
},
|
| 960 |
+
{
|
| 961 |
+
"index": 94,
|
| 962 |
+
"start": 192512,
|
| 963 |
+
"nll_delta": 0.0,
|
| 964 |
+
"ppl_delta": 0.0,
|
| 965 |
+
"nll_exact": true
|
| 966 |
+
},
|
| 967 |
+
{
|
| 968 |
+
"index": 95,
|
| 969 |
+
"start": 194560,
|
| 970 |
+
"nll_delta": 0.0,
|
| 971 |
+
"ppl_delta": 0.0,
|
| 972 |
+
"nll_exact": true
|
| 973 |
+
},
|
| 974 |
+
{
|
| 975 |
+
"index": 96,
|
| 976 |
+
"start": 196608,
|
| 977 |
+
"nll_delta": 0.0,
|
| 978 |
+
"ppl_delta": 0.0,
|
| 979 |
+
"nll_exact": true
|
| 980 |
+
},
|
| 981 |
+
{
|
| 982 |
+
"index": 97,
|
| 983 |
+
"start": 198656,
|
| 984 |
+
"nll_delta": 0.0,
|
| 985 |
+
"ppl_delta": 0.0,
|
| 986 |
+
"nll_exact": true
|
| 987 |
+
},
|
| 988 |
+
{
|
| 989 |
+
"index": 98,
|
| 990 |
+
"start": 200704,
|
| 991 |
+
"nll_delta": 0.0,
|
| 992 |
+
"ppl_delta": 0.0,
|
| 993 |
+
"nll_exact": true
|
| 994 |
+
},
|
| 995 |
+
{
|
| 996 |
+
"index": 99,
|
| 997 |
+
"start": 202752,
|
| 998 |
+
"nll_delta": 0.0,
|
| 999 |
+
"ppl_delta": 0.0,
|
| 1000 |
+
"nll_exact": true
|
| 1001 |
+
},
|
| 1002 |
+
{
|
| 1003 |
+
"index": 100,
|
| 1004 |
+
"start": 204800,
|
| 1005 |
+
"nll_delta": 0.0,
|
| 1006 |
+
"ppl_delta": 0.0,
|
| 1007 |
+
"nll_exact": true
|
| 1008 |
+
},
|
| 1009 |
+
{
|
| 1010 |
+
"index": 101,
|
| 1011 |
+
"start": 206848,
|
| 1012 |
+
"nll_delta": 0.0,
|
| 1013 |
+
"ppl_delta": 0.0,
|
| 1014 |
+
"nll_exact": true
|
| 1015 |
+
},
|
| 1016 |
+
{
|
| 1017 |
+
"index": 102,
|
| 1018 |
+
"start": 208896,
|
| 1019 |
+
"nll_delta": 0.0,
|
| 1020 |
+
"ppl_delta": 0.0,
|
| 1021 |
+
"nll_exact": true
|
| 1022 |
+
},
|
| 1023 |
+
{
|
| 1024 |
+
"index": 103,
|
| 1025 |
+
"start": 210944,
|
| 1026 |
+
"nll_delta": 0.0,
|
| 1027 |
+
"ppl_delta": 0.0,
|
| 1028 |
+
"nll_exact": true
|
| 1029 |
+
},
|
| 1030 |
+
{
|
| 1031 |
+
"index": 104,
|
| 1032 |
+
"start": 212992,
|
| 1033 |
+
"nll_delta": 0.0,
|
| 1034 |
+
"ppl_delta": 0.0,
|
| 1035 |
+
"nll_exact": true
|
| 1036 |
+
},
|
| 1037 |
+
{
|
| 1038 |
+
"index": 105,
|
| 1039 |
+
"start": 215040,
|
| 1040 |
+
"nll_delta": 0.0,
|
| 1041 |
+
"ppl_delta": 0.0,
|
| 1042 |
+
"nll_exact": true
|
| 1043 |
+
},
|
| 1044 |
+
{
|
| 1045 |
+
"index": 106,
|
| 1046 |
+
"start": 217088,
|
| 1047 |
+
"nll_delta": 0.0,
|
| 1048 |
+
"ppl_delta": 0.0,
|
| 1049 |
+
"nll_exact": true
|
| 1050 |
+
},
|
| 1051 |
+
{
|
| 1052 |
+
"index": 107,
|
| 1053 |
+
"start": 219136,
|
| 1054 |
+
"nll_delta": 0.0,
|
| 1055 |
+
"ppl_delta": 0.0,
|
| 1056 |
+
"nll_exact": true
|
| 1057 |
+
},
|
| 1058 |
+
{
|
| 1059 |
+
"index": 108,
|
| 1060 |
+
"start": 221184,
|
| 1061 |
+
"nll_delta": 0.0,
|
| 1062 |
+
"ppl_delta": 0.0,
|
| 1063 |
+
"nll_exact": true
|
| 1064 |
+
},
|
| 1065 |
+
{
|
| 1066 |
+
"index": 109,
|
| 1067 |
+
"start": 223232,
|
| 1068 |
+
"nll_delta": 0.0,
|
| 1069 |
+
"ppl_delta": 0.0,
|
| 1070 |
+
"nll_exact": true
|
| 1071 |
+
},
|
| 1072 |
+
{
|
| 1073 |
+
"index": 110,
|
| 1074 |
+
"start": 225280,
|
| 1075 |
+
"nll_delta": 0.0,
|
| 1076 |
+
"ppl_delta": 0.0,
|
| 1077 |
+
"nll_exact": true
|
| 1078 |
+
},
|
| 1079 |
+
{
|
| 1080 |
+
"index": 111,
|
| 1081 |
+
"start": 227328,
|
| 1082 |
+
"nll_delta": 0.0,
|
| 1083 |
+
"ppl_delta": 0.0,
|
| 1084 |
+
"nll_exact": true
|
| 1085 |
+
},
|
| 1086 |
+
{
|
| 1087 |
+
"index": 112,
|
| 1088 |
+
"start": 229376,
|
| 1089 |
+
"nll_delta": 0.0,
|
| 1090 |
+
"ppl_delta": 0.0,
|
| 1091 |
+
"nll_exact": true
|
| 1092 |
+
},
|
| 1093 |
+
{
|
| 1094 |
+
"index": 113,
|
| 1095 |
+
"start": 231424,
|
| 1096 |
+
"nll_delta": 0.0,
|
| 1097 |
+
"ppl_delta": 0.0,
|
| 1098 |
+
"nll_exact": true
|
| 1099 |
+
},
|
| 1100 |
+
{
|
| 1101 |
+
"index": 114,
|
| 1102 |
+
"start": 233472,
|
| 1103 |
+
"nll_delta": 0.0,
|
| 1104 |
+
"ppl_delta": 0.0,
|
| 1105 |
+
"nll_exact": true
|
| 1106 |
+
},
|
| 1107 |
+
{
|
| 1108 |
+
"index": 115,
|
| 1109 |
+
"start": 235520,
|
| 1110 |
+
"nll_delta": 0.0,
|
| 1111 |
+
"ppl_delta": 0.0,
|
| 1112 |
+
"nll_exact": true
|
| 1113 |
+
},
|
| 1114 |
+
{
|
| 1115 |
+
"index": 116,
|
| 1116 |
+
"start": 237568,
|
| 1117 |
+
"nll_delta": 0.0,
|
| 1118 |
+
"ppl_delta": 0.0,
|
| 1119 |
+
"nll_exact": true
|
| 1120 |
+
},
|
| 1121 |
+
{
|
| 1122 |
+
"index": 117,
|
| 1123 |
+
"start": 239616,
|
| 1124 |
+
"nll_delta": 0.0,
|
| 1125 |
+
"ppl_delta": 0.0,
|
| 1126 |
+
"nll_exact": true
|
| 1127 |
+
},
|
| 1128 |
+
{
|
| 1129 |
+
"index": 118,
|
| 1130 |
+
"start": 241664,
|
| 1131 |
+
"nll_delta": 0.0,
|
| 1132 |
+
"ppl_delta": 0.0,
|
| 1133 |
+
"nll_exact": true
|
| 1134 |
+
},
|
| 1135 |
+
{
|
| 1136 |
+
"index": 119,
|
| 1137 |
+
"start": 243712,
|
| 1138 |
+
"nll_delta": 0.0,
|
| 1139 |
+
"ppl_delta": 0.0,
|
| 1140 |
+
"nll_exact": true
|
| 1141 |
+
},
|
| 1142 |
+
{
|
| 1143 |
+
"index": 120,
|
| 1144 |
+
"start": 245760,
|
| 1145 |
+
"nll_delta": 0.0,
|
| 1146 |
+
"ppl_delta": 0.0,
|
| 1147 |
+
"nll_exact": true
|
| 1148 |
+
},
|
| 1149 |
+
{
|
| 1150 |
+
"index": 121,
|
| 1151 |
+
"start": 247808,
|
| 1152 |
+
"nll_delta": 0.0,
|
| 1153 |
+
"ppl_delta": 0.0,
|
| 1154 |
+
"nll_exact": true
|
| 1155 |
+
},
|
| 1156 |
+
{
|
| 1157 |
+
"index": 122,
|
| 1158 |
+
"start": 249856,
|
| 1159 |
+
"nll_delta": 0.0,
|
| 1160 |
+
"ppl_delta": 0.0,
|
| 1161 |
+
"nll_exact": true
|
| 1162 |
+
},
|
| 1163 |
+
{
|
| 1164 |
+
"index": 123,
|
| 1165 |
+
"start": 251904,
|
| 1166 |
+
"nll_delta": 0.0,
|
| 1167 |
+
"ppl_delta": 0.0,
|
| 1168 |
+
"nll_exact": true
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"index": 124,
|
| 1172 |
+
"start": 253952,
|
| 1173 |
+
"nll_delta": 0.0,
|
| 1174 |
+
"ppl_delta": 0.0,
|
| 1175 |
+
"nll_exact": true
|
| 1176 |
+
},
|
| 1177 |
+
{
|
| 1178 |
+
"index": 125,
|
| 1179 |
+
"start": 256000,
|
| 1180 |
+
"nll_delta": 0.0,
|
| 1181 |
+
"ppl_delta": 0.0,
|
| 1182 |
+
"nll_exact": true
|
| 1183 |
+
},
|
| 1184 |
+
{
|
| 1185 |
+
"index": 126,
|
| 1186 |
+
"start": 258048,
|
| 1187 |
+
"nll_delta": 0.0,
|
| 1188 |
+
"ppl_delta": 0.0,
|
| 1189 |
+
"nll_exact": true
|
| 1190 |
+
},
|
| 1191 |
+
{
|
| 1192 |
+
"index": 127,
|
| 1193 |
+
"start": 260096,
|
| 1194 |
+
"nll_delta": 0.0,
|
| 1195 |
+
"ppl_delta": 0.0,
|
| 1196 |
+
"nll_exact": true
|
| 1197 |
+
},
|
| 1198 |
+
{
|
| 1199 |
+
"index": 128,
|
| 1200 |
+
"start": 262144,
|
| 1201 |
+
"nll_delta": 0.0,
|
| 1202 |
+
"ppl_delta": 0.0,
|
| 1203 |
+
"nll_exact": true
|
| 1204 |
+
},
|
| 1205 |
+
{
|
| 1206 |
+
"index": 129,
|
| 1207 |
+
"start": 264192,
|
| 1208 |
+
"nll_delta": 0.0,
|
| 1209 |
+
"ppl_delta": 0.0,
|
| 1210 |
+
"nll_exact": true
|
| 1211 |
+
}
|
| 1212 |
+
]
|
| 1213 |
+
},
|
| 1214 |
+
"mk": {
|
| 1215 |
+
"rows": 768,
|
| 1216 |
+
"all_generated_ids_exact": true,
|
| 1217 |
+
"all_output_text_exact": true,
|
| 1218 |
+
"all_predictions_exact": true,
|
| 1219 |
+
"all_correctness_exact": true,
|
| 1220 |
+
"changed_rows": 0,
|
| 1221 |
+
"differences": []
|
| 1222 |
+
}
|
| 1223 |
+
},
|
| 1224 |
+
"adapter": {
|
| 1225 |
+
"ppl": {
|
| 1226 |
+
"aggregate_nll_exact": true,
|
| 1227 |
+
"aggregate_ppl_exact": true,
|
| 1228 |
+
"nll_delta": 0.0,
|
| 1229 |
+
"ppl_delta": 0.0,
|
| 1230 |
+
"max_abs_window_nll_error": 0.0,
|
| 1231 |
+
"max_abs_window_ppl_error": 0.0,
|
| 1232 |
+
"exact_nll_windows": 130,
|
| 1233 |
+
"windows": [
|
| 1234 |
+
{
|
| 1235 |
+
"index": 0,
|
| 1236 |
+
"start": 0,
|
| 1237 |
+
"nll_delta": 0.0,
|
| 1238 |
+
"ppl_delta": 0.0,
|
| 1239 |
+
"nll_exact": true
|
| 1240 |
+
},
|
| 1241 |
+
{
|
| 1242 |
+
"index": 1,
|
| 1243 |
+
"start": 2048,
|
| 1244 |
+
"nll_delta": 0.0,
|
| 1245 |
+
"ppl_delta": 0.0,
|
| 1246 |
+
"nll_exact": true
|
| 1247 |
+
},
|
| 1248 |
+
{
|
| 1249 |
+
"index": 2,
|
| 1250 |
+
"start": 4096,
|
| 1251 |
+
"nll_delta": 0.0,
|
| 1252 |
+
"ppl_delta": 0.0,
|
| 1253 |
+
"nll_exact": true
|
| 1254 |
+
},
|
| 1255 |
+
{
|
| 1256 |
+
"index": 3,
|
| 1257 |
+
"start": 6144,
|
| 1258 |
+
"nll_delta": 0.0,
|
| 1259 |
+
"ppl_delta": 0.0,
|
| 1260 |
+
"nll_exact": true
|
| 1261 |
+
},
|
| 1262 |
+
{
|
| 1263 |
+
"index": 4,
|
| 1264 |
+
"start": 8192,
|
| 1265 |
+
"nll_delta": 0.0,
|
| 1266 |
+
"ppl_delta": 0.0,
|
| 1267 |
+
"nll_exact": true
|
| 1268 |
+
},
|
| 1269 |
+
{
|
| 1270 |
+
"index": 5,
|
| 1271 |
+
"start": 10240,
|
| 1272 |
+
"nll_delta": 0.0,
|
| 1273 |
+
"ppl_delta": 0.0,
|
| 1274 |
+
"nll_exact": true
|
| 1275 |
+
},
|
| 1276 |
+
{
|
| 1277 |
+
"index": 6,
|
| 1278 |
+
"start": 12288,
|
| 1279 |
+
"nll_delta": 0.0,
|
| 1280 |
+
"ppl_delta": 0.0,
|
| 1281 |
+
"nll_exact": true
|
| 1282 |
+
},
|
| 1283 |
+
{
|
| 1284 |
+
"index": 7,
|
| 1285 |
+
"start": 14336,
|
| 1286 |
+
"nll_delta": 0.0,
|
| 1287 |
+
"ppl_delta": 0.0,
|
| 1288 |
+
"nll_exact": true
|
| 1289 |
+
},
|
| 1290 |
+
{
|
| 1291 |
+
"index": 8,
|
| 1292 |
+
"start": 16384,
|
| 1293 |
+
"nll_delta": 0.0,
|
| 1294 |
+
"ppl_delta": 0.0,
|
| 1295 |
+
"nll_exact": true
|
| 1296 |
+
},
|
| 1297 |
+
{
|
| 1298 |
+
"index": 9,
|
| 1299 |
+
"start": 18432,
|
| 1300 |
+
"nll_delta": 0.0,
|
| 1301 |
+
"ppl_delta": 0.0,
|
| 1302 |
+
"nll_exact": true
|
| 1303 |
+
},
|
| 1304 |
+
{
|
| 1305 |
+
"index": 10,
|
| 1306 |
+
"start": 20480,
|
| 1307 |
+
"nll_delta": 0.0,
|
| 1308 |
+
"ppl_delta": 0.0,
|
| 1309 |
+
"nll_exact": true
|
| 1310 |
+
},
|
| 1311 |
+
{
|
| 1312 |
+
"index": 11,
|
| 1313 |
+
"start": 22528,
|
| 1314 |
+
"nll_delta": 0.0,
|
| 1315 |
+
"ppl_delta": 0.0,
|
| 1316 |
+
"nll_exact": true
|
| 1317 |
+
},
|
| 1318 |
+
{
|
| 1319 |
+
"index": 12,
|
| 1320 |
+
"start": 24576,
|
| 1321 |
+
"nll_delta": 0.0,
|
| 1322 |
+
"ppl_delta": 0.0,
|
| 1323 |
+
"nll_exact": true
|
| 1324 |
+
},
|
| 1325 |
+
{
|
| 1326 |
+
"index": 13,
|
| 1327 |
+
"start": 26624,
|
| 1328 |
+
"nll_delta": 0.0,
|
| 1329 |
+
"ppl_delta": 0.0,
|
| 1330 |
+
"nll_exact": true
|
| 1331 |
+
},
|
| 1332 |
+
{
|
| 1333 |
+
"index": 14,
|
| 1334 |
+
"start": 28672,
|
| 1335 |
+
"nll_delta": 0.0,
|
| 1336 |
+
"ppl_delta": 0.0,
|
| 1337 |
+
"nll_exact": true
|
| 1338 |
+
},
|
| 1339 |
+
{
|
| 1340 |
+
"index": 15,
|
| 1341 |
+
"start": 30720,
|
| 1342 |
+
"nll_delta": 0.0,
|
| 1343 |
+
"ppl_delta": 0.0,
|
| 1344 |
+
"nll_exact": true
|
| 1345 |
+
},
|
| 1346 |
+
{
|
| 1347 |
+
"index": 16,
|
| 1348 |
+
"start": 32768,
|
| 1349 |
+
"nll_delta": 0.0,
|
| 1350 |
+
"ppl_delta": 0.0,
|
| 1351 |
+
"nll_exact": true
|
| 1352 |
+
},
|
| 1353 |
+
{
|
| 1354 |
+
"index": 17,
|
| 1355 |
+
"start": 34816,
|
| 1356 |
+
"nll_delta": 0.0,
|
| 1357 |
+
"ppl_delta": 0.0,
|
| 1358 |
+
"nll_exact": true
|
| 1359 |
+
},
|
| 1360 |
+
{
|
| 1361 |
+
"index": 18,
|
| 1362 |
+
"start": 36864,
|
| 1363 |
+
"nll_delta": 0.0,
|
| 1364 |
+
"ppl_delta": 0.0,
|
| 1365 |
+
"nll_exact": true
|
| 1366 |
+
},
|
| 1367 |
+
{
|
| 1368 |
+
"index": 19,
|
| 1369 |
+
"start": 38912,
|
| 1370 |
+
"nll_delta": 0.0,
|
| 1371 |
+
"ppl_delta": 0.0,
|
| 1372 |
+
"nll_exact": true
|
| 1373 |
+
},
|
| 1374 |
+
{
|
| 1375 |
+
"index": 20,
|
| 1376 |
+
"start": 40960,
|
| 1377 |
+
"nll_delta": 0.0,
|
| 1378 |
+
"ppl_delta": 0.0,
|
| 1379 |
+
"nll_exact": true
|
| 1380 |
+
},
|
| 1381 |
+
{
|
| 1382 |
+
"index": 21,
|
| 1383 |
+
"start": 43008,
|
| 1384 |
+
"nll_delta": 0.0,
|
| 1385 |
+
"ppl_delta": 0.0,
|
| 1386 |
+
"nll_exact": true
|
| 1387 |
+
},
|
| 1388 |
+
{
|
| 1389 |
+
"index": 22,
|
| 1390 |
+
"start": 45056,
|
| 1391 |
+
"nll_delta": 0.0,
|
| 1392 |
+
"ppl_delta": 0.0,
|
| 1393 |
+
"nll_exact": true
|
| 1394 |
+
},
|
| 1395 |
+
{
|
| 1396 |
+
"index": 23,
|
| 1397 |
+
"start": 47104,
|
| 1398 |
+
"nll_delta": 0.0,
|
| 1399 |
+
"ppl_delta": 0.0,
|
| 1400 |
+
"nll_exact": true
|
| 1401 |
+
},
|
| 1402 |
+
{
|
| 1403 |
+
"index": 24,
|
| 1404 |
+
"start": 49152,
|
| 1405 |
+
"nll_delta": 0.0,
|
| 1406 |
+
"ppl_delta": 0.0,
|
| 1407 |
+
"nll_exact": true
|
| 1408 |
+
},
|
| 1409 |
+
{
|
| 1410 |
+
"index": 25,
|
| 1411 |
+
"start": 51200,
|
| 1412 |
+
"nll_delta": 0.0,
|
| 1413 |
+
"ppl_delta": 0.0,
|
| 1414 |
+
"nll_exact": true
|
| 1415 |
+
},
|
| 1416 |
+
{
|
| 1417 |
+
"index": 26,
|
| 1418 |
+
"start": 53248,
|
| 1419 |
+
"nll_delta": 0.0,
|
| 1420 |
+
"ppl_delta": 0.0,
|
| 1421 |
+
"nll_exact": true
|
| 1422 |
+
},
|
| 1423 |
+
{
|
| 1424 |
+
"index": 27,
|
| 1425 |
+
"start": 55296,
|
| 1426 |
+
"nll_delta": 0.0,
|
| 1427 |
+
"ppl_delta": 0.0,
|
| 1428 |
+
"nll_exact": true
|
| 1429 |
+
},
|
| 1430 |
+
{
|
| 1431 |
+
"index": 28,
|
| 1432 |
+
"start": 57344,
|
| 1433 |
+
"nll_delta": 0.0,
|
| 1434 |
+
"ppl_delta": 0.0,
|
| 1435 |
+
"nll_exact": true
|
| 1436 |
+
},
|
| 1437 |
+
{
|
| 1438 |
+
"index": 29,
|
| 1439 |
+
"start": 59392,
|
| 1440 |
+
"nll_delta": 0.0,
|
| 1441 |
+
"ppl_delta": 0.0,
|
| 1442 |
+
"nll_exact": true
|
| 1443 |
+
},
|
| 1444 |
+
{
|
| 1445 |
+
"index": 30,
|
| 1446 |
+
"start": 61440,
|
| 1447 |
+
"nll_delta": 0.0,
|
| 1448 |
+
"ppl_delta": 0.0,
|
| 1449 |
+
"nll_exact": true
|
| 1450 |
+
},
|
| 1451 |
+
{
|
| 1452 |
+
"index": 31,
|
| 1453 |
+
"start": 63488,
|
| 1454 |
+
"nll_delta": 0.0,
|
| 1455 |
+
"ppl_delta": 0.0,
|
| 1456 |
+
"nll_exact": true
|
| 1457 |
+
},
|
| 1458 |
+
{
|
| 1459 |
+
"index": 32,
|
| 1460 |
+
"start": 65536,
|
| 1461 |
+
"nll_delta": 0.0,
|
| 1462 |
+
"ppl_delta": 0.0,
|
| 1463 |
+
"nll_exact": true
|
| 1464 |
+
},
|
| 1465 |
+
{
|
| 1466 |
+
"index": 33,
|
| 1467 |
+
"start": 67584,
|
| 1468 |
+
"nll_delta": 0.0,
|
| 1469 |
+
"ppl_delta": 0.0,
|
| 1470 |
+
"nll_exact": true
|
| 1471 |
+
},
|
| 1472 |
+
{
|
| 1473 |
+
"index": 34,
|
| 1474 |
+
"start": 69632,
|
| 1475 |
+
"nll_delta": 0.0,
|
| 1476 |
+
"ppl_delta": 0.0,
|
| 1477 |
+
"nll_exact": true
|
| 1478 |
+
},
|
| 1479 |
+
{
|
| 1480 |
+
"index": 35,
|
| 1481 |
+
"start": 71680,
|
| 1482 |
+
"nll_delta": 0.0,
|
| 1483 |
+
"ppl_delta": 0.0,
|
| 1484 |
+
"nll_exact": true
|
| 1485 |
+
},
|
| 1486 |
+
{
|
| 1487 |
+
"index": 36,
|
| 1488 |
+
"start": 73728,
|
| 1489 |
+
"nll_delta": 0.0,
|
| 1490 |
+
"ppl_delta": 0.0,
|
| 1491 |
+
"nll_exact": true
|
| 1492 |
+
},
|
| 1493 |
+
{
|
| 1494 |
+
"index": 37,
|
| 1495 |
+
"start": 75776,
|
| 1496 |
+
"nll_delta": 0.0,
|
| 1497 |
+
"ppl_delta": 0.0,
|
| 1498 |
+
"nll_exact": true
|
| 1499 |
+
},
|
| 1500 |
+
{
|
| 1501 |
+
"index": 38,
|
| 1502 |
+
"start": 77824,
|
| 1503 |
+
"nll_delta": 0.0,
|
| 1504 |
+
"ppl_delta": 0.0,
|
| 1505 |
+
"nll_exact": true
|
| 1506 |
+
},
|
| 1507 |
+
{
|
| 1508 |
+
"index": 39,
|
| 1509 |
+
"start": 79872,
|
| 1510 |
+
"nll_delta": 0.0,
|
| 1511 |
+
"ppl_delta": 0.0,
|
| 1512 |
+
"nll_exact": true
|
| 1513 |
+
},
|
| 1514 |
+
{
|
| 1515 |
+
"index": 40,
|
| 1516 |
+
"start": 81920,
|
| 1517 |
+
"nll_delta": 0.0,
|
| 1518 |
+
"ppl_delta": 0.0,
|
| 1519 |
+
"nll_exact": true
|
| 1520 |
+
},
|
| 1521 |
+
{
|
| 1522 |
+
"index": 41,
|
| 1523 |
+
"start": 83968,
|
| 1524 |
+
"nll_delta": 0.0,
|
| 1525 |
+
"ppl_delta": 0.0,
|
| 1526 |
+
"nll_exact": true
|
| 1527 |
+
},
|
| 1528 |
+
{
|
| 1529 |
+
"index": 42,
|
| 1530 |
+
"start": 86016,
|
| 1531 |
+
"nll_delta": 0.0,
|
| 1532 |
+
"ppl_delta": 0.0,
|
| 1533 |
+
"nll_exact": true
|
| 1534 |
+
},
|
| 1535 |
+
{
|
| 1536 |
+
"index": 43,
|
| 1537 |
+
"start": 88064,
|
| 1538 |
+
"nll_delta": 0.0,
|
| 1539 |
+
"ppl_delta": 0.0,
|
| 1540 |
+
"nll_exact": true
|
| 1541 |
+
},
|
| 1542 |
+
{
|
| 1543 |
+
"index": 44,
|
| 1544 |
+
"start": 90112,
|
| 1545 |
+
"nll_delta": 0.0,
|
| 1546 |
+
"ppl_delta": 0.0,
|
| 1547 |
+
"nll_exact": true
|
| 1548 |
+
},
|
| 1549 |
+
{
|
| 1550 |
+
"index": 45,
|
| 1551 |
+
"start": 92160,
|
| 1552 |
+
"nll_delta": 0.0,
|
| 1553 |
+
"ppl_delta": 0.0,
|
| 1554 |
+
"nll_exact": true
|
| 1555 |
+
},
|
| 1556 |
+
{
|
| 1557 |
+
"index": 46,
|
| 1558 |
+
"start": 94208,
|
| 1559 |
+
"nll_delta": 0.0,
|
| 1560 |
+
"ppl_delta": 0.0,
|
| 1561 |
+
"nll_exact": true
|
| 1562 |
+
},
|
| 1563 |
+
{
|
| 1564 |
+
"index": 47,
|
| 1565 |
+
"start": 96256,
|
| 1566 |
+
"nll_delta": 0.0,
|
| 1567 |
+
"ppl_delta": 0.0,
|
| 1568 |
+
"nll_exact": true
|
| 1569 |
+
},
|
| 1570 |
+
{
|
| 1571 |
+
"index": 48,
|
| 1572 |
+
"start": 98304,
|
| 1573 |
+
"nll_delta": 0.0,
|
| 1574 |
+
"ppl_delta": 0.0,
|
| 1575 |
+
"nll_exact": true
|
| 1576 |
+
},
|
| 1577 |
+
{
|
| 1578 |
+
"index": 49,
|
| 1579 |
+
"start": 100352,
|
| 1580 |
+
"nll_delta": 0.0,
|
| 1581 |
+
"ppl_delta": 0.0,
|
| 1582 |
+
"nll_exact": true
|
| 1583 |
+
},
|
| 1584 |
+
{
|
| 1585 |
+
"index": 50,
|
| 1586 |
+
"start": 102400,
|
| 1587 |
+
"nll_delta": 0.0,
|
| 1588 |
+
"ppl_delta": 0.0,
|
| 1589 |
+
"nll_exact": true
|
| 1590 |
+
},
|
| 1591 |
+
{
|
| 1592 |
+
"index": 51,
|
| 1593 |
+
"start": 104448,
|
| 1594 |
+
"nll_delta": 0.0,
|
| 1595 |
+
"ppl_delta": 0.0,
|
| 1596 |
+
"nll_exact": true
|
| 1597 |
+
},
|
| 1598 |
+
{
|
| 1599 |
+
"index": 52,
|
| 1600 |
+
"start": 106496,
|
| 1601 |
+
"nll_delta": 0.0,
|
| 1602 |
+
"ppl_delta": 0.0,
|
| 1603 |
+
"nll_exact": true
|
| 1604 |
+
},
|
| 1605 |
+
{
|
| 1606 |
+
"index": 53,
|
| 1607 |
+
"start": 108544,
|
| 1608 |
+
"nll_delta": 0.0,
|
| 1609 |
+
"ppl_delta": 0.0,
|
| 1610 |
+
"nll_exact": true
|
| 1611 |
+
},
|
| 1612 |
+
{
|
| 1613 |
+
"index": 54,
|
| 1614 |
+
"start": 110592,
|
| 1615 |
+
"nll_delta": 0.0,
|
| 1616 |
+
"ppl_delta": 0.0,
|
| 1617 |
+
"nll_exact": true
|
| 1618 |
+
},
|
| 1619 |
+
{
|
| 1620 |
+
"index": 55,
|
| 1621 |
+
"start": 112640,
|
| 1622 |
+
"nll_delta": 0.0,
|
| 1623 |
+
"ppl_delta": 0.0,
|
| 1624 |
+
"nll_exact": true
|
| 1625 |
+
},
|
| 1626 |
+
{
|
| 1627 |
+
"index": 56,
|
| 1628 |
+
"start": 114688,
|
| 1629 |
+
"nll_delta": 0.0,
|
| 1630 |
+
"ppl_delta": 0.0,
|
| 1631 |
+
"nll_exact": true
|
| 1632 |
+
},
|
| 1633 |
+
{
|
| 1634 |
+
"index": 57,
|
| 1635 |
+
"start": 116736,
|
| 1636 |
+
"nll_delta": 0.0,
|
| 1637 |
+
"ppl_delta": 0.0,
|
| 1638 |
+
"nll_exact": true
|
| 1639 |
+
},
|
| 1640 |
+
{
|
| 1641 |
+
"index": 58,
|
| 1642 |
+
"start": 118784,
|
| 1643 |
+
"nll_delta": 0.0,
|
| 1644 |
+
"ppl_delta": 0.0,
|
| 1645 |
+
"nll_exact": true
|
| 1646 |
+
},
|
| 1647 |
+
{
|
| 1648 |
+
"index": 59,
|
| 1649 |
+
"start": 120832,
|
| 1650 |
+
"nll_delta": 0.0,
|
| 1651 |
+
"ppl_delta": 0.0,
|
| 1652 |
+
"nll_exact": true
|
| 1653 |
+
},
|
| 1654 |
+
{
|
| 1655 |
+
"index": 60,
|
| 1656 |
+
"start": 122880,
|
| 1657 |
+
"nll_delta": 0.0,
|
| 1658 |
+
"ppl_delta": 0.0,
|
| 1659 |
+
"nll_exact": true
|
| 1660 |
+
},
|
| 1661 |
+
{
|
| 1662 |
+
"index": 61,
|
| 1663 |
+
"start": 124928,
|
| 1664 |
+
"nll_delta": 0.0,
|
| 1665 |
+
"ppl_delta": 0.0,
|
| 1666 |
+
"nll_exact": true
|
| 1667 |
+
},
|
| 1668 |
+
{
|
| 1669 |
+
"index": 62,
|
| 1670 |
+
"start": 126976,
|
| 1671 |
+
"nll_delta": 0.0,
|
| 1672 |
+
"ppl_delta": 0.0,
|
| 1673 |
+
"nll_exact": true
|
| 1674 |
+
},
|
| 1675 |
+
{
|
| 1676 |
+
"index": 63,
|
| 1677 |
+
"start": 129024,
|
| 1678 |
+
"nll_delta": 0.0,
|
| 1679 |
+
"ppl_delta": 0.0,
|
| 1680 |
+
"nll_exact": true
|
| 1681 |
+
},
|
| 1682 |
+
{
|
| 1683 |
+
"index": 64,
|
| 1684 |
+
"start": 131072,
|
| 1685 |
+
"nll_delta": 0.0,
|
| 1686 |
+
"ppl_delta": 0.0,
|
| 1687 |
+
"nll_exact": true
|
| 1688 |
+
},
|
| 1689 |
+
{
|
| 1690 |
+
"index": 65,
|
| 1691 |
+
"start": 133120,
|
| 1692 |
+
"nll_delta": 0.0,
|
| 1693 |
+
"ppl_delta": 0.0,
|
| 1694 |
+
"nll_exact": true
|
| 1695 |
+
},
|
| 1696 |
+
{
|
| 1697 |
+
"index": 66,
|
| 1698 |
+
"start": 135168,
|
| 1699 |
+
"nll_delta": 0.0,
|
| 1700 |
+
"ppl_delta": 0.0,
|
| 1701 |
+
"nll_exact": true
|
| 1702 |
+
},
|
| 1703 |
+
{
|
| 1704 |
+
"index": 67,
|
| 1705 |
+
"start": 137216,
|
| 1706 |
+
"nll_delta": 0.0,
|
| 1707 |
+
"ppl_delta": 0.0,
|
| 1708 |
+
"nll_exact": true
|
| 1709 |
+
},
|
| 1710 |
+
{
|
| 1711 |
+
"index": 68,
|
| 1712 |
+
"start": 139264,
|
| 1713 |
+
"nll_delta": 0.0,
|
| 1714 |
+
"ppl_delta": 0.0,
|
| 1715 |
+
"nll_exact": true
|
| 1716 |
+
},
|
| 1717 |
+
{
|
| 1718 |
+
"index": 69,
|
| 1719 |
+
"start": 141312,
|
| 1720 |
+
"nll_delta": 0.0,
|
| 1721 |
+
"ppl_delta": 0.0,
|
| 1722 |
+
"nll_exact": true
|
| 1723 |
+
},
|
| 1724 |
+
{
|
| 1725 |
+
"index": 70,
|
| 1726 |
+
"start": 143360,
|
| 1727 |
+
"nll_delta": 0.0,
|
| 1728 |
+
"ppl_delta": 0.0,
|
| 1729 |
+
"nll_exact": true
|
| 1730 |
+
},
|
| 1731 |
+
{
|
| 1732 |
+
"index": 71,
|
| 1733 |
+
"start": 145408,
|
| 1734 |
+
"nll_delta": 0.0,
|
| 1735 |
+
"ppl_delta": 0.0,
|
| 1736 |
+
"nll_exact": true
|
| 1737 |
+
},
|
| 1738 |
+
{
|
| 1739 |
+
"index": 72,
|
| 1740 |
+
"start": 147456,
|
| 1741 |
+
"nll_delta": 0.0,
|
| 1742 |
+
"ppl_delta": 0.0,
|
| 1743 |
+
"nll_exact": true
|
| 1744 |
+
},
|
| 1745 |
+
{
|
| 1746 |
+
"index": 73,
|
| 1747 |
+
"start": 149504,
|
| 1748 |
+
"nll_delta": 0.0,
|
| 1749 |
+
"ppl_delta": 0.0,
|
| 1750 |
+
"nll_exact": true
|
| 1751 |
+
},
|
| 1752 |
+
{
|
| 1753 |
+
"index": 74,
|
| 1754 |
+
"start": 151552,
|
| 1755 |
+
"nll_delta": 0.0,
|
| 1756 |
+
"ppl_delta": 0.0,
|
| 1757 |
+
"nll_exact": true
|
| 1758 |
+
},
|
| 1759 |
+
{
|
| 1760 |
+
"index": 75,
|
| 1761 |
+
"start": 153600,
|
| 1762 |
+
"nll_delta": 0.0,
|
| 1763 |
+
"ppl_delta": 0.0,
|
| 1764 |
+
"nll_exact": true
|
| 1765 |
+
},
|
| 1766 |
+
{
|
| 1767 |
+
"index": 76,
|
| 1768 |
+
"start": 155648,
|
| 1769 |
+
"nll_delta": 0.0,
|
| 1770 |
+
"ppl_delta": 0.0,
|
| 1771 |
+
"nll_exact": true
|
| 1772 |
+
},
|
| 1773 |
+
{
|
| 1774 |
+
"index": 77,
|
| 1775 |
+
"start": 157696,
|
| 1776 |
+
"nll_delta": 0.0,
|
| 1777 |
+
"ppl_delta": 0.0,
|
| 1778 |
+
"nll_exact": true
|
| 1779 |
+
},
|
| 1780 |
+
{
|
| 1781 |
+
"index": 78,
|
| 1782 |
+
"start": 159744,
|
| 1783 |
+
"nll_delta": 0.0,
|
| 1784 |
+
"ppl_delta": 0.0,
|
| 1785 |
+
"nll_exact": true
|
| 1786 |
+
},
|
| 1787 |
+
{
|
| 1788 |
+
"index": 79,
|
| 1789 |
+
"start": 161792,
|
| 1790 |
+
"nll_delta": 0.0,
|
| 1791 |
+
"ppl_delta": 0.0,
|
| 1792 |
+
"nll_exact": true
|
| 1793 |
+
},
|
| 1794 |
+
{
|
| 1795 |
+
"index": 80,
|
| 1796 |
+
"start": 163840,
|
| 1797 |
+
"nll_delta": 0.0,
|
| 1798 |
+
"ppl_delta": 0.0,
|
| 1799 |
+
"nll_exact": true
|
| 1800 |
+
},
|
| 1801 |
+
{
|
| 1802 |
+
"index": 81,
|
| 1803 |
+
"start": 165888,
|
| 1804 |
+
"nll_delta": 0.0,
|
| 1805 |
+
"ppl_delta": 0.0,
|
| 1806 |
+
"nll_exact": true
|
| 1807 |
+
},
|
| 1808 |
+
{
|
| 1809 |
+
"index": 82,
|
| 1810 |
+
"start": 167936,
|
| 1811 |
+
"nll_delta": 0.0,
|
| 1812 |
+
"ppl_delta": 0.0,
|
| 1813 |
+
"nll_exact": true
|
| 1814 |
+
},
|
| 1815 |
+
{
|
| 1816 |
+
"index": 83,
|
| 1817 |
+
"start": 169984,
|
| 1818 |
+
"nll_delta": 0.0,
|
| 1819 |
+
"ppl_delta": 0.0,
|
| 1820 |
+
"nll_exact": true
|
| 1821 |
+
},
|
| 1822 |
+
{
|
| 1823 |
+
"index": 84,
|
| 1824 |
+
"start": 172032,
|
| 1825 |
+
"nll_delta": 0.0,
|
| 1826 |
+
"ppl_delta": 0.0,
|
| 1827 |
+
"nll_exact": true
|
| 1828 |
+
},
|
| 1829 |
+
{
|
| 1830 |
+
"index": 85,
|
| 1831 |
+
"start": 174080,
|
| 1832 |
+
"nll_delta": 0.0,
|
| 1833 |
+
"ppl_delta": 0.0,
|
| 1834 |
+
"nll_exact": true
|
| 1835 |
+
},
|
| 1836 |
+
{
|
| 1837 |
+
"index": 86,
|
| 1838 |
+
"start": 176128,
|
| 1839 |
+
"nll_delta": 0.0,
|
| 1840 |
+
"ppl_delta": 0.0,
|
| 1841 |
+
"nll_exact": true
|
| 1842 |
+
},
|
| 1843 |
+
{
|
| 1844 |
+
"index": 87,
|
| 1845 |
+
"start": 178176,
|
| 1846 |
+
"nll_delta": 0.0,
|
| 1847 |
+
"ppl_delta": 0.0,
|
| 1848 |
+
"nll_exact": true
|
| 1849 |
+
},
|
| 1850 |
+
{
|
| 1851 |
+
"index": 88,
|
| 1852 |
+
"start": 180224,
|
| 1853 |
+
"nll_delta": 0.0,
|
| 1854 |
+
"ppl_delta": 0.0,
|
| 1855 |
+
"nll_exact": true
|
| 1856 |
+
},
|
| 1857 |
+
{
|
| 1858 |
+
"index": 89,
|
| 1859 |
+
"start": 182272,
|
| 1860 |
+
"nll_delta": 0.0,
|
| 1861 |
+
"ppl_delta": 0.0,
|
| 1862 |
+
"nll_exact": true
|
| 1863 |
+
},
|
| 1864 |
+
{
|
| 1865 |
+
"index": 90,
|
| 1866 |
+
"start": 184320,
|
| 1867 |
+
"nll_delta": 0.0,
|
| 1868 |
+
"ppl_delta": 0.0,
|
| 1869 |
+
"nll_exact": true
|
| 1870 |
+
},
|
| 1871 |
+
{
|
| 1872 |
+
"index": 91,
|
| 1873 |
+
"start": 186368,
|
| 1874 |
+
"nll_delta": 0.0,
|
| 1875 |
+
"ppl_delta": 0.0,
|
| 1876 |
+
"nll_exact": true
|
| 1877 |
+
},
|
| 1878 |
+
{
|
| 1879 |
+
"index": 92,
|
| 1880 |
+
"start": 188416,
|
| 1881 |
+
"nll_delta": 0.0,
|
| 1882 |
+
"ppl_delta": 0.0,
|
| 1883 |
+
"nll_exact": true
|
| 1884 |
+
},
|
| 1885 |
+
{
|
| 1886 |
+
"index": 93,
|
| 1887 |
+
"start": 190464,
|
| 1888 |
+
"nll_delta": 0.0,
|
| 1889 |
+
"ppl_delta": 0.0,
|
| 1890 |
+
"nll_exact": true
|
| 1891 |
+
},
|
| 1892 |
+
{
|
| 1893 |
+
"index": 94,
|
| 1894 |
+
"start": 192512,
|
| 1895 |
+
"nll_delta": 0.0,
|
| 1896 |
+
"ppl_delta": 0.0,
|
| 1897 |
+
"nll_exact": true
|
| 1898 |
+
},
|
| 1899 |
+
{
|
| 1900 |
+
"index": 95,
|
| 1901 |
+
"start": 194560,
|
| 1902 |
+
"nll_delta": 0.0,
|
| 1903 |
+
"ppl_delta": 0.0,
|
| 1904 |
+
"nll_exact": true
|
| 1905 |
+
},
|
| 1906 |
+
{
|
| 1907 |
+
"index": 96,
|
| 1908 |
+
"start": 196608,
|
| 1909 |
+
"nll_delta": 0.0,
|
| 1910 |
+
"ppl_delta": 0.0,
|
| 1911 |
+
"nll_exact": true
|
| 1912 |
+
},
|
| 1913 |
+
{
|
| 1914 |
+
"index": 97,
|
| 1915 |
+
"start": 198656,
|
| 1916 |
+
"nll_delta": 0.0,
|
| 1917 |
+
"ppl_delta": 0.0,
|
| 1918 |
+
"nll_exact": true
|
| 1919 |
+
},
|
| 1920 |
+
{
|
| 1921 |
+
"index": 98,
|
| 1922 |
+
"start": 200704,
|
| 1923 |
+
"nll_delta": 0.0,
|
| 1924 |
+
"ppl_delta": 0.0,
|
| 1925 |
+
"nll_exact": true
|
| 1926 |
+
},
|
| 1927 |
+
{
|
| 1928 |
+
"index": 99,
|
| 1929 |
+
"start": 202752,
|
| 1930 |
+
"nll_delta": 0.0,
|
| 1931 |
+
"ppl_delta": 0.0,
|
| 1932 |
+
"nll_exact": true
|
| 1933 |
+
},
|
| 1934 |
+
{
|
| 1935 |
+
"index": 100,
|
| 1936 |
+
"start": 204800,
|
| 1937 |
+
"nll_delta": 0.0,
|
| 1938 |
+
"ppl_delta": 0.0,
|
| 1939 |
+
"nll_exact": true
|
| 1940 |
+
},
|
| 1941 |
+
{
|
| 1942 |
+
"index": 101,
|
| 1943 |
+
"start": 206848,
|
| 1944 |
+
"nll_delta": 0.0,
|
| 1945 |
+
"ppl_delta": 0.0,
|
| 1946 |
+
"nll_exact": true
|
| 1947 |
+
},
|
| 1948 |
+
{
|
| 1949 |
+
"index": 102,
|
| 1950 |
+
"start": 208896,
|
| 1951 |
+
"nll_delta": 0.0,
|
| 1952 |
+
"ppl_delta": 0.0,
|
| 1953 |
+
"nll_exact": true
|
| 1954 |
+
},
|
| 1955 |
+
{
|
| 1956 |
+
"index": 103,
|
| 1957 |
+
"start": 210944,
|
| 1958 |
+
"nll_delta": 0.0,
|
| 1959 |
+
"ppl_delta": 0.0,
|
| 1960 |
+
"nll_exact": true
|
| 1961 |
+
},
|
| 1962 |
+
{
|
| 1963 |
+
"index": 104,
|
| 1964 |
+
"start": 212992,
|
| 1965 |
+
"nll_delta": 0.0,
|
| 1966 |
+
"ppl_delta": 0.0,
|
| 1967 |
+
"nll_exact": true
|
| 1968 |
+
},
|
| 1969 |
+
{
|
| 1970 |
+
"index": 105,
|
| 1971 |
+
"start": 215040,
|
| 1972 |
+
"nll_delta": 0.0,
|
| 1973 |
+
"ppl_delta": 0.0,
|
| 1974 |
+
"nll_exact": true
|
| 1975 |
+
},
|
| 1976 |
+
{
|
| 1977 |
+
"index": 106,
|
| 1978 |
+
"start": 217088,
|
| 1979 |
+
"nll_delta": 0.0,
|
| 1980 |
+
"ppl_delta": 0.0,
|
| 1981 |
+
"nll_exact": true
|
| 1982 |
+
},
|
| 1983 |
+
{
|
| 1984 |
+
"index": 107,
|
| 1985 |
+
"start": 219136,
|
| 1986 |
+
"nll_delta": 0.0,
|
| 1987 |
+
"ppl_delta": 0.0,
|
| 1988 |
+
"nll_exact": true
|
| 1989 |
+
},
|
| 1990 |
+
{
|
| 1991 |
+
"index": 108,
|
| 1992 |
+
"start": 221184,
|
| 1993 |
+
"nll_delta": 0.0,
|
| 1994 |
+
"ppl_delta": 0.0,
|
| 1995 |
+
"nll_exact": true
|
| 1996 |
+
},
|
| 1997 |
+
{
|
| 1998 |
+
"index": 109,
|
| 1999 |
+
"start": 223232,
|
| 2000 |
+
"nll_delta": 0.0,
|
| 2001 |
+
"ppl_delta": 0.0,
|
| 2002 |
+
"nll_exact": true
|
| 2003 |
+
},
|
| 2004 |
+
{
|
| 2005 |
+
"index": 110,
|
| 2006 |
+
"start": 225280,
|
| 2007 |
+
"nll_delta": 0.0,
|
| 2008 |
+
"ppl_delta": 0.0,
|
| 2009 |
+
"nll_exact": true
|
| 2010 |
+
},
|
| 2011 |
+
{
|
| 2012 |
+
"index": 111,
|
| 2013 |
+
"start": 227328,
|
| 2014 |
+
"nll_delta": 0.0,
|
| 2015 |
+
"ppl_delta": 0.0,
|
| 2016 |
+
"nll_exact": true
|
| 2017 |
+
},
|
| 2018 |
+
{
|
| 2019 |
+
"index": 112,
|
| 2020 |
+
"start": 229376,
|
| 2021 |
+
"nll_delta": 0.0,
|
| 2022 |
+
"ppl_delta": 0.0,
|
| 2023 |
+
"nll_exact": true
|
| 2024 |
+
},
|
| 2025 |
+
{
|
| 2026 |
+
"index": 113,
|
| 2027 |
+
"start": 231424,
|
| 2028 |
+
"nll_delta": 0.0,
|
| 2029 |
+
"ppl_delta": 0.0,
|
| 2030 |
+
"nll_exact": true
|
| 2031 |
+
},
|
| 2032 |
+
{
|
| 2033 |
+
"index": 114,
|
| 2034 |
+
"start": 233472,
|
| 2035 |
+
"nll_delta": 0.0,
|
| 2036 |
+
"ppl_delta": 0.0,
|
| 2037 |
+
"nll_exact": true
|
| 2038 |
+
},
|
| 2039 |
+
{
|
| 2040 |
+
"index": 115,
|
| 2041 |
+
"start": 235520,
|
| 2042 |
+
"nll_delta": 0.0,
|
| 2043 |
+
"ppl_delta": 0.0,
|
| 2044 |
+
"nll_exact": true
|
| 2045 |
+
},
|
| 2046 |
+
{
|
| 2047 |
+
"index": 116,
|
| 2048 |
+
"start": 237568,
|
| 2049 |
+
"nll_delta": 0.0,
|
| 2050 |
+
"ppl_delta": 0.0,
|
| 2051 |
+
"nll_exact": true
|
| 2052 |
+
},
|
| 2053 |
+
{
|
| 2054 |
+
"index": 117,
|
| 2055 |
+
"start": 239616,
|
| 2056 |
+
"nll_delta": 0.0,
|
| 2057 |
+
"ppl_delta": 0.0,
|
| 2058 |
+
"nll_exact": true
|
| 2059 |
+
},
|
| 2060 |
+
{
|
| 2061 |
+
"index": 118,
|
| 2062 |
+
"start": 241664,
|
| 2063 |
+
"nll_delta": 0.0,
|
| 2064 |
+
"ppl_delta": 0.0,
|
| 2065 |
+
"nll_exact": true
|
| 2066 |
+
},
|
| 2067 |
+
{
|
| 2068 |
+
"index": 119,
|
| 2069 |
+
"start": 243712,
|
| 2070 |
+
"nll_delta": 0.0,
|
| 2071 |
+
"ppl_delta": 0.0,
|
| 2072 |
+
"nll_exact": true
|
| 2073 |
+
},
|
| 2074 |
+
{
|
| 2075 |
+
"index": 120,
|
| 2076 |
+
"start": 245760,
|
| 2077 |
+
"nll_delta": 0.0,
|
| 2078 |
+
"ppl_delta": 0.0,
|
| 2079 |
+
"nll_exact": true
|
| 2080 |
+
},
|
| 2081 |
+
{
|
| 2082 |
+
"index": 121,
|
| 2083 |
+
"start": 247808,
|
| 2084 |
+
"nll_delta": 0.0,
|
| 2085 |
+
"ppl_delta": 0.0,
|
| 2086 |
+
"nll_exact": true
|
| 2087 |
+
},
|
| 2088 |
+
{
|
| 2089 |
+
"index": 122,
|
| 2090 |
+
"start": 249856,
|
| 2091 |
+
"nll_delta": 0.0,
|
| 2092 |
+
"ppl_delta": 0.0,
|
| 2093 |
+
"nll_exact": true
|
| 2094 |
+
},
|
| 2095 |
+
{
|
| 2096 |
+
"index": 123,
|
| 2097 |
+
"start": 251904,
|
| 2098 |
+
"nll_delta": 0.0,
|
| 2099 |
+
"ppl_delta": 0.0,
|
| 2100 |
+
"nll_exact": true
|
| 2101 |
+
},
|
| 2102 |
+
{
|
| 2103 |
+
"index": 124,
|
| 2104 |
+
"start": 253952,
|
| 2105 |
+
"nll_delta": 0.0,
|
| 2106 |
+
"ppl_delta": 0.0,
|
| 2107 |
+
"nll_exact": true
|
| 2108 |
+
},
|
| 2109 |
+
{
|
| 2110 |
+
"index": 125,
|
| 2111 |
+
"start": 256000,
|
| 2112 |
+
"nll_delta": 0.0,
|
| 2113 |
+
"ppl_delta": 0.0,
|
| 2114 |
+
"nll_exact": true
|
| 2115 |
+
},
|
| 2116 |
+
{
|
| 2117 |
+
"index": 126,
|
| 2118 |
+
"start": 258048,
|
| 2119 |
+
"nll_delta": 0.0,
|
| 2120 |
+
"ppl_delta": 0.0,
|
| 2121 |
+
"nll_exact": true
|
| 2122 |
+
},
|
| 2123 |
+
{
|
| 2124 |
+
"index": 127,
|
| 2125 |
+
"start": 260096,
|
| 2126 |
+
"nll_delta": 0.0,
|
| 2127 |
+
"ppl_delta": 0.0,
|
| 2128 |
+
"nll_exact": true
|
| 2129 |
+
},
|
| 2130 |
+
{
|
| 2131 |
+
"index": 128,
|
| 2132 |
+
"start": 262144,
|
| 2133 |
+
"nll_delta": 0.0,
|
| 2134 |
+
"ppl_delta": 0.0,
|
| 2135 |
+
"nll_exact": true
|
| 2136 |
+
},
|
| 2137 |
+
{
|
| 2138 |
+
"index": 129,
|
| 2139 |
+
"start": 264192,
|
| 2140 |
+
"nll_delta": 0.0,
|
| 2141 |
+
"ppl_delta": 0.0,
|
| 2142 |
+
"nll_exact": true
|
| 2143 |
+
}
|
| 2144 |
+
]
|
| 2145 |
+
},
|
| 2146 |
+
"mk": {
|
| 2147 |
+
"rows": 768,
|
| 2148 |
+
"all_generated_ids_exact": true,
|
| 2149 |
+
"all_output_text_exact": true,
|
| 2150 |
+
"all_predictions_exact": true,
|
| 2151 |
+
"all_correctness_exact": true,
|
| 2152 |
+
"changed_rows": 0,
|
| 2153 |
+
"differences": []
|
| 2154 |
+
}
|
| 2155 |
+
}
|
| 2156 |
+
},
|
| 2157 |
+
"errors": [],
|
| 2158 |
+
"integrity_passed": true,
|
| 2159 |
+
"exact_replay": true,
|
| 2160 |
+
"status": "exact_replay",
|
| 2161 |
+
"files": {
|
| 2162 |
+
"published": {
|
| 2163 |
+
"path": "/Users/Kun/Documents/ChatGPT/mamb2_8B_Recall/reports/source_resurface_v1_confirm_full.json",
|
| 2164 |
+
"sha256": "4c99694d66af1db71924bd9d3113f1ea2f0a9b93191ed229f3d26f2320c8c940"
|
| 2165 |
+
},
|
| 2166 |
+
"replay": {
|
| 2167 |
+
"path": "/Users/Kun/Documents/ChatGPT/mamb2_8B_Recall/reports/verification_replay_v1.json",
|
| 2168 |
+
"sha256": "a83faedb5f25150ff8c3bf93a312619c11191e5dd06677d236cb7658c8173779"
|
| 2169 |
+
},
|
| 2170 |
+
"adapter": {
|
| 2171 |
+
"path": "/Users/Kun/Documents/ChatGPT/mamb2_8B_Recall/artifacts/source_resurface_v1/adapter_fp16.pt",
|
| 2172 |
+
"sha256": "e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0"
|
| 2173 |
+
}
|
| 2174 |
+
}
|
| 2175 |
+
}
|
reports/verification_hub_metadata_v1.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"method": "huggingface_hub.HfApi model_info(files_metadata=True) and dataset_info at pinned revisions",
|
| 3 |
+
"verified_date": "2026-09-28",
|
| 4 |
+
"model": "nvidia/mamba2-8b-3t-4k",
|
| 5 |
+
"model_revision": "b915550c63ba9359f88f44d1f6a600d85af27302",
|
| 6 |
+
"files": [
|
| 7 |
+
{
|
| 8 |
+
"file": "mt_nlg_plus_multilingual_ja_zh_the_stack_frac_015_256k.model",
|
| 9 |
+
"bytes": 4573028,
|
| 10 |
+
"sha256": "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09"
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
"file": "release/mp_rank_00/model_optim_rng.pt",
|
| 14 |
+
"bytes": 16474189490,
|
| 15 |
+
"sha256": "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb"
|
| 16 |
+
}
|
| 17 |
+
],
|
| 18 |
+
"dataset": "Salesforce/wikitext",
|
| 19 |
+
"dataset_revision": "b08601e04326c79dfdd32d625aee71d232d685c3"
|
| 20 |
+
}
|
reports/verification_origin_v1.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"git_commit": "e4137a43ef87cb95b70243ea2271f8e9b3d93d27",
|
| 3 |
+
"git_clean": true,
|
| 4 |
+
"environment": {
|
| 5 |
+
"python": "3.10.12",
|
| 6 |
+
"packages": {
|
| 7 |
+
"torch": "2.11.0+cu128",
|
| 8 |
+
"mamba-ssm": "2.3.2.post1",
|
| 9 |
+
"numpy": "1.26.4",
|
| 10 |
+
"triton": "3.6.0",
|
| 11 |
+
"datasets": "4.8.5",
|
| 12 |
+
"sentencepiece": "0.2.1"
|
| 13 |
+
},
|
| 14 |
+
"cuda_runtime": "12.8",
|
| 15 |
+
"gpu": "NVIDIA RTX PRO 6000 Blackwell Server Edition",
|
| 16 |
+
"tf32_matmul": false
|
| 17 |
+
},
|
| 18 |
+
"command": [
|
| 19 |
+
"/home/horde/.venvs/lodram/bin/python",
|
| 20 |
+
"scripts/evaluate.py",
|
| 21 |
+
"--source-dir",
|
| 22 |
+
"/home/horde/Mamba2-8B-E8W5/models/source",
|
| 23 |
+
"--adapter",
|
| 24 |
+
"/home/horde/mamb2_8B_Recall_verify_e4137a4/artifacts/source_resurface_v1/adapter_fp16.pt",
|
| 25 |
+
"--data-root",
|
| 26 |
+
"/home/horde/mamb2_8B_Recall_verify_e4137a4/training_data/numeric_v1",
|
| 27 |
+
"--eval-manifest-sha256",
|
| 28 |
+
"227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c",
|
| 29 |
+
"--split",
|
| 30 |
+
"confirm",
|
| 31 |
+
"--report",
|
| 32 |
+
"/home/horde/mamb2_8B_Recall_verify_e4137a4/reports/verification_replay_v1.json"
|
| 33 |
+
],
|
| 34 |
+
"code_sha256": {
|
| 35 |
+
"mamba2_recall/__init__.py": "79b32606ac476c3248911c55571bf97f96689770067856ce8347837478ef33fd",
|
| 36 |
+
"mamba2_recall/calibration.py": "54e178521abfe2513fb7bac2aed2ef178fc01b63135222ecc212001ee3ce0a04",
|
| 37 |
+
"mamba2_recall/evaluation.py": "95cba0b201e37f92e6cbfadb9b3e9d79ba7b0cdc9efda6a58a6216b0d84d35e0",
|
| 38 |
+
"mamba2_recall/resurface_data.py": "1a547fe3cedca406d6e3db85f65c3ce554558691e3b29b9c92d8fd6bd1c1ba35",
|
| 39 |
+
"mamba2_recall/resurface_loss.py": "ec045368583b6e49f484341b2d718658bb59e8d11050710377742752c1c67294",
|
| 40 |
+
"mamba2_recall/resurface_native.py": "2dd08c7ee8958c832f0ae9da7cf5f261dceeff3e528e493c905c7c52df7166d7",
|
| 41 |
+
"mamba2_recall/runtime.py": "73a405b4286dda403f252cf0b73d367adcfead96298a1e6f440b65f5b309530c",
|
| 42 |
+
"scripts/compare_four_arms.py": "6e41f9ab4f6e39c5a23da6ad1edc29e5b10da57e93e2ea008f4d153c8f195e3b",
|
| 43 |
+
"scripts/evaluate.py": "825acc58d957abe9c755b44c783970c7a379594dfd15e0a67f0ff9a0638f74bb",
|
| 44 |
+
"scripts/prepare_data.py": "11d5e6872382fb8a62987937ec37006422b38e4b1650431a4794d5834c6a4604",
|
| 45 |
+
"scripts/prepare_prose.py": "f63659bab565f2428629f2c9239ba2bdb4ccfb6c647accc44be71b2f419a7c7e",
|
| 46 |
+
"scripts/train.py": "3ea5ef8beadf5d4f14650e9fe15949cd6116e247ddd7641d7f024c5763aa8eb2"
|
| 47 |
+
}
|
| 48 |
+
}
|
reports/verification_replay_v1.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
reports/verification_token_receipts_v1.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"complete": true,
|
| 3 |
+
"passed": true,
|
| 4 |
+
"method": "CPU-only regenerated numeric prompts and pinned WikiText tokens; SentencePiece decode of saved generated IDs; independent little-endian int64 token hashing",
|
| 5 |
+
"tokenizer_sha256": "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09",
|
| 6 |
+
"reports_sha256": {
|
| 7 |
+
"source_resurface_v1_confirm_full.json": "4c99694d66af1db71924bd9d3113f1ea2f0a9b93191ed229f3d26f2320c8c940",
|
| 8 |
+
"verification_replay_v1.json": "a83faedb5f25150ff8c3bf93a312619c11191e5dd06677d236cb7658c8173779"
|
| 9 |
+
},
|
| 10 |
+
"generated_outputs_checked": 3088,
|
| 11 |
+
"prompt_receipts_checked": 3088,
|
| 12 |
+
"ppl_window_receipts_checked": 520,
|
| 13 |
+
"train_rows": 1536,
|
| 14 |
+
"confirm_rows": 768,
|
| 15 |
+
"numeric_train_confirm_overlap_counts": {
|
| 16 |
+
"ids": 0,
|
| 17 |
+
"prompts": 0,
|
| 18 |
+
"keys": 0,
|
| 19 |
+
"values": 0
|
| 20 |
+
},
|
| 21 |
+
"errors": []
|
| 22 |
+
}
|
resurface_config.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"format": "MAMBA2_SOURCE_RESURFACE_HF_RELEASE_V1",
|
| 3 |
+
"repo_id": "EndlessChasing/Mamb2_8B_Recall",
|
| 4 |
+
"source_repository": "https://github.com/EndlessChasing/mamb2_8B_Recall",
|
| 5 |
+
"source_commit": "4478c034aff9e5dab7af47efa84214287824138d",
|
| 6 |
+
"base_model": {
|
| 7 |
+
"repo_id": "nvidia/mamba2-8b-3t-4k",
|
| 8 |
+
"revision": "b915550c63ba9359f88f44d1f6a600d85af27302",
|
| 9 |
+
"checkpoint_path": "release/mp_rank_00/model_optim_rng.pt",
|
| 10 |
+
"checkpoint_sha256": "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb",
|
| 11 |
+
"tokenizer_path": "mt_nlg_plus_multilingual_ja_zh_the_stack_frac_015_256k.model",
|
| 12 |
+
"tokenizer_sha256": "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09",
|
| 13 |
+
"parameters": 8236999680,
|
| 14 |
+
"blocks": 56,
|
| 15 |
+
"architecture": "pure Mamba2; no attention or MoE",
|
| 16 |
+
"source_dtype": "bfloat16",
|
| 17 |
+
"runtime_dtype": "float16",
|
| 18 |
+
"download_separately": true
|
| 19 |
+
},
|
| 20 |
+
"adapter": {
|
| 21 |
+
"path": "artifacts/source_resurface_v1/adapter_fp16.pt",
|
| 22 |
+
"bytes": 2374143,
|
| 23 |
+
"sha256": "e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0",
|
| 24 |
+
"parameters": 1154104,
|
| 25 |
+
"payload_bytes": 2308208,
|
| 26 |
+
"gate_mode": "soft",
|
| 27 |
+
"format": "MAMBA2_POST_D_RESURFACE_FP16_V1",
|
| 28 |
+
"insertion_site": "post-D, before grouped gated RMSNorm",
|
| 29 |
+
"additional_recurrent_cache_bytes": 0,
|
| 30 |
+
"binding": {
|
| 31 |
+
"source_checkpoint_sha256": "47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb",
|
| 32 |
+
"tokenizer_sha256": "5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09",
|
| 33 |
+
"protocol_sha256": "dee9457bfaca067b63837dcd3bc94bf9ef9a3d805b1ab04227db05a4b92c54c2",
|
| 34 |
+
"train_manifest_sha256": "e711c87378dcee84c9ff5023ae15aa11c5abe6c64fbe68c52c543eaea70103b8",
|
| 35 |
+
"prose_manifest_sha256": "facb2ca461615a4199781bd21784d642d6674f5b862641b3b9edac3fb499b89d",
|
| 36 |
+
"prose_tokens_sha256": "e54b02e5162e042a9cdd504f4eb1b1652724fb240bbc2c97608967aa26297233",
|
| 37 |
+
"prose_tokens_int64le_sha256": "049dfb6847d778897fd19b67653c3189f29fbc19a36022e8a4801306d08228bc",
|
| 38 |
+
"prose_file_exact_historical": true,
|
| 39 |
+
"adapter": "MAMBA2_POST_D_RESURFACE_FP16_V1",
|
| 40 |
+
"successful_updates": 1536
|
| 41 |
+
}
|
| 42 |
+
},
|
| 43 |
+
"custom_runtime": {
|
| 44 |
+
"loader": "mamba2_recall.runtime.load_source_model",
|
| 45 |
+
"installer": "mamba2_recall.resurface_native.install_fp16",
|
| 46 |
+
"requires_gpu": "CUDA",
|
| 47 |
+
"transformers_auto_model_compatible": false,
|
| 48 |
+
"peft_compatible": false
|
| 49 |
+
},
|
| 50 |
+
"metrics": {
|
| 51 |
+
"source_ppl": 7.334175947318572,
|
| 52 |
+
"adapter_ppl": 7.052063515606311,
|
| 53 |
+
"source_normal_mk": {
|
| 54 |
+
"correct": 147,
|
| 55 |
+
"count": 384,
|
| 56 |
+
"accuracy": 0.3828125
|
| 57 |
+
},
|
| 58 |
+
"adapter_normal_mk": {
|
| 59 |
+
"correct": 365,
|
| 60 |
+
"count": 384,
|
| 61 |
+
"accuracy": 0.9505208333333334
|
| 62 |
+
},
|
| 63 |
+
"protocol": "docs/PROTOCOL.md",
|
| 64 |
+
"verification": "docs/VERIFICATION.md",
|
| 65 |
+
"verification_report": "reports/verification_audit_v1.json",
|
| 66 |
+
"untouched_holdout": false
|
| 67 |
+
}
|
| 68 |
+
}
|
scripts/compare_four_arms.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Compare paired source/compressed Resurface results on identical inputs."""
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
OLD_MK_SHA='306ae9e8ed5e78756f7c8ea39c8db40dbebf3895ced3c5c279722be5100a344b'
|
| 10 |
+
OLD_PPL_SHA='06a71c11fc0a12a52add6e7bf5d28b8a8eb9f832b2ec1cb846d9acaf30afe961'
|
| 11 |
+
IDENTITY=('id','condition','prompt_token_sha256_int64le')
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def sha256_file(path):
|
| 15 |
+
digest=hashlib.sha256()
|
| 16 |
+
with Path(path).open('rb') as stream:
|
| 17 |
+
for chunk in iter(lambda:stream.read(8<<20),b''):
|
| 18 |
+
digest.update(chunk)
|
| 19 |
+
return digest.hexdigest()
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def identity(rows):
|
| 23 |
+
return [tuple(row[k] for k in IDENTITY) for row in rows]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def summary(rows):
|
| 27 |
+
result={}
|
| 28 |
+
for condition in ('normal','target_removed'):
|
| 29 |
+
relevant=[r for r in rows if r['condition']==condition]
|
| 30 |
+
result[condition]={'correct':sum(r['correct'] for r in relevant),
|
| 31 |
+
'count':len(relevant)}
|
| 32 |
+
return result
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def main():
|
| 36 |
+
p=argparse.ArgumentParser(description=__doc__)
|
| 37 |
+
p.add_argument('--source-report',type=Path,required=True)
|
| 38 |
+
p.add_argument('--compressed-mk-report',type=Path,required=True)
|
| 39 |
+
p.add_argument('--compressed-ppl-report',type=Path,required=True)
|
| 40 |
+
p.add_argument('--output',type=Path,required=True)
|
| 41 |
+
a=p.parse_args()
|
| 42 |
+
if a.output.exists():raise FileExistsError(a.output)
|
| 43 |
+
if (sha256_file(a.compressed_mk_report)!=OLD_MK_SHA or
|
| 44 |
+
sha256_file(a.compressed_ppl_report)!=OLD_PPL_SHA):
|
| 45 |
+
raise ValueError('Historical compressed reports differ from published receipts')
|
| 46 |
+
source=json.loads(a.source_report.read_text())
|
| 47 |
+
mk=json.loads(a.compressed_mk_report.read_text())
|
| 48 |
+
ppl=json.loads(a.compressed_ppl_report.read_text())
|
| 49 |
+
if (source.get('complete') is not True or source.get('smoke') is not False
|
| 50 |
+
or source.get('split')!='confirm' or mk.get('complete') is not True
|
| 51 |
+
or ppl.get('complete') is not True):
|
| 52 |
+
raise ValueError('Only complete full source/COMPRESSED reports are comparable')
|
| 53 |
+
rows={
|
| 54 |
+
'source_fp16':source['baseline_mk']['rows'],
|
| 55 |
+
'source_resurface':source['adapter_mk']['rows'],
|
| 56 |
+
'compressed_base':mk['arms']['current_readapted']['rows'],
|
| 57 |
+
'compressed_resurface':mk['arms']['active_resurface']['rows'],
|
| 58 |
+
}
|
| 59 |
+
if (any(len(item)!=768 for item in rows.values()) or
|
| 60 |
+
len({tuple(identity(item)) for item in rows.values()})!=1):
|
| 61 |
+
raise ValueError('Different MK prompt ordering, tokens or split')
|
| 62 |
+
for name,item in rows.items():
|
| 63 |
+
if summary(item)['normal']['count']!=384 or summary(item)['target_removed']['count']!=384:
|
| 64 |
+
raise ValueError(f'Incomplete MK condition coverage: {name}')
|
| 65 |
+
source_ppl_windows=source['baseline_ppl']['windows']
|
| 66 |
+
source_active_windows=source['adapter_ppl']['windows']
|
| 67 |
+
compressed_ppl_windows=ppl['ppl']['current_readapted']['windows']
|
| 68 |
+
compressed_active_windows=ppl['ppl']['active_resurface']['windows']
|
| 69 |
+
def windows_id(items):
|
| 70 |
+
return [(r['start'],r['target_tokens'],r['token_sha256_int64le']) for r in items]
|
| 71 |
+
if (any(len(item)!=130 for item in (source_ppl_windows,source_active_windows,
|
| 72 |
+
compressed_ppl_windows,compressed_active_windows)) or
|
| 73 |
+
len({tuple(windows_id(item)) for item in (source_ppl_windows,source_active_windows,
|
| 74 |
+
compressed_ppl_windows,compressed_active_windows)})!=1 or
|
| 75 |
+
sum(r['target_tokens'] for r in source_ppl_windows)!=264764):
|
| 76 |
+
raise ValueError('PPL tokenizer/window/target coverage differs')
|
| 77 |
+
metrics={name:{'mk':summary(item)} for name,item in rows.items()}
|
| 78 |
+
for name,value in zip(metrics,(
|
| 79 |
+
source['baseline_ppl']['ppl'],source['adapter_ppl']['ppl'],
|
| 80 |
+
ppl['ppl']['current_readapted']['summary']['ppl'],
|
| 81 |
+
ppl['ppl']['active_resurface']['summary']['ppl'])):
|
| 82 |
+
metrics[name]['ppl']=value
|
| 83 |
+
score=lambda name:100*metrics[name]['mk']['normal']['correct']/384
|
| 84 |
+
source_gain=score('source_resurface')-score('source_fp16')
|
| 85 |
+
compressed_gain=score('compressed_resurface')-score('compressed_base')
|
| 86 |
+
result={'format':'MAMBA2_SOURCE_COMPRESSED_FOUR_ARM_COMPARISON_V1',
|
| 87 |
+
'complete':True,'source_report_sha256':sha256_file(a.source_report),
|
| 88 |
+
'compressed_mk_report_sha256':OLD_MK_SHA,'compressed_ppl_report_sha256':OLD_PPL_SHA,
|
| 89 |
+
'exact_mk_prompt_identity':True,'exact_ppl_window_identity':True,
|
| 90 |
+
'metrics':metrics,'source_adapter_gain_pp':source_gain,
|
| 91 |
+
'compressed_adapter_gain_pp':compressed_gain,
|
| 92 |
+
'difference_of_gains_pp':compressed_gain-source_gain,
|
| 93 |
+
'interpretation':'Descriptive four-arm comparison on already observed numeric/template and validation data; the compressed base also received 448 small-tensor readaptation updates before adapter training, and each arm has its own unadapted-base KL teacher. Do not infer a causal quantization-only interaction or unseen-template generalization.'}
|
| 94 |
+
a.output.parent.mkdir(parents=True,exist_ok=True)
|
| 95 |
+
a.output.write_text(json.dumps(result,indent=2,allow_nan=False)+'\n')
|
| 96 |
+
print(json.dumps({'complete':True,'source_adapter_gain_pp':source_gain,
|
| 97 |
+
'compressed_adapter_gain_pp':compressed_gain,
|
| 98 |
+
'difference_of_gains_pp':compressed_gain-source_gain}),flush=True)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
if __name__=='__main__':main()
|
scripts/evaluate.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Paired FP16 source/readout recall and WikiText-2 validation evaluation."""
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
import argparse
|
| 5 |
+
import json
|
| 6 |
+
import math
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
import re
|
| 9 |
+
import sys
|
| 10 |
+
import time
|
| 11 |
+
import traceback
|
| 12 |
+
|
| 13 |
+
import torch
|
| 14 |
+
|
| 15 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 16 |
+
sys.path.insert(0,str(ROOT))
|
| 17 |
+
from mamba2_recall import calibration, evaluation, resurface_data as data
|
| 18 |
+
from mamba2_recall import resurface_native as native, runtime
|
| 19 |
+
|
| 20 |
+
MATCH = re.compile(r'(?<!\d)\d{6}(?!\d)')
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def write_json(path,value):
|
| 24 |
+
path = Path(path)
|
| 25 |
+
path.parent.mkdir(parents=True,exist_ok=True)
|
| 26 |
+
temporary = path.with_suffix(path.suffix+'.tmp')
|
| 27 |
+
temporary.write_text(json.dumps(value,indent=2,allow_nan=False)+'\n')
|
| 28 |
+
temporary.replace(path)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@torch.inference_mode()
|
| 32 |
+
def score_mk(model,tokenizer,cases,limit=None):
|
| 33 |
+
rows=[]
|
| 34 |
+
for index,case in enumerate(cases[:limit] if limit is not None else cases):
|
| 35 |
+
output,generated,tokens,cache_bytes = evaluation.generate_greedy(
|
| 36 |
+
model,tokenizer,case['prompt'],max_new_tokens=12,execution='prefill')
|
| 37 |
+
match = MATCH.search(output)
|
| 38 |
+
prediction = match.group() if match else None
|
| 39 |
+
rows.append({'id':case['id'],'condition':case['condition'],
|
| 40 |
+
'N':case['N'],'template':case['template'],
|
| 41 |
+
'prompt_token_sha256_int64le':data.token_digest(tokenizer.encode(case['prompt'])),
|
| 42 |
+
'expected':case['answer'],'prediction':prediction,
|
| 43 |
+
'correct':prediction==case['answer'],'generated_ids':generated,
|
| 44 |
+
'output':output,'prompt_tokens':tokens,'cache_bytes':cache_bytes})
|
| 45 |
+
if cache_bytes!=122028032:
|
| 46 |
+
raise RuntimeError('FP16 native cache bytes differ')
|
| 47 |
+
if (index+1)%32==0 or index==0:
|
| 48 |
+
print(json.dumps({'mk_completed':index+1,'mk_total':len(cases) if limit is None else limit}),flush=True)
|
| 49 |
+
summary={}
|
| 50 |
+
for condition in ('normal','target_removed'):
|
| 51 |
+
selected=[r for r in rows if r['condition']==condition]
|
| 52 |
+
if selected:
|
| 53 |
+
summary[condition]={'correct':sum(r['correct'] for r in selected),
|
| 54 |
+
'count':len(selected),'accuracy':sum(r['correct'] for r in selected)/len(selected)}
|
| 55 |
+
return {'rows':rows,'summary':summary,'generation':'greedy max12, full256K, fresh FP16 cache',
|
| 56 |
+
'matching':'first standalone six-digit integer'}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def compare_mk(baseline,active):
|
| 60 |
+
result={}
|
| 61 |
+
for condition in ('normal','target_removed'):
|
| 62 |
+
counts={'both_correct':0,'both_wrong':0,'gained':0,'lost':0}
|
| 63 |
+
a=[row for row in baseline['rows'] if row['condition']==condition]
|
| 64 |
+
b=[row for row in active['rows'] if row['condition']==condition]
|
| 65 |
+
if len(a)!=len(b):
|
| 66 |
+
raise ValueError('MK arm length differs')
|
| 67 |
+
for before,after in zip(a,b):
|
| 68 |
+
if any(before[key]!=after[key] for key in ('id','condition','expected','prompt_token_sha256_int64le')):
|
| 69 |
+
raise ValueError('Paired MK prompt identity differs')
|
| 70 |
+
bucket={(False,False):'both_wrong',(True,True):'both_correct',
|
| 71 |
+
(False,True):'gained',(True,False):'lost'}[(before['correct'],after['correct'])]
|
| 72 |
+
counts[bucket]+=1
|
| 73 |
+
result[condition]={**counts,'count':len(a),
|
| 74 |
+
'baseline_correct':sum(r['correct'] for r in a),
|
| 75 |
+
'adapter_correct':sum(r['correct'] for r in b),
|
| 76 |
+
'delta_percentage_points':100*(counts['gained']-counts['lost'])/len(a)}
|
| 77 |
+
return result
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def main():
|
| 81 |
+
p=argparse.ArgumentParser(description=__doc__)
|
| 82 |
+
p.add_argument('--source-dir',type=Path,required=True)
|
| 83 |
+
p.add_argument('--adapter',type=Path,required=True)
|
| 84 |
+
p.add_argument('--data-root',type=Path,required=True)
|
| 85 |
+
p.add_argument('--eval-manifest-sha256',required=True)
|
| 86 |
+
p.add_argument('--split',choices=('dev','confirm'),default='confirm')
|
| 87 |
+
p.add_argument('--report',type=Path,required=True)
|
| 88 |
+
p.add_argument('--smoke',action='store_true',help='First 8 MK rows and 2 prose windows only')
|
| 89 |
+
args=p.parse_args()
|
| 90 |
+
if args.report.exists():
|
| 91 |
+
raise FileExistsError('Preserve existing report')
|
| 92 |
+
torch.set_num_threads(8)
|
| 93 |
+
torch.backends.cuda.matmul.allow_tf32=False
|
| 94 |
+
torch.set_float32_matmul_precision('highest')
|
| 95 |
+
tokenizer=runtime.SentencePieceTokenizer(args.source_dir)
|
| 96 |
+
manifest,cases,tokens=data.load_evaluation(args.data_root,args.split,args.eval_manifest_sha256,tokenizer)
|
| 97 |
+
if (manifest['protocol_sha256']!=data.sha_file(ROOT/'docs'/'PROTOCOL.md')
|
| 98 |
+
or any(data.token_digest(tokenizer.encode(row['prompt']))!=tok['prompt_token_sha256_int64le']
|
| 99 |
+
for row,tok in zip(cases,tokens))):
|
| 100 |
+
raise ValueError('Evaluation data/protocol identity differs')
|
| 101 |
+
adapter=native.read_fp16(args.adapter)
|
| 102 |
+
if adapter['binding'].get('source_checkpoint_sha256')!=runtime.SOURCE_CHECKPOINT_SHA256:
|
| 103 |
+
raise ValueError('Adapter bound to another base')
|
| 104 |
+
if adapter['binding'].get('protocol_sha256')!=manifest['protocol_sha256']:
|
| 105 |
+
raise ValueError('Adapter and evaluation split use different protocol')
|
| 106 |
+
report={'format':'MAMBA2_SOURCE_RESURFACE_EVAL_V1','complete':False,
|
| 107 |
+
'started_unix':time.time(),'smoke':args.smoke,'split':args.split,
|
| 108 |
+
'source_checkpoint_sha256':runtime.SOURCE_CHECKPOINT_SHA256,
|
| 109 |
+
'tokenizer_sha256':tokenizer.sha256,'protocol_sha256':manifest['protocol_sha256'],
|
| 110 |
+
'data_manifest_sha256':args.eval_manifest_sha256,
|
| 111 |
+
'adapter_sha256':data.sha_file(args.adapter),
|
| 112 |
+
'dataset_status':'previously observed template family and numeric CONFIRM instances',
|
| 113 |
+
'model_precision':'source BF16 cast to native FP16'}
|
| 114 |
+
write_json(args.report,report)
|
| 115 |
+
try:
|
| 116 |
+
ids,dataset=calibration.load_wikitext_tokens(tokenizer,'validation')
|
| 117 |
+
windows=evaluation.ppl_windows(ids,2048)
|
| 118 |
+
if not args.smoke and (len(windows)!=130 or sum(len(w)-1 for _,w in windows)!=264764):
|
| 119 |
+
raise ValueError('Full WikiText validation target/window count differs')
|
| 120 |
+
if args.smoke:
|
| 121 |
+
windows=windows[:2]
|
| 122 |
+
report['dataset']=dataset
|
| 123 |
+
report['ppl_windows']=len(windows)
|
| 124 |
+
report['mk_cases']=len(cases) if not args.smoke else 8
|
| 125 |
+
model=runtime.load_source_model(args.source_dir)
|
| 126 |
+
report['baseline_ppl']=evaluation.evaluate_ppl(model,windows)
|
| 127 |
+
write_json(args.report,report)
|
| 128 |
+
report['baseline_mk']=score_mk(model,tokenizer,cases,8 if args.smoke else None)
|
| 129 |
+
write_json(args.report,report)
|
| 130 |
+
with native.install_fp16(model,args.adapter,expected_binding=adapter['binding']) as bank:
|
| 131 |
+
report['adapter_ppl']=evaluation.evaluate_ppl(model,windows)
|
| 132 |
+
write_json(args.report,report)
|
| 133 |
+
report['adapter_mk']=score_mk(model,tokenizer,cases,8 if args.smoke else None)
|
| 134 |
+
report['frozen_base_check']=bank.assert_base_frozen()
|
| 135 |
+
report['mk_comparison']=compare_mk(report['baseline_mk'],report['adapter_mk'])
|
| 136 |
+
report['ppl_delta_percent']=100*(report['adapter_ppl']['ppl']/report['baseline_ppl']['ppl']-1)
|
| 137 |
+
report['restored_probe']=score_mk(model,tokenizer,cases,8)
|
| 138 |
+
if report['restored_probe']['rows']!=report['baseline_mk']['rows'][:8]:
|
| 139 |
+
raise RuntimeError('Adapter removal failed exact same-process MK replay')
|
| 140 |
+
if args.smoke:
|
| 141 |
+
report['quality_claim']='smoke only; no full MK or PPL conclusion'
|
| 142 |
+
else:
|
| 143 |
+
report['quality_claim']='full specified protocol, reused known template family; no untouched generalization claim'
|
| 144 |
+
report['gpu_memory']=runtime.gpu_memory_receipt()
|
| 145 |
+
report['complete']=True
|
| 146 |
+
print(json.dumps({'complete':True,'baseline_ppl':report['baseline_ppl']['ppl'],
|
| 147 |
+
'adapter_ppl':report['adapter_ppl']['ppl'],
|
| 148 |
+
'mk':{k:v['delta_percentage_points'] for k,v in report['mk_comparison'].items()}}),flush=True)
|
| 149 |
+
except BaseException as error:
|
| 150 |
+
report.update(error=repr(error),traceback=traceback.format_exc())
|
| 151 |
+
raise
|
| 152 |
+
finally:
|
| 153 |
+
report['finished_unix']=time.time()
|
| 154 |
+
write_json(args.report,report)
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
if __name__=='__main__':
|
| 158 |
+
main()
|
scripts/prepare_data.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Prepare one provenance-bound numeric split without initializing CUDA."""
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 10 |
+
sys.path.insert(0, str(ROOT))
|
| 11 |
+
from mamba2_recall import resurface_data as data
|
| 12 |
+
from mamba2_recall.runtime import SentencePieceTokenizer
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 17 |
+
parser.add_argument('--split', choices=('train', 'dev', 'confirm'), required=True)
|
| 18 |
+
parser.add_argument('--source-dir', type=Path, required=True)
|
| 19 |
+
parser.add_argument('--data-root', type=Path, default=ROOT/'training_data'/'numeric_v1')
|
| 20 |
+
args = parser.parse_args()
|
| 21 |
+
if os.environ.get('CUDA_VISIBLE_DEVICES') != '':
|
| 22 |
+
raise RuntimeError('Set CUDA_VISIBLE_DEVICES= for CPU data preparation')
|
| 23 |
+
protocol = ROOT/'docs'/'PROTOCOL.md'
|
| 24 |
+
tokenizer = SentencePieceTokenizer(args.source_dir)
|
| 25 |
+
manifest = data.prepare_split(args.data_root, args.split, tokenizer,
|
| 26 |
+
protocol_path=protocol, protocol_sha256=data.sha_file(protocol),
|
| 27 |
+
tokenizer_sha256=data.TOKENIZER_SHA)
|
| 28 |
+
path = args.data_root/args.split/'manifest.json'
|
| 29 |
+
loaded, _, _ = (data.load_training(args.data_root, data.sha_file(path), tokenizer)
|
| 30 |
+
if args.split == 'train' else
|
| 31 |
+
data.load_evaluation(args.data_root, args.split, data.sha_file(path), tokenizer))
|
| 32 |
+
if loaded != manifest:
|
| 33 |
+
raise RuntimeError('Prepared split failed exact readback')
|
| 34 |
+
print(json.dumps({'split': args.split, 'rows': manifest['row_count'],
|
| 35 |
+
'manifest_sha256': data.sha_file(path),
|
| 36 |
+
'protocol_sha256': data.sha_file(protocol),
|
| 37 |
+
'cuda_initialized': False}), flush=True)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
if __name__ == '__main__':
|
| 41 |
+
main()
|
scripts/prepare_prose.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Regenerate the exact historical 448 WikiText TRAIN token windows by content."""
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
import torch
|
| 10 |
+
|
| 11 |
+
ROOT=Path(__file__).resolve().parents[1]
|
| 12 |
+
sys.path.insert(0,str(ROOT))
|
| 13 |
+
from mamba2_recall import calibration, runtime
|
| 14 |
+
|
| 15 |
+
MANIFEST_SHA='facb2ca461615a4199781bd21784d642d6674f5b862641b3b9edac3fb499b89d'
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def main():
|
| 19 |
+
p=argparse.ArgumentParser(description=__doc__)
|
| 20 |
+
p.add_argument('--source-dir',type=Path,required=True)
|
| 21 |
+
p.add_argument('--out',type=Path,required=True)
|
| 22 |
+
args=p.parse_args()
|
| 23 |
+
if os.environ.get('CUDA_VISIBLE_DEVICES')!='':
|
| 24 |
+
raise RuntimeError('Set CUDA_VISIBLE_DEVICES= to keep this CPU-only')
|
| 25 |
+
if args.out.exists():
|
| 26 |
+
raise FileExistsError(args.out)
|
| 27 |
+
manifest_path=ROOT/'docs'/'prose_train_manifest.json'
|
| 28 |
+
if runtime.sha256_file(manifest_path)!=MANIFEST_SHA:
|
| 29 |
+
raise ValueError('Historical prose selection manifest changed')
|
| 30 |
+
manifest=json.loads(manifest_path.read_text())
|
| 31 |
+
tokenizer=runtime.SentencePieceTokenizer(args.source_dir)
|
| 32 |
+
ids,dataset=calibration.load_wikitext_tokens(tokenizer,'train')
|
| 33 |
+
starts=manifest['training_starts']
|
| 34 |
+
if (len(starts)!=448 or len(ids)!=2533678 or dataset!=manifest['dataset']
|
| 35 |
+
or len(set(starts))!=448 or any(type(s) is not int or s<0 or s+2048>len(ids) for s in starts)):
|
| 36 |
+
raise ValueError('Historical corpus/windows identity differs')
|
| 37 |
+
tokens=torch.stack([ids[start:start+2048] for start in starts])
|
| 38 |
+
content_sha=runtime.token_digest(tokens.flatten().numpy())
|
| 39 |
+
if content_sha!=manifest['training_tokens_sha256_int64le']:
|
| 40 |
+
raise ValueError('Recreated TRAIN token content differs')
|
| 41 |
+
args.out.parent.mkdir(parents=True,exist_ok=True)
|
| 42 |
+
with args.out.open('xb') as stream:
|
| 43 |
+
torch.save(tokens,stream)
|
| 44 |
+
roundtrip=torch.load(args.out,map_location='cpu',weights_only=True)
|
| 45 |
+
if not torch.equal(roundtrip,tokens):
|
| 46 |
+
raise RuntimeError('Serialized TRAIN windows differ')
|
| 47 |
+
print(json.dumps({'windows':448,'tokens':int(tokens.numel()),
|
| 48 |
+
'content_sha256':content_sha,'file_sha256':runtime.sha256_file(args.out),
|
| 49 |
+
'historical_file_sha256':manifest['training_tokens_file_sha256'],
|
| 50 |
+
'identical_file':runtime.sha256_file(args.out)==manifest['training_tokens_file_sha256']}))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
if __name__=='__main__':main()
|
scripts/train.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Train the frozen-source Resurface control with the compressed arm's schedule."""
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
import math
|
| 8 |
+
import os
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
import sys
|
| 11 |
+
import time
|
| 12 |
+
import traceback
|
| 13 |
+
|
| 14 |
+
import torch
|
| 15 |
+
|
| 16 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 17 |
+
sys.path.insert(0, str(ROOT))
|
| 18 |
+
from mamba2_recall import resurface_data as data, resurface_native as native
|
| 19 |
+
from mamba2_recall import resurface_loss as objective
|
| 20 |
+
from mamba2_recall import runtime
|
| 21 |
+
|
| 22 |
+
STEPS = 1536
|
| 23 |
+
PROSE_MANIFEST_SHA = 'facb2ca461615a4199781bd21784d642d6674f5b862641b3b9edac3fb499b89d'
|
| 24 |
+
PROSE_TOKENS_SHA = 'e54b02e5162e042a9cdd504f4eb1b1652724fb240bbc2c97608967aa26297233'
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def write_json(path, value):
|
| 28 |
+
path = Path(path)
|
| 29 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 30 |
+
temporary = path.with_suffix(path.suffix+'.tmp')
|
| 31 |
+
temporary.write_text(json.dumps(value, indent=2, allow_nan=False)+'\n')
|
| 32 |
+
temporary.replace(path)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def lr_factor(j):
|
| 36 |
+
return .1 + .9*(1+math.cos(math.pi*j/(STEPS-1)))/2
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def schedule():
|
| 40 |
+
return torch.randperm(STEPS, generator=torch.Generator(device='cpu').manual_seed(2026092803)).tolist()
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def load_training_inputs(args):
|
| 44 |
+
tokenizer = runtime.SentencePieceTokenizer(args.source_dir)
|
| 45 |
+
manifest, _, examples = data.load_training(args.data_root,
|
| 46 |
+
args.train_manifest_sha256, tokenizer)
|
| 47 |
+
protocol_sha = data.sha_file(ROOT/'docs'/'PROTOCOL.md')
|
| 48 |
+
if manifest['protocol_sha256'] != protocol_sha or len(examples) != STEPS:
|
| 49 |
+
raise ValueError('Prepared numeric TRAIN split differs from frozen protocol')
|
| 50 |
+
if data.sha_file(args.prose_manifest) != PROSE_MANIFEST_SHA:
|
| 51 |
+
raise ValueError('Pinned WikiText TRAIN manifest differs')
|
| 52 |
+
prose_manifest = json.loads(args.prose_manifest.read_text())
|
| 53 |
+
windows = torch.load(args.prose_tokens, map_location='cpu', weights_only=True)
|
| 54 |
+
prose_file_sha = data.sha_file(args.prose_tokens)
|
| 55 |
+
if (not prose_manifest.get('complete') or
|
| 56 |
+
prose_manifest.get('training_tokens_file_sha256') != PROSE_TOKENS_SHA or
|
| 57 |
+
tuple(windows.shape) != (448,2048) or windows.dtype != torch.int64 or
|
| 58 |
+
sorted(prose_manifest['schedule']) != list(range(448)) or
|
| 59 |
+
runtime.token_digest(windows.flatten().numpy()) !=
|
| 60 |
+
prose_manifest['training_tokens_sha256_int64le']):
|
| 61 |
+
raise ValueError('Expected 448 disjoint, pinned prose TRAIN windows')
|
| 62 |
+
binding = {'source_checkpoint_sha256': runtime.SOURCE_CHECKPOINT_SHA256,
|
| 63 |
+
'tokenizer_sha256': tokenizer.sha256,
|
| 64 |
+
'protocol_sha256': protocol_sha,
|
| 65 |
+
'train_manifest_sha256': args.train_manifest_sha256,
|
| 66 |
+
'prose_manifest_sha256': PROSE_MANIFEST_SHA,
|
| 67 |
+
'prose_tokens_sha256': prose_file_sha,
|
| 68 |
+
'prose_tokens_int64le_sha256': prose_manifest['training_tokens_sha256_int64le'],
|
| 69 |
+
'prose_file_exact_historical': prose_file_sha == PROSE_TOKENS_SHA,
|
| 70 |
+
'adapter': native.FORMAT, 'successful_updates': STEPS}
|
| 71 |
+
return tokenizer, examples, windows, prose_manifest['schedule'], binding
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def pair_for(j, ordered, examples, windows, prose_order):
|
| 75 |
+
row = examples[ordered[j]]
|
| 76 |
+
full = torch.tensor(row['full_ids'], dtype=torch.long, device='cuda')[None]
|
| 77 |
+
answer_mask = torch.zeros_like(full[:,:-1], dtype=torch.bool)
|
| 78 |
+
answer_mask[:,row['ce_hidden_positions']] = True
|
| 79 |
+
if int(answer_mask.sum()) != row['answer_target_count']:
|
| 80 |
+
raise ValueError('Numeric answer suffix mask differs')
|
| 81 |
+
prose_index = prose_order[j%448]
|
| 82 |
+
prose_start = 512*((j//448)%4)
|
| 83 |
+
prose = windows[prose_index,prose_start:prose_start+512].to('cuda')[None]
|
| 84 |
+
if tuple(prose.shape) != (1,512):
|
| 85 |
+
raise ValueError('Prose segment geometry differs')
|
| 86 |
+
return {'id': row['id'], 'schedule_entry': ordered[j],
|
| 87 |
+
'prose_window': prose_index, 'prose_start': prose_start,
|
| 88 |
+
'mk_ids': full[:,:-1], 'mk_targets': full[:,1:], 'answer_mask': answer_mask,
|
| 89 |
+
'prose_ids': prose[:,:-1], 'prose_targets': prose[:,1:]}
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def optimizer_for(bank):
|
| 93 |
+
mix = [p for name,p in bank.masters.items() if name.endswith(('.V_read','.g_read'))]
|
| 94 |
+
router = [p for name,p in bank.masters.items() if name.endswith(('.router_w','.router_b'))]
|
| 95 |
+
return torch.optim.AdamW([{'params':mix,'lr':1e-4,'base_lr':1e-4},
|
| 96 |
+
{'params':router,'lr':3e-4,'base_lr':3e-4}],
|
| 97 |
+
betas=(.9,.999),eps=1e-8,weight_decay=0.)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def attempt(bank, teacher, pair, optimizer, scaler, j):
|
| 101 |
+
optimizer.zero_grad(set_to_none=True)
|
| 102 |
+
for group in optimizer.param_groups:
|
| 103 |
+
group['lr'] = group['base_lr']*lr_factor(j)
|
| 104 |
+
hidden,gates = bank.forward_hidden(pair['mk_ids'], use_checkpoint=True)
|
| 105 |
+
mk = objective.staged_loss_backward(hidden,pair['mk_targets'],bank.model.lm_head,
|
| 106 |
+
gates=gates,scaler=scaler,answer_mask=pair['answer_mask'],ce_weight=1.,
|
| 107 |
+
kl_weight=0.,closure_weight=0.,chunk_tokens=64)
|
| 108 |
+
del hidden,gates
|
| 109 |
+
with torch.no_grad():
|
| 110 |
+
teacher_hidden = teacher.backbone(pair['prose_ids'])
|
| 111 |
+
hidden,gates = bank.forward_hidden(pair['prose_ids'],use_checkpoint=True)
|
| 112 |
+
prose = objective.staged_loss_backward(hidden,pair['prose_targets'],bank.model.lm_head,
|
| 113 |
+
gates=gates,scaler=scaler,teacher_hidden=teacher_hidden,
|
| 114 |
+
teacher_head=teacher.lm_head,ce_weight=.5,kl_weight=.5,
|
| 115 |
+
closure_weight=3.,chunk_tokens=64)
|
| 116 |
+
del hidden,gates,teacher_hidden
|
| 117 |
+
scaler.unscale_(optimizer)
|
| 118 |
+
gradients = [p.grad for p in bank.parameters()]
|
| 119 |
+
if any(g is None for g in gradients):
|
| 120 |
+
raise RuntimeError('Missing adapter gradient')
|
| 121 |
+
overflow = (not all(bool(torch.isfinite(g).all()) for g in gradients)
|
| 122 |
+
or not mk['scaled_hidden_gradient_finite']
|
| 123 |
+
or not prose['scaled_hidden_gradient_finite'])
|
| 124 |
+
if overflow:
|
| 125 |
+
scaler.update(new_scale=scaler.get_scale()*.5)
|
| 126 |
+
magnitude = None
|
| 127 |
+
else:
|
| 128 |
+
magnitude = float(torch.nn.utils.clip_grad_norm_(bank.parameters(),1.,error_if_nonfinite=True))
|
| 129 |
+
scaler.step(optimizer)
|
| 130 |
+
scaler.update()
|
| 131 |
+
if any(not bool(torch.isfinite(p).all()) or not bool(torch.isfinite(p.half()).all())
|
| 132 |
+
for p in bank.parameters()):
|
| 133 |
+
raise FloatingPointError('Nonfinite updated adapter master or FP16 cast')
|
| 134 |
+
bank.assert_base_frozen()
|
| 135 |
+
return {'mk_ce':mk['ce'], 'prose_ce':prose['ce'],
|
| 136 |
+
'prose_kl':prose['teacher_to_student_kl'],
|
| 137 |
+
'prose_closure':prose['closure'], 'overflow':overflow,
|
| 138 |
+
'gradient_norm_before_clip':magnitude, 'loss_scale':scaler.get_scale()}
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def save_checkpoint(path, bank, optimizer, scaler, binding, success, attempts):
|
| 142 |
+
if path.exists():
|
| 143 |
+
raise FileExistsError(path)
|
| 144 |
+
temporary = path.with_suffix('.pt.tmp')
|
| 145 |
+
if temporary.exists():
|
| 146 |
+
raise FileExistsError(temporary)
|
| 147 |
+
with temporary.open('wb') as stream:
|
| 148 |
+
torch.save({'format':'MAMBA2_SOURCE_RESURFACE_CHECKPOINT_V1',
|
| 149 |
+
'binding':binding,'successful_updates':success,'attempts':attempts,
|
| 150 |
+
'masters':bank.state_dict(),'optimizer':optimizer.state_dict(),
|
| 151 |
+
'scaler':scaler.state_dict()}, stream)
|
| 152 |
+
stream.flush(); os.fsync(stream.fileno())
|
| 153 |
+
temporary.replace(path)
|
| 154 |
+
return {'path':str(path),'bytes':path.stat().st_size,'sha256':data.sha_file(path)}
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def main():
|
| 158 |
+
p = argparse.ArgumentParser(description=__doc__)
|
| 159 |
+
p.add_argument('--source-dir',type=Path,required=True)
|
| 160 |
+
p.add_argument('--data-root',type=Path,required=True)
|
| 161 |
+
p.add_argument('--train-manifest-sha256',required=True)
|
| 162 |
+
p.add_argument('--prose-manifest',type=Path,required=True)
|
| 163 |
+
p.add_argument('--prose-tokens',type=Path,required=True)
|
| 164 |
+
p.add_argument('--out-dir',type=Path,required=True)
|
| 165 |
+
p.add_argument('--smoke',action='store_true',help='Discard one GPU update; no adapter export')
|
| 166 |
+
args = p.parse_args()
|
| 167 |
+
if args.out_dir.exists():
|
| 168 |
+
raise FileExistsError('New output directory required')
|
| 169 |
+
args.out_dir.mkdir(parents=True)
|
| 170 |
+
torch.set_num_threads(8)
|
| 171 |
+
torch.manual_seed(2026092803); torch.cuda.manual_seed_all(2026092803)
|
| 172 |
+
torch.backends.cuda.matmul.allow_tf32 = False
|
| 173 |
+
torch.backends.cudnn.allow_tf32 = False
|
| 174 |
+
torch.set_float32_matmul_precision('highest')
|
| 175 |
+
report = {'format':'MAMBA2_SOURCE_RESURFACE_TRAIN_V1','complete':False,
|
| 176 |
+
'mode':'smoke' if args.smoke else 'formal',
|
| 177 |
+
'started_unix':time.time(),'source_sha256':data.sha_file(__file__),
|
| 178 |
+
'history':[],'checkpoints':[]}
|
| 179 |
+
try:
|
| 180 |
+
tokenizer, examples, windows, prose_order, binding = load_training_inputs(args)
|
| 181 |
+
report['binding'] = binding
|
| 182 |
+
write_json(args.out_dir/'report.json',report)
|
| 183 |
+
student = runtime.load_source_model(args.source_dir)
|
| 184 |
+
teacher = runtime.load_source_model(args.source_dir)
|
| 185 |
+
if sum(p.numel() for p in student.parameters()) != 8236999680:
|
| 186 |
+
raise RuntimeError('Wrong source model parameter count')
|
| 187 |
+
bank = native.ResurfaceNative(student,'soft')
|
| 188 |
+
if len(bank.masters)!=224 or sum(p.numel() for p in bank.parameters())!=1154104:
|
| 189 |
+
raise RuntimeError('Wrong adapter geometry')
|
| 190 |
+
optimizer = optimizer_for(bank)
|
| 191 |
+
scaler = torch.amp.GradScaler('cuda',init_scale=1024.,growth_factor=2.,
|
| 192 |
+
backoff_factor=.5,growth_interval=2000)
|
| 193 |
+
ordered = schedule()
|
| 194 |
+
successful = attempts = 0
|
| 195 |
+
limit = 1 if args.smoke else STEPS
|
| 196 |
+
while successful < limit:
|
| 197 |
+
if attempts >= limit+8:
|
| 198 |
+
raise RuntimeError('Overflow retry budget exceeded')
|
| 199 |
+
pair = pair_for(successful,ordered,examples,windows,prose_order)
|
| 200 |
+
start = time.monotonic()
|
| 201 |
+
result = attempt(bank,teacher,pair,optimizer,scaler,successful)
|
| 202 |
+
attempts += 1
|
| 203 |
+
if not result['overflow']:
|
| 204 |
+
successful += 1
|
| 205 |
+
row = {'attempt':attempts,'successful_updates':successful,
|
| 206 |
+
'case_id':pair['id'],'schedule_entry':pair['schedule_entry'],
|
| 207 |
+
'prose_window':pair['prose_window'],'prose_start':pair['prose_start'],
|
| 208 |
+
'answer_targets':int(pair['answer_mask'].sum()),
|
| 209 |
+
'seconds':time.monotonic()-start,**result}
|
| 210 |
+
report['history'].append(row)
|
| 211 |
+
if not args.smoke and successful and successful%384==0 and not result['overflow']:
|
| 212 |
+
report['checkpoints'].append(save_checkpoint(args.out_dir/f'checkpoint_{successful:04d}.pt',
|
| 213 |
+
bank,optimizer,scaler,binding,successful,attempts))
|
| 214 |
+
if attempts%16==0 or successful==limit or result['overflow']:
|
| 215 |
+
report.update(successful_updates=successful,attempts=attempts,
|
| 216 |
+
gpu_memory=runtime.gpu_memory_receipt())
|
| 217 |
+
write_json(args.out_dir/'report.json',report)
|
| 218 |
+
print(json.dumps({'updates':successful,'attempts':attempts,
|
| 219 |
+
'mk_ce':result['mk_ce'],'prose_ce':result['prose_ce'],
|
| 220 |
+
'overflow':result['overflow']}),flush=True)
|
| 221 |
+
if not args.smoke:
|
| 222 |
+
adapter_path = args.out_dir/'adapter_fp16.pt'
|
| 223 |
+
exported = bank.export_fp16(adapter_path,binding=binding)
|
| 224 |
+
if native.read_fp16(adapter_path,expected_binding=binding)['gate_mode']!='soft':
|
| 225 |
+
raise RuntimeError('Export roundtrip differs')
|
| 226 |
+
report['adapter'] = exported
|
| 227 |
+
report['frozen_base_check'] = bank.assert_base_frozen()
|
| 228 |
+
report['teacher_base_parameters_frozen'] = all(
|
| 229 |
+
not p.requires_grad and p.grad is None for p in teacher.parameters())
|
| 230 |
+
report.update(complete=True,successful_updates=successful,attempts=attempts,
|
| 231 |
+
gpu_memory=runtime.gpu_memory_receipt())
|
| 232 |
+
bank.close()
|
| 233 |
+
except BaseException as error:
|
| 234 |
+
report.update(error=repr(error),traceback=traceback.format_exc())
|
| 235 |
+
raise
|
| 236 |
+
finally:
|
| 237 |
+
report['finished_unix'] = time.time()
|
| 238 |
+
write_json(args.out_dir/'report.json',report)
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
if __name__=='__main__':
|
| 242 |
+
main()
|
scripts/verify_replay.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Independently audit raw PPL/MK reports and compare a fresh v1 GPU replay.
|
| 3 |
+
|
| 4 |
+
Only the Python standard library is required. Exit 1 means an identity,
|
| 5 |
+
structure, or arithmetic check failed. Exit 0 means both reports are internally
|
| 6 |
+
valid; inspect ``exact_replay`` and ``status`` for numerical/output differences.
|
| 7 |
+
No tokenizer decoding or model inference is performed by this offline audit.
|
| 8 |
+
"""
|
| 9 |
+
from __future__ import annotations
|
| 10 |
+
|
| 11 |
+
import argparse
|
| 12 |
+
from collections import Counter
|
| 13 |
+
import copy
|
| 14 |
+
import hashlib
|
| 15 |
+
import json
|
| 16 |
+
import math
|
| 17 |
+
from pathlib import Path
|
| 18 |
+
import re
|
| 19 |
+
import sys
|
| 20 |
+
import tempfile
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 24 |
+
PINS = {
|
| 25 |
+
'source_checkpoint_sha256': '47c2766f6aad89d73beafbeaecb334aab902d7370906d081764a90bb7a8bbbcb',
|
| 26 |
+
'tokenizer_sha256': '5862e2f71caf762bc9845662be5fec2867deb58d874568235a02a36c5111cd09',
|
| 27 |
+
'protocol_sha256': 'dee9457bfaca067b63837dcd3bc94bf9ef9a3d805b1ab04227db05a4b92c54c2',
|
| 28 |
+
'adapter_sha256': 'e8b2b4dfe69f8e85dc9e147c9aeaa3297cff14f4043e558bb1795ad476c1fca0',
|
| 29 |
+
}
|
| 30 |
+
PUBLISHED_METADATA_PINS = {
|
| 31 |
+
'data_manifest_sha256': '227737dd5fbb301d76e583457ff8ee29246047661b3e9a64ebd068a6f34f376c',
|
| 32 |
+
'dataset_fingerprint': '51d84d52d095f90d',
|
| 33 |
+
}
|
| 34 |
+
DATASET_PINS = {
|
| 35 |
+
'dataset': 'Salesforce/wikitext', 'configuration': 'wikitext-2-raw-v1',
|
| 36 |
+
'split': 'validation', 'revision_argument': 'b08601e04326c79dfdd32d625aee71d232d685c3',
|
| 37 |
+
'document_join': 'two newline characters',
|
| 38 |
+
'text_sha256': 'b44fb967f92b525731216a507d1fbc44b97446b7ef0a2b4d1a893f81f1bbc29e',
|
| 39 |
+
'token_stream_sha256_int64le': '5bbeae08ba8eb34a482f3b6e9d17b182e67229dd14b2853d87f89fc72e5ad027',
|
| 40 |
+
'total_tokens': 264765, 'tokenizer_sha256': PINS['tokenizer_sha256'],
|
| 41 |
+
'automatic_special_tokens': False,
|
| 42 |
+
}
|
| 43 |
+
MATCH = re.compile(r'(?<!\d)\d{6}(?!\d)')
|
| 44 |
+
SHA = re.compile(r'[0-9a-f]{64}')
|
| 45 |
+
IDENTITY_FIELDS = ('id', 'condition', 'N', 'template', 'expected',
|
| 46 |
+
'prompt_token_sha256_int64le', 'prompt_tokens', 'cache_bytes')
|
| 47 |
+
PPL_IDENTITY_FIELDS = ('start', 'input_tokens', 'target_tokens', 'token_sha256_int64le')
|
| 48 |
+
ARITHMETIC_REL_TOL = 1e-12
|
| 49 |
+
ARITHMETIC_ABS_TOL = 1e-9
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def file_sha256(path):
|
| 53 |
+
digest = hashlib.sha256()
|
| 54 |
+
with Path(path).open('rb') as handle:
|
| 55 |
+
for block in iter(lambda: handle.read(1 << 20), b''):
|
| 56 |
+
digest.update(block)
|
| 57 |
+
return digest.hexdigest()
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def load_json(path):
|
| 61 |
+
def reject_duplicates(pairs):
|
| 62 |
+
result = {}
|
| 63 |
+
for key, value in pairs:
|
| 64 |
+
if key in result:
|
| 65 |
+
raise ValueError('Duplicate JSON key: ' + key)
|
| 66 |
+
result[key] = value
|
| 67 |
+
return result
|
| 68 |
+
|
| 69 |
+
def reject_constant(value):
|
| 70 |
+
raise ValueError('Nonfinite JSON constant: ' + value)
|
| 71 |
+
|
| 72 |
+
return json.loads(Path(path).read_text(), object_pairs_hook=reject_duplicates,
|
| 73 |
+
parse_constant=reject_constant)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def write_new_audit(path, result):
|
| 77 |
+
"""Preserve existing receipts, including if a path appears during auditing."""
|
| 78 |
+
serialized = json.dumps(result, indent=2, allow_nan=False) + '\n'
|
| 79 |
+
path = Path(path)
|
| 80 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 81 |
+
with path.open('x') as handle:
|
| 82 |
+
handle.write(serialized)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def expected_mk_order():
|
| 86 |
+
return [(f'resurface-confirm-n{size}-t{template}-s{sample}' +
|
| 87 |
+
('-removed' if condition == 'target_removed' else ''),
|
| 88 |
+
condition, size, template)
|
| 89 |
+
for size in (16, 64) for template in range(3) for sample in range(64)
|
| 90 |
+
for condition in ('normal', 'target_removed')]
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class Audit:
|
| 94 |
+
def __init__(self):
|
| 95 |
+
self.errors = []
|
| 96 |
+
self.decoded_outputs = {}
|
| 97 |
+
|
| 98 |
+
def check(self, condition, message):
|
| 99 |
+
if not condition:
|
| 100 |
+
self.errors.append(message)
|
| 101 |
+
|
| 102 |
+
def number(self, value, label, minimum=0):
|
| 103 |
+
valid = type(value) in (int, float) and math.isfinite(value) and value >= minimum
|
| 104 |
+
self.check(valid, label + ': expected finite number >= ' + str(minimum))
|
| 105 |
+
if not valid:
|
| 106 |
+
raise ValueError(label + ': invalid numeric value')
|
| 107 |
+
return value
|
| 108 |
+
|
| 109 |
+
def integer(self, value, label, minimum=0):
|
| 110 |
+
self.check(type(value) is int and value >= minimum, label + ': invalid integer')
|
| 111 |
+
|
| 112 |
+
def equal(self, actual, expected, label):
|
| 113 |
+
self.check(type(actual) is type(expected) and actual == expected,
|
| 114 |
+
label + ': inconsistent value')
|
| 115 |
+
|
| 116 |
+
def arithmetic(self, actual, expected, label):
|
| 117 |
+
actual = self.number(actual, label, minimum=-math.inf)
|
| 118 |
+
self.check(math.isclose(actual, expected, rel_tol=ARITHMETIC_REL_TOL,
|
| 119 |
+
abs_tol=ARITHMETIC_ABS_TOL),
|
| 120 |
+
f'{label}: stored={actual!r}, recomputed={expected!r}')
|
| 121 |
+
|
| 122 |
+
def ppl(self, block, label):
|
| 123 |
+
rows = block['windows']
|
| 124 |
+
self.equal(len(rows), 130, label + '.window_count')
|
| 125 |
+
self.equal(block['execution'], 'prefill', label + '.execution')
|
| 126 |
+
self.equal(block['cache_dtype'], 'SSD scan internal precision', label + '.cache_dtype')
|
| 127 |
+
self.equal(block['cache_bytes'], None, label + '.cache_bytes')
|
| 128 |
+
self.equal(block['logits_chunk_tokens'], 64, label + '.logits_chunk_tokens')
|
| 129 |
+
self.equal(block['score'], 'next-token cross entropy; no BOS/EOS added; each window starts from zero state',
|
| 130 |
+
label + '.score')
|
| 131 |
+
losses, targets = [], []
|
| 132 |
+
for index, row in enumerate(rows):
|
| 133 |
+
tag = f'{label}.windows[{index}]'
|
| 134 |
+
target_count = 2048 if index < 129 else 572
|
| 135 |
+
self.equal(row['start'], index * 2048, tag + '.start')
|
| 136 |
+
self.equal(row['target_tokens'], target_count, tag + '.target_tokens')
|
| 137 |
+
self.equal(row['input_tokens'], target_count, tag + '.input_tokens')
|
| 138 |
+
self.check(isinstance(row['token_sha256_int64le'], str) and
|
| 139 |
+
SHA.fullmatch(row['token_sha256_int64le']) is not None, tag + '.token_hash')
|
| 140 |
+
loss = self.number(row['nll'], tag + '.nll')
|
| 141 |
+
losses.append(loss)
|
| 142 |
+
targets.append(row['target_tokens'])
|
| 143 |
+
self.arithmetic(row['ppl'], math.exp(loss / target_count), tag + '.ppl')
|
| 144 |
+
target_total, nll = sum(targets), math.fsum(losses)
|
| 145 |
+
self.equal(target_total, 264764, label + '.target_count')
|
| 146 |
+
self.equal(block['target_tokens'], target_total, label + '.target_tokens')
|
| 147 |
+
self.arithmetic(block['nll'], nll, label + '.nll')
|
| 148 |
+
ppl = math.exp(nll / target_total)
|
| 149 |
+
self.arithmetic(block['ppl'], ppl, label + '.ppl')
|
| 150 |
+
return {'windows': len(rows), 'target_tokens': target_total, 'nll_recomputed': nll,
|
| 151 |
+
'ppl_recomputed': ppl, 'stored_nll_minus_recomputed': block['nll'] - nll,
|
| 152 |
+
'stored_ppl_minus_recomputed': block['ppl'] - ppl}
|
| 153 |
+
|
| 154 |
+
def mk(self, block, label, probe=False):
|
| 155 |
+
rows = block['rows']
|
| 156 |
+
order = expected_mk_order()[:8] if probe else expected_mk_order()
|
| 157 |
+
self.equal(len(rows), len(order), label + '.row_count')
|
| 158 |
+
self.equal(block['generation'], 'greedy max12, full256K, fresh FP16 cache', label + '.generation')
|
| 159 |
+
self.equal(block['matching'], 'first standalone six-digit integer', label + '.matching')
|
| 160 |
+
self.equal(len(set(row['id'] for row in rows)), len(rows), label + '.unique_ids')
|
| 161 |
+
self.equal(len(set(row['prompt_token_sha256_int64le'] for row in rows)), len(rows),
|
| 162 |
+
label + '.unique_prompt_hashes')
|
| 163 |
+
correct = []
|
| 164 |
+
for index, row in enumerate(rows):
|
| 165 |
+
tag = f'{label}.rows[{index}]'
|
| 166 |
+
if index < len(order):
|
| 167 |
+
self.equal(tuple(row[key] for key in ('id', 'condition', 'N', 'template')),
|
| 168 |
+
order[index], tag + '.ordered_case_identity')
|
| 169 |
+
self.check(isinstance(row['expected'], str) and
|
| 170 |
+
re.fullmatch(r'[0-9]{6}', row['expected']) is not None, tag + '.expected')
|
| 171 |
+
self.check(isinstance(row['output'], str), tag + '.output must be text')
|
| 172 |
+
self.check(isinstance(row['prompt_token_sha256_int64le'], str) and
|
| 173 |
+
SHA.fullmatch(row['prompt_token_sha256_int64le']) is not None, tag + '.prompt_hash')
|
| 174 |
+
self.integer(row['prompt_tokens'], tag + '.prompt_tokens', minimum=1)
|
| 175 |
+
self.equal(row['cache_bytes'], 122028032, tag + '.cache_bytes')
|
| 176 |
+
generated = row['generated_ids']
|
| 177 |
+
self.check(isinstance(generated, list) and 1 <= len(generated) <= 12,
|
| 178 |
+
tag + '.generated_ids count outside greedy max12')
|
| 179 |
+
self.check(all(type(token) is int and 0 <= token < 256000 for token in generated),
|
| 180 |
+
tag + '.generated_ids outside vocabulary')
|
| 181 |
+
if generated:
|
| 182 |
+
self.check(3 not in generated[:-1], tag + '.tokens after EOS')
|
| 183 |
+
self.check(len(generated) == 12 or generated[-1] == 3,
|
| 184 |
+
tag + '.short generation without EOS')
|
| 185 |
+
token_key = tuple(generated)
|
| 186 |
+
if token_key in self.decoded_outputs:
|
| 187 |
+
self.equal(row['output'], self.decoded_outputs[token_key], tag + '.same_ids_different_output')
|
| 188 |
+
else:
|
| 189 |
+
self.decoded_outputs[token_key] = row['output']
|
| 190 |
+
match = MATCH.search(row['output'])
|
| 191 |
+
prediction = match.group(0) if match else None
|
| 192 |
+
score = prediction == row['expected']
|
| 193 |
+
self.equal(row['prediction'], prediction, tag + '.prediction regex rescore')
|
| 194 |
+
self.equal(row['correct'], score, tag + '.correct regex rescore')
|
| 195 |
+
correct.append(score)
|
| 196 |
+
if index % 2:
|
| 197 |
+
self.equal(row['expected'], rows[index - 1]['expected'], tag + '.paired_expected')
|
| 198 |
+
summary = {}
|
| 199 |
+
for condition in ('normal', 'target_removed'):
|
| 200 |
+
selected = [i for i, row in enumerate(rows) if row['condition'] == condition]
|
| 201 |
+
count, successes = len(selected), sum(correct[i] for i in selected)
|
| 202 |
+
summary[condition] = {'correct': successes, 'count': count,
|
| 203 |
+
'accuracy': successes / count if count else None}
|
| 204 |
+
stored = block['summary'][condition]
|
| 205 |
+
self.equal(stored['correct'], successes, label + '.' + condition + '.correct')
|
| 206 |
+
self.equal(stored['count'], count, label + '.' + condition + '.count')
|
| 207 |
+
if count:
|
| 208 |
+
self.arithmetic(stored['accuracy'], successes / count, label + '.' + condition + '.accuracy')
|
| 209 |
+
per_n = {}
|
| 210 |
+
for size in (16, 64):
|
| 211 |
+
selected = [i for i, row in enumerate(rows) if row['condition'] == 'normal' and row['N'] == size]
|
| 212 |
+
if selected:
|
| 213 |
+
count, successes = len(selected), sum(correct[i] for i in selected)
|
| 214 |
+
per_n[str(size)] = {'correct': successes, 'count': count, 'accuracy': successes / count}
|
| 215 |
+
if not probe:
|
| 216 |
+
self.equal(sum(r['prompt_tokens'] for r in rows), 517120, label + '.total_prompt_tokens')
|
| 217 |
+
self.equal(max(r['prompt_tokens'] for r in rows), 1236, label + '.max_prompt_tokens')
|
| 218 |
+
return {'summary': summary, 'normal_by_N': per_n,
|
| 219 |
+
'generated_length_histogram': dict(sorted(Counter(len(r['generated_ids']) for r in rows).items()))}
|
| 220 |
+
|
| 221 |
+
def paired_mk(self, report, label):
|
| 222 |
+
before, after = report['baseline_mk']['rows'], report['adapter_mk']['rows']
|
| 223 |
+
self.equal(len(before), len(after), label + '.paired row count')
|
| 224 |
+
for index, (old, new) in enumerate(zip(before, after)):
|
| 225 |
+
self.equal(tuple(old[k] for k in IDENTITY_FIELDS), tuple(new[k] for k in IDENTITY_FIELDS),
|
| 226 |
+
f'{label}.paired.rows[{index}].identity')
|
| 227 |
+
results = {}
|
| 228 |
+
for condition in ('normal', 'target_removed'):
|
| 229 |
+
counts = {'both_correct': 0, 'both_wrong': 0, 'gained': 0, 'lost': 0}
|
| 230 |
+
for old, new in zip(before, after):
|
| 231 |
+
if old['condition'] != condition:
|
| 232 |
+
continue
|
| 233 |
+
old_match, new_match = MATCH.search(old['output']), MATCH.search(new['output'])
|
| 234 |
+
a = old_match is not None and old_match.group() == old['expected']
|
| 235 |
+
b = new_match is not None and new_match.group() == new['expected']
|
| 236 |
+
name = {(True, True): 'both_correct', (False, False): 'both_wrong',
|
| 237 |
+
(False, True): 'gained', (True, False): 'lost'}[(a, b)]
|
| 238 |
+
counts[name] += 1
|
| 239 |
+
counts.update(count=sum(counts.values()),
|
| 240 |
+
baseline_correct=counts['both_correct'] + counts['lost'],
|
| 241 |
+
adapter_correct=counts['both_correct'] + counts['gained'])
|
| 242 |
+
counts['delta_percentage_points'] = 100 * (counts['gained'] - counts['lost']) / counts['count']
|
| 243 |
+
for field, value in counts.items():
|
| 244 |
+
stored = report['mk_comparison'][condition][field]
|
| 245 |
+
if type(value) is float:
|
| 246 |
+
self.arithmetic(stored, value, label + '.mk_comparison.' + condition + '.' + field)
|
| 247 |
+
else:
|
| 248 |
+
self.equal(stored, value, label + '.mk_comparison.' + condition + '.' + field)
|
| 249 |
+
results[condition] = counts
|
| 250 |
+
return results
|
| 251 |
+
|
| 252 |
+
def report(self, report, label):
|
| 253 |
+
self.equal(report['format'], 'MAMBA2_SOURCE_RESURFACE_EVAL_V1', label + '.format')
|
| 254 |
+
self.equal(report['complete'], True, label + '.complete')
|
| 255 |
+
self.equal(report['smoke'], False, label + '.smoke')
|
| 256 |
+
self.equal(report['split'], 'confirm', label + '.split')
|
| 257 |
+
self.equal(report['ppl_windows'], 130, label + '.ppl_windows')
|
| 258 |
+
self.equal(report['mk_cases'], 768, label + '.mk_cases')
|
| 259 |
+
self.equal(report['model_precision'], 'source BF16 cast to native FP16', label + '.precision')
|
| 260 |
+
for key, expected in PINS.items():
|
| 261 |
+
self.equal(report[key], expected, label + '.' + key)
|
| 262 |
+
manifest_sha = report['data_manifest_sha256']
|
| 263 |
+
fingerprint = report['dataset']['dataset_fingerprint']
|
| 264 |
+
self.check(isinstance(manifest_sha, str) and SHA.fullmatch(manifest_sha) is not None,
|
| 265 |
+
label + '.data_manifest_sha256: invalid SHA256')
|
| 266 |
+
self.check(isinstance(fingerprint, str) and bool(fingerprint.strip()),
|
| 267 |
+
label + '.dataset.dataset_fingerprint: expected nonempty string')
|
| 268 |
+
if label == 'published':
|
| 269 |
+
self.equal(manifest_sha, PUBLISHED_METADATA_PINS['data_manifest_sha256'],
|
| 270 |
+
label + '.data_manifest_sha256')
|
| 271 |
+
self.equal(fingerprint, PUBLISHED_METADATA_PINS['dataset_fingerprint'],
|
| 272 |
+
label + '.dataset.dataset_fingerprint')
|
| 273 |
+
for key, expected in DATASET_PINS.items():
|
| 274 |
+
self.equal(report['dataset'][key], expected, label + '.dataset.' + key)
|
| 275 |
+
base = report['frozen_base_check']
|
| 276 |
+
self.equal(base['tensors'], 507, label + '.base.tensors')
|
| 277 |
+
self.equal(base['parameters'], 8236999680, label + '.base.parameters')
|
| 278 |
+
self.equal(base['identity_version_gradients_unchanged'], True, label + '.base.frozen')
|
| 279 |
+
result = {}
|
| 280 |
+
for arm in ('baseline', 'adapter'):
|
| 281 |
+
result[arm] = {'ppl': self.ppl(report[arm + '_ppl'], label + '.' + arm + '_ppl'),
|
| 282 |
+
'mk': self.mk(report[arm + '_mk'], label + '.' + arm + '_mk')}
|
| 283 |
+
for index, (a, b) in enumerate(zip(report['baseline_ppl']['windows'], report['adapter_ppl']['windows'])):
|
| 284 |
+
self.equal(tuple(a[k] for k in PPL_IDENTITY_FIELDS), tuple(b[k] for k in PPL_IDENTITY_FIELDS),
|
| 285 |
+
f'{label}.paired.ppl.windows[{index}].identity')
|
| 286 |
+
result['mk_comparison'] = self.paired_mk(report, label)
|
| 287 |
+
delta = 100 * (result['adapter']['ppl']['ppl_recomputed'] / result['baseline']['ppl']['ppl_recomputed'] - 1)
|
| 288 |
+
self.arithmetic(report['ppl_delta_percent'], delta, label + '.ppl_delta_percent')
|
| 289 |
+
result['ppl_delta_percent_recomputed'] = delta
|
| 290 |
+
result['restored_probe'] = self.mk(report['restored_probe'], label + '.restored_probe', probe=True)
|
| 291 |
+
self.equal(report['restored_probe']['rows'], report['baseline_mk']['rows'][:8], label + '.restored_probe_exact')
|
| 292 |
+
return result
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
def verify_reports(published, replay, actual_adapter_sha):
|
| 296 |
+
audit = Audit()
|
| 297 |
+
result = {
|
| 298 |
+
'format': 'MAMBA2_RESURFACE_REPLAY_AUDIT_V1',
|
| 299 |
+
'arithmetic_tolerance': {'relative': ARITHMETIC_REL_TOL, 'absolute': ARITHMETIC_ABS_TOL},
|
| 300 |
+
'actual_adapter_sha256': actual_adapter_sha, 'pins': PINS,
|
| 301 |
+
'published_metadata_pins': PUBLISHED_METADATA_PINS,
|
| 302 |
+
'scope': 'Offline raw-report arithmetic, content identity, regex rescore, and fresh-report comparison. exact_replay covers scientific inputs and outputs; environment-dependent metadata equality is reported separately.',
|
| 303 |
+
'limitations': [
|
| 304 |
+
'The verifier does not run the model or independently recompute logits.',
|
| 305 |
+
'Token hashes are compared; raw prompt/PPL token bytes are not embedded in these reports.',
|
| 306 |
+
'SentencePiece decoding is not rerun. Equal generated IDs must have equal output text across reports.',
|
| 307 |
+
'Original frozen-base receipt checks identities, version counters, and gradients, not full tensor contents.',
|
| 308 |
+
'CONFIRM templates/instances and WikiText validation were previously observed.',
|
| 309 |
+
],
|
| 310 |
+
}
|
| 311 |
+
audit.equal(actual_adapter_sha, PINS['adapter_sha256'], 'actual adapter SHA256')
|
| 312 |
+
for label, report in (('published', published), ('replay', replay)):
|
| 313 |
+
try:
|
| 314 |
+
result[label] = audit.report(report, label)
|
| 315 |
+
except (KeyError, TypeError, ValueError, ZeroDivisionError, OverflowError, IndexError) as error:
|
| 316 |
+
audit.errors.append(f'{label}: malformed report: {error}')
|
| 317 |
+
differences = {}
|
| 318 |
+
try:
|
| 319 |
+
for key in PINS:
|
| 320 |
+
audit.equal(published[key], replay[key], 'replay identity.' + key)
|
| 321 |
+
for key in DATASET_PINS:
|
| 322 |
+
audit.equal(published['dataset'][key], replay['dataset'][key], 'replay dataset identity.' + key)
|
| 323 |
+
result['metadata_comparison'] = {
|
| 324 |
+
'manifests_equal': published['data_manifest_sha256'] == replay['data_manifest_sha256'],
|
| 325 |
+
'published_data_manifest_sha256': published['data_manifest_sha256'],
|
| 326 |
+
'replay_data_manifest_sha256': replay['data_manifest_sha256'],
|
| 327 |
+
'dataset_fingerprints_equal': published['dataset']['dataset_fingerprint'] == replay['dataset']['dataset_fingerprint'],
|
| 328 |
+
'published_dataset_fingerprint': published['dataset']['dataset_fingerprint'],
|
| 329 |
+
'replay_dataset_fingerprint': replay['dataset']['dataset_fingerprint'],
|
| 330 |
+
'interpretation': 'The data manifest embeds Python version and dataset fingerprints depend on environment. These metadata may differ while all ordered prompt/token hashes, answers, dataset text/token digests, and revision remain identical.',
|
| 331 |
+
}
|
| 332 |
+
for arm in ('baseline', 'adapter'):
|
| 333 |
+
a, b = published[arm + '_ppl'], replay[arm + '_ppl']
|
| 334 |
+
for source_name, block in (('published', a), ('replay', b)):
|
| 335 |
+
for field in ('nll', 'ppl'):
|
| 336 |
+
audit.number(block[field], f'{source_name}.{arm}.comparison.{field}')
|
| 337 |
+
window_deltas = []
|
| 338 |
+
for index, (old, new) in enumerate(zip(a['windows'], b['windows'])):
|
| 339 |
+
audit.equal(tuple(old[k] for k in PPL_IDENTITY_FIELDS), tuple(new[k] for k in PPL_IDENTITY_FIELDS),
|
| 340 |
+
f'replay.{arm}.ppl.windows[{index}].identity')
|
| 341 |
+
for source_name, row in (('published', old), ('replay', new)):
|
| 342 |
+
for field in ('nll', 'ppl'):
|
| 343 |
+
audit.number(row[field], f'{source_name}.{arm}.comparison.windows[{index}].{field}')
|
| 344 |
+
delta = new['nll'] - old['nll']
|
| 345 |
+
window_deltas.append({'index': index, 'start': old['start'], 'nll_delta': delta,
|
| 346 |
+
'ppl_delta': new['ppl'] - old['ppl'], 'nll_exact': old['nll'] == new['nll']})
|
| 347 |
+
before, after = published[arm + '_mk']['rows'], replay[arm + '_mk']['rows']
|
| 348 |
+
mk_deltas = []
|
| 349 |
+
for index, (old, new) in enumerate(zip(before, after)):
|
| 350 |
+
audit.equal(tuple(old[k] for k in IDENTITY_FIELDS), tuple(new[k] for k in IDENTITY_FIELDS),
|
| 351 |
+
f'replay.{arm}.mk.rows[{index}].identity')
|
| 352 |
+
fields = [key for key in ('generated_ids', 'output', 'prediction', 'correct') if old[key] != new[key]]
|
| 353 |
+
if fields:
|
| 354 |
+
mk_deltas.append({'index': index, 'id': old['id'], 'changed_fields': fields,
|
| 355 |
+
'published_prediction': old['prediction'], 'replay_prediction': new['prediction'],
|
| 356 |
+
'published_correct': old['correct'], 'replay_correct': new['correct']})
|
| 357 |
+
differences[arm] = {
|
| 358 |
+
'ppl': {'aggregate_nll_exact': a['nll'] == b['nll'], 'aggregate_ppl_exact': a['ppl'] == b['ppl'],
|
| 359 |
+
'nll_delta': b['nll'] - a['nll'], 'ppl_delta': b['ppl'] - a['ppl'],
|
| 360 |
+
'max_abs_window_nll_error': max(abs(row['nll_delta']) for row in window_deltas),
|
| 361 |
+
'max_abs_window_ppl_error': max(abs(row['ppl_delta']) for row in window_deltas),
|
| 362 |
+
'exact_nll_windows': sum(row['nll_exact'] for row in window_deltas),
|
| 363 |
+
'windows': window_deltas},
|
| 364 |
+
'mk': {'rows': len(before), 'all_generated_ids_exact': all(a['generated_ids'] == b['generated_ids'] for a, b in zip(before, after)),
|
| 365 |
+
'all_output_text_exact': all(a['output'] == b['output'] for a, b in zip(before, after)),
|
| 366 |
+
'all_predictions_exact': all(a['prediction'] == b['prediction'] for a, b in zip(before, after)),
|
| 367 |
+
'all_correctness_exact': all(a['correct'] == b['correct'] for a, b in zip(before, after)),
|
| 368 |
+
'changed_rows': len(mk_deltas), 'differences': mk_deltas},
|
| 369 |
+
}
|
| 370 |
+
except (KeyError, TypeError, ValueError, ZeroDivisionError, OverflowError, IndexError) as error:
|
| 371 |
+
audit.errors.append('replay comparison: malformed report: ' + str(error))
|
| 372 |
+
result['comparison'] = differences
|
| 373 |
+
result['errors'] = audit.errors
|
| 374 |
+
result['integrity_passed'] = not audit.errors
|
| 375 |
+
result['exact_replay'] = not audit.errors and len(differences) == 2 and all(
|
| 376 |
+
row['ppl']['aggregate_nll_exact'] and row['ppl']['aggregate_ppl_exact']
|
| 377 |
+
and row['ppl']['exact_nll_windows'] == 130 and row['ppl']['max_abs_window_ppl_error'] == 0
|
| 378 |
+
and row['mk']['changed_rows'] == 0 for row in differences.values())
|
| 379 |
+
result['status'] = ('integrity_failure' if audit.errors else
|
| 380 |
+
'exact_replay' if result['exact_replay'] else 'valid_reports_with_replay_differences')
|
| 381 |
+
return result
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
def self_test(published, actual_sha):
|
| 385 |
+
checks = []
|
| 386 |
+
|
| 387 |
+
def expect(name, candidate, valid, exact=False):
|
| 388 |
+
result = verify_reports(published, candidate, actual_sha)
|
| 389 |
+
assert result['integrity_passed'] is valid, (name, result['errors'])
|
| 390 |
+
assert result['exact_replay'] is exact, name
|
| 391 |
+
checks.append(name)
|
| 392 |
+
|
| 393 |
+
expect('published versus itself', published, True, True)
|
| 394 |
+
for name, mutate in (
|
| 395 |
+
('source hash tamper', lambda r: r.update(source_checkpoint_sha256='0' * 64)),
|
| 396 |
+
('malformed replay manifest hash', lambda r: r.update(data_manifest_sha256='invalid')),
|
| 397 |
+
('empty replay dataset fingerprint', lambda r: r['dataset'].update(dataset_fingerprint='')),
|
| 398 |
+
('PPL arithmetic tamper', lambda r: r['adapter_ppl'].update(nll=r['adapter_ppl']['nll'] + 1)),
|
| 399 |
+
('PPL token identity tamper', lambda r: r['adapter_ppl']['windows'][0].update(token_sha256_int64le='0' * 64)),
|
| 400 |
+
('MK regex correctness tamper', lambda r: r['adapter_mk']['rows'][0].update(correct=False)),
|
| 401 |
+
('MK duplicate identity tamper', lambda r: r['adapter_mk']['rows'][1].update(id=r['adapter_mk']['rows'][0]['id'])),
|
| 402 |
+
('MK paired counts tamper', lambda r: r['mk_comparison']['normal'].update(gained=223)),
|
| 403 |
+
('restored probe tamper', lambda r: r['restored_probe']['rows'][0].update(output='000000')),
|
| 404 |
+
('same token IDs inconsistent decode', lambda r: r['adapter_mk']['rows'][0].update(output=r['adapter_mk']['rows'][0]['output'] + ' ')),
|
| 405 |
+
('nonfinite NLL tamper', lambda r: r['adapter_ppl']['windows'][0].update(nll=float('nan'))),
|
| 406 |
+
):
|
| 407 |
+
candidate = copy.deepcopy(published)
|
| 408 |
+
mutate(candidate)
|
| 409 |
+
expect(name, candidate, False)
|
| 410 |
+
candidate = copy.deepcopy(published)
|
| 411 |
+
block = candidate['adapter_ppl']
|
| 412 |
+
block['windows'][0]['nll'] += 1e-7
|
| 413 |
+
block['windows'][0]['ppl'] = math.exp(block['windows'][0]['nll'] / block['windows'][0]['target_tokens'])
|
| 414 |
+
block['nll'] = math.fsum(row['nll'] for row in block['windows'])
|
| 415 |
+
block['ppl'] = math.exp(block['nll'] / block['target_tokens'])
|
| 416 |
+
candidate['ppl_delta_percent'] = 100 * (block['ppl'] / candidate['baseline_ppl']['ppl'] - 1)
|
| 417 |
+
expect('consistent tiny NLL difference reported without integrity failure', candidate, True)
|
| 418 |
+
candidate = copy.deepcopy(published)
|
| 419 |
+
candidate['adapter_mk']['rows'][-1]['generated_ids'][-1] = 251555
|
| 420 |
+
candidate['adapter_mk']['rows'][-1]['output'] += '!'
|
| 421 |
+
expect('changed MK IDs and text reported without inventing decoder validation', candidate, True)
|
| 422 |
+
candidate = copy.deepcopy(published)
|
| 423 |
+
candidate['data_manifest_sha256'] = 'a' * 64
|
| 424 |
+
candidate['dataset']['dataset_fingerprint'] = 'same-data-different-environment'
|
| 425 |
+
expect('environment metadata differs but identical content and scores are accepted', candidate, True, True)
|
| 426 |
+
metadata = verify_reports(published, candidate, actual_sha)['metadata_comparison']
|
| 427 |
+
assert metadata['manifests_equal'] is False
|
| 428 |
+
assert metadata['dataset_fingerprints_equal'] is False
|
| 429 |
+
assert metadata['replay_data_manifest_sha256'] == 'a' * 64
|
| 430 |
+
assert metadata['replay_dataset_fingerprint'] == 'same-data-different-environment'
|
| 431 |
+
bad_sha = verify_reports(published, published, '0' * 64)
|
| 432 |
+
assert not bad_sha['integrity_passed']
|
| 433 |
+
checks.append('actual adapter hash tamper')
|
| 434 |
+
with tempfile.TemporaryDirectory(prefix='mamba2-audit-selftest-') as directory:
|
| 435 |
+
path = Path(directory) / 'receipt.json'
|
| 436 |
+
write_new_audit(path, {'receipt': 'original'})
|
| 437 |
+
original = path.read_bytes()
|
| 438 |
+
try:
|
| 439 |
+
write_new_audit(path, {'receipt': 'overwrite attempt'})
|
| 440 |
+
except FileExistsError:
|
| 441 |
+
pass
|
| 442 |
+
else:
|
| 443 |
+
raise AssertionError('Existing audit receipt was overwritten')
|
| 444 |
+
assert path.read_bytes() == original
|
| 445 |
+
checks.append('existing audit receipt preserved by exclusive creation')
|
| 446 |
+
return {'passed': len(checks), 'checks': checks}
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
def main():
|
| 450 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 451 |
+
parser.add_argument('--published', type=Path)
|
| 452 |
+
parser.add_argument('--replay', type=Path)
|
| 453 |
+
parser.add_argument('--adapter', type=Path)
|
| 454 |
+
parser.add_argument('--output', type=Path)
|
| 455 |
+
parser.add_argument('--self-test', action='store_true', help='Audit bundled published report and exercise tamper cases')
|
| 456 |
+
args = parser.parse_args()
|
| 457 |
+
if args.self_test:
|
| 458 |
+
published = load_json(args.published or ROOT / 'reports/source_resurface_v1_confirm_full.json')
|
| 459 |
+
digest = file_sha256(args.adapter or ROOT / 'artifacts/source_resurface_v1/adapter_fp16.pt')
|
| 460 |
+
print(json.dumps(self_test(published, digest), indent=2, allow_nan=False))
|
| 461 |
+
return 0
|
| 462 |
+
if any(value is None for value in (args.published, args.replay, args.adapter, args.output)):
|
| 463 |
+
parser.error('--published, --replay, --adapter, and --output are required')
|
| 464 |
+
if args.output.exists():
|
| 465 |
+
print(f'Refusing to overwrite existing audit receipt: {args.output}', file=sys.stderr)
|
| 466 |
+
return 1
|
| 467 |
+
try:
|
| 468 |
+
result = verify_reports(load_json(args.published), load_json(args.replay), file_sha256(args.adapter))
|
| 469 |
+
result['files'] = {key: {'path': str(path.resolve()), 'sha256': file_sha256(path)}
|
| 470 |
+
for key, path in (('published', args.published), ('replay', args.replay), ('adapter', args.adapter))}
|
| 471 |
+
except (OSError, ValueError, TypeError) as error:
|
| 472 |
+
result = {'format': 'MAMBA2_RESURFACE_REPLAY_AUDIT_V1', 'integrity_passed': False,
|
| 473 |
+
'exact_replay': False, 'status': 'integrity_failure', 'errors': [str(error)]}
|
| 474 |
+
try:
|
| 475 |
+
write_new_audit(args.output, result)
|
| 476 |
+
except FileExistsError:
|
| 477 |
+
print(f'Refusing to overwrite existing audit receipt: {args.output}', file=sys.stderr)
|
| 478 |
+
return 1
|
| 479 |
+
except OSError as error:
|
| 480 |
+
print(f'Cannot write audit receipt {args.output}: {error}', file=sys.stderr)
|
| 481 |
+
return 1
|
| 482 |
+
print(json.dumps({key: result[key] for key in ('status', 'integrity_passed', 'exact_replay', 'errors')},
|
| 483 |
+
indent=2, allow_nan=False))
|
| 484 |
+
return 0 if result['integrity_passed'] else 1
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
if __name__ == '__main__':
|
| 488 |
+
sys.exit(main())
|