Initial release: SRT-Adapter v8a (peer-review distribution)
Browse files- .gitattributes +4 -34
- LICENSE +190 -0
- README.md +298 -0
- SHA256SUMS +26 -0
- VALIDATION_HISTORY.md +198 -0
- adapter.pt +3 -0
- adapter.safetensors +3 -0
- benchmarks/curated_metrics.json +241 -0
- benchmarks/curated_traces.json +0 -0
- config.json +52 -0
- data/DATA.md +42 -0
- data/NOTICE +28 -0
- data/archetypes.json +38 -0
- data/val_200.jsonl +0 -0
- examples/README.md +59 -0
- examples/load_and_score.py +116 -0
- paper.pdf +3 -0
- requirements.txt +5 -0
- src/srt/__init__.py +3 -0
- src/srt/adapter.py +316 -0
- src/srt/config.py +155 -0
- src/srt/modules/__init__.py +16 -0
- src/srt/modules/ben.py +71 -0
- src/srt/modules/community.py +116 -0
- src/srt/modules/mah.py +109 -0
- src/srt/modules/rrm.py +109 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,5 @@
|
|
| 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 |
-
|
| 27 |
-
*.
|
| 28 |
-
*.
|
| 29 |
-
*.
|
| 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 |
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.pdf filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.jsonl filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of tracking or improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for describing the origin of the Work and
|
| 141 |
+
reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Support. While redistributing the Work or
|
| 166 |
+
Derivative Works thereof, You may choose to offer, and charge a
|
| 167 |
+
fee for, acceptance of support, warranty, indemnity, or other
|
| 168 |
+
liability obligations and/or rights consistent with this License.
|
| 169 |
+
However, in accepting such obligations, You may act only on Your
|
| 170 |
+
own behalf and on Your sole responsibility, not on behalf of any
|
| 171 |
+
other Contributor, and only if You agree to indemnify, defend,
|
| 172 |
+
and hold each Contributor harmless for any liability incurred by,
|
| 173 |
+
or claims asserted against, such Contributor by reason of your
|
| 174 |
+
accepting any such warranty or support.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
Copyright 2026 James Burton Lancaster
|
| 179 |
+
|
| 180 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 181 |
+
you may not use this file except in compliance with the License.
|
| 182 |
+
You may obtain a copy of the License at
|
| 183 |
+
|
| 184 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 185 |
+
|
| 186 |
+
Unless required by applicable law or agreed to in writing, software
|
| 187 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 188 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 189 |
+
See the License for the specific language governing permissions and
|
| 190 |
+
limitations under the License.
|
README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
base_model: Qwen/Qwen2.5-7B
|
| 4 |
+
tags:
|
| 5 |
+
- adapter
|
| 6 |
+
- semiotics
|
| 7 |
+
- bifurcation-detection
|
| 8 |
+
- metapragmatics
|
| 9 |
+
- frozen-backbone
|
| 10 |
+
- pytorch
|
| 11 |
+
- custom_code
|
| 12 |
+
language:
|
| 13 |
+
- en
|
| 14 |
+
library_name: pytorch
|
| 15 |
+
pipeline_tag: feature-extraction
|
| 16 |
+
inference: false
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
+
# SRT-Adapter v8a: Peer-Review Release
|
| 20 |
+
|
| 21 |
+
A peer-review distribution of the **Semiotic-Reflexive Transformer Adapter (SRT-Adapter)**, v8a generation, trained on top of a frozen `Qwen/Qwen2.5-7B`. Includes the trained weights, an inference-only loader, evaluation data, benchmark artifacts, and the paper.
|
| 22 |
+
|
| 23 |
+
> **Custom-code model.** This is not an `AutoModel`-loadable checkpoint. `AutoModel.from_pretrained(...)` will not work. Clone or download this repository and load the weights through the bundled `SRTAdapter` class. See [How to get started with the model](#how-to-get-started-with-the-model).
|
| 24 |
+
|
| 25 |
+
> **Training and research source code is held back during patent and publication review.** This package ships the architecture as **inference-only Python**, sufficient to load the weights and read out all four semiotic channels. Training pipelines, loss code, dataset construction, and the wider SRT framework are not included.
|
| 26 |
+
|
| 27 |
+
---
|
| 28 |
+
|
| 29 |
+
## Model details
|
| 30 |
+
|
| 31 |
+
| | |
|
| 32 |
+
|---|---|
|
| 33 |
+
| **Developed by** | James Burton Lancaster |
|
| 34 |
+
| **Model type** | Adapter (parameter-efficient side network) on a frozen causal language model |
|
| 35 |
+
| **Backbone** | `Qwen/Qwen2.5-7B` (7.6B params, frozen, bf16) |
|
| 36 |
+
| **Trainable parameters** | ~14.5M (0.19% of backbone) |
|
| 37 |
+
| **Language** | English |
|
| 38 |
+
| **License** | Apache-2.0 (adapter weights, code, and config) |
|
| 39 |
+
|
| 40 |
+
The SRT-Adapter bolts **semiotic awareness** onto a frozen 7B language model. It does not modify a single backbone parameter and does not degrade language modeling quality. It exposes four new readouts at every token position:
|
| 41 |
+
|
| 42 |
+
- a continuous 64-D **community vector** (which discourse community is speaking)
|
| 43 |
+
- per-layer **divergence vectors** (where meaning forks across communities)
|
| 44 |
+
- a continuous **reflexivity estimate** $\hat{r}$ (how contested is this token)
|
| 45 |
+
- a binary **regime classification** (subcritical / supercritical)
|
| 46 |
+
|
| 47 |
+
The v8a generation is the headline result of the paper: removing the discrete prototype basis used in v3–v7 leaves cross-entropy unchanged while substantially improving every encoder-geometry metric.
|
| 48 |
+
|
| 49 |
+
---
|
| 50 |
+
|
| 51 |
+
## Evaluation
|
| 52 |
+
|
| 53 |
+
All measured on `Qwen/Qwen2.5-7B`, with no backbone parameters touched.
|
| 54 |
+
|
| 55 |
+
| Metric | Unadapted Qwen | SRT-Adapter v8a |
|
| 56 |
+
|---|---|---|
|
| 57 |
+
| Validation cross-entropy (nats) | 2.71 | **2.63** |
|
| 58 |
+
| Reddit community recall@1 (35-class) | 0.029 (chance) | **0.484** (16.7× chance) |
|
| 59 |
+
| Archetype recall@1 (33-class, OOD) | 0.030 (chance) | **0.230** (7.6× chance) |
|
| 60 |
+
| Within/between cosine ratio | n/a | **2.016** (vs 1.006 prior) |
|
| 61 |
+
| Trajectory anisotropy expansion | n/a | **~325×** vs prototype baseline |
|
| 62 |
+
| Regime AUROC | n/a | **0.99** (ECE ≈ 0.001 on 351K tokens) |
|
| 63 |
+
| TruthfulQA hallucination AUROC (zero-shot) | n/a | **0.573** (no TruthfulQA in training) |
|
| 64 |
+
| Counterfactual community decoding | n/a | 0.00 disagreement (factual) / **0.95** (contested) |
|
| 65 |
+
|
| 66 |
+
Full reporting and version history (v3 → v8b): paper §5 and Appendix A.
|
| 67 |
+
|
| 68 |
+
---
|
| 69 |
+
|
| 70 |
+
## Lineage and validation history
|
| 71 |
+
|
| 72 |
+
This adapter is the production-scaling stage of a multi-year research program on computational semiotics. The architectural commitments and training objectives were validated in two prior stages on different backbones and datasets before this release. Treat the v8a numbers below as the latest checkpoint in a longer arc, not as a fresh proposal.
|
| 73 |
+
|
| 74 |
+
- **Stage 1 (synthetic validation, 2026-03).** Four core architectural claims (subspace specialization, community differentiation, divergence tracking, bifurcation detection) were tested on synthetic data with planted divergence signals. All four passed: linear-probe margin $\geq 0.15$ on each Peircean subspace, $3.28\times$ contested-vs-neutral cosine ratio, Spearman $\rho = 0.822$ on divergence tracking, 100% regime classification with $\Delta \hat{r} = 0.659$. Full record: [`VALIDATION_HISTORY.md`](VALIDATION_HISTORY.md), Stage 1.
|
| 75 |
+
- **Stage 2 (natural-language validation, 2026-03).** The full five-test suite was re-run on the Supabase semiotic news corpus (19K articles, 5 political communities, 141K Peircean sign annotations). All five tests passed at required thresholds: silhouette $1.45\times$, $2.29\times$ contested-vs-neutral divergence norm ratio, Pearson $r = 0.884$ correlation between $\hat{r}$ and external polarization, $1.31\times$ cross-topic transfer ratio, and 85% regime classification accuracy on held-out curated passages. Full record: [`VALIDATION_HISTORY.md`](VALIDATION_HISTORY.md), Stage 2.
|
| 76 |
+
- **Stage 3 Phase 1 (frozen-backbone integration on TinyLlama-1.1B, 2026-03 to 2026-04).** 105 training rounds (R21 through R105) on a frozen TinyLlama-1.1B backbone established that the semiotic modules transfer to production backbones. Community detection silhouette improved to $6.93\times$; $\hat{r}$ correlation with external polarization remained robust at 0.66; curated-passage regime classification reached 85%. Two tests plateaued on the sparse 2-community Supabase data (MAH divergence ratio at $1.05$ to $1.10\times$ vs. required $2.0\times$; cross-topic transfer at $1.03$ to $1.04\times$ vs. required $1.3\times$). The plateau triggered a data-first pivot to a denser corpus and a backbone capable of supporting it.
|
| 77 |
+
- **Stage 3 Scalable Implementation (this release, 2026-04).** v5 through v8a port the validated architecture onto Qwen 2.5-7B and the Reddit Discourse Corpus (35 communities, 1M training samples). v8a is the current best checkpoint. The headline gain is not the discovery of bifurcation detection (already established in Stages 1 and 2) but the demonstration that the framework scales to a 7B frozen backbone at 0.19% parameter overhead, with $\sim 325\times$ trajectory-anisotropy expansion and Reddit recall@1 at $16.7\times$ chance.
|
| 78 |
+
|
| 79 |
+
For the program-level theoretical foundation see Lancaster (2025), "The Treachery of Signs," SSRN [5987495](https://papers.ssrn.com/abstract=5987495). For the full prior architecture specification and Stage 1 + Stage 2 results see Lancaster (2026a), SSRN [6349978](https://papers.ssrn.com/abstract=6349978). The present paper reports Stage 3 Phase 1 plus the v5 through v8a Stage 3 Scalable progression.
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## Versions and roadmap
|
| 84 |
+
|
| 85 |
+
- **v8a (this release).** Headline result. Removing the discrete prototype basis used in v3 through v7 leaves cross-entropy unchanged while substantially improving every encoder-geometry metric. All paper §5 numbers are measured on this checkpoint.
|
| 86 |
+
- **v8b.** A falsification run included in the paper. Pushing the supervised-contrastive objective harder partially undoes v8a's gains. Documented as a negative result.
|
| 87 |
+
- **v9 (in training).** An experimental generation that adds a target-norm penalty on the inject-back arm to attack the central open problem from §6.3 (the inject-back arm carries no measurable signal). Will be released as a follow-up revision on this repo *only if* it improves on v8a across multiple metrics. Otherwise it will be documented as an additional ablation in a future paper revision and v8a will remain canonical.
|
| 88 |
+
|
| 89 |
+
If you are reviewing the paper, use v8a. The model card will be updated with a `revision` tag if v9 ships as an upgrade.
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## Package contents
|
| 94 |
+
|
| 95 |
+
```
|
| 96 |
+
srt-adapter-v8a/
|
| 97 |
+
├── README.md ← you are here
|
| 98 |
+
├── LICENSE ← Apache-2.0
|
| 99 |
+
├── paper.pdf ← preprint with full architecture spec (§3 + Appendix A)
|
| 100 |
+
├── VALIDATION_HISTORY.md ← Stage 1 + Stage 2 + Stage 3 Phase 1 evidence summary
|
| 101 |
+
├── config.json ← v8a hyperparameters and module dimensions
|
| 102 |
+
├── adapter.safetensors ← v8a weights (~28 MB, safetensors, preferred)
|
| 103 |
+
├── adapter.pt ← v8a weights (~28 MB, PyTorch state-dict, legacy)
|
| 104 |
+
├── requirements.txt ← torch + transformers + numpy + safetensors
|
| 105 |
+
├── src/
|
| 106 |
+
│ └── srt/ ← inference-only model code
|
| 107 |
+
│ ├── config.py ← config dataclasses
|
| 108 |
+
│ ├── adapter.py ← SRTAdapter (frozen-backbone wrapper)
|
| 109 |
+
│ └── modules/ ← CDH, MAH, RRM, BEN
|
| 110 |
+
├── examples/
|
| 111 |
+
│ ├── README.md
|
| 112 |
+
│ └── load_and_score.py ← end-to-end demo, prints all 4 readouts
|
| 113 |
+
├── data/
|
| 114 |
+
│ ├── DATA.md ← schema + reproduction instructions for the full corpus
|
| 115 |
+
│ ├── NOTICE ← copyright notice for bundled Reddit comments
|
| 116 |
+
│ ├── val_200.jsonl ← 200 held-out samples with per-token r_true labels
|
| 117 |
+
│ └── archetypes.json ← 33-class out-of-distribution archetype probe
|
| 118 |
+
└── benchmarks/
|
| 119 |
+
├── curated_metrics.json ← reference metrics from paper §5
|
| 120 |
+
└── curated_traces.json ← per-token trace dumps used in plots
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
> **Note on `benchmarks/curated_metrics.json`.** This file reports v8a numbers on a 100-passage curated probe (regime accuracy, per-layer divergence norms, community-protocol activations). The near-zero $\hat{r}$ vs $r_{\text{true}}$ Pearson on this slice is expected and is discussed in paper §5.7 ($\hat{r}$ tracks information density as much as contestedness on short curated passages). The headline Pearson and recall numbers in the Evaluation table above come from the full Reddit validation split, not this curated probe.
|
| 124 |
+
|
| 125 |
+
### What's NOT in this package
|
| 126 |
+
|
| 127 |
+
- **Training pipelines, loss functions, and the dataset construction code.** Held back during patent and publication review.
|
| 128 |
+
- **The wider SRT research framework** (annotation pipeline, ablation harness, sweep tooling, instrumentation scripts).
|
| 129 |
+
- **The full 1M-sample training corpus.** Reddit's redistribution terms preclude bundling it; see [`data/DATA.md`](data/DATA.md) for schema and reproduction.
|
| 130 |
+
- **The Qwen 2.5-7B backbone weights.** Pulled from HuggingFace under the [Tongyi Qianwen License](https://huggingface.co/Qwen/Qwen2.5-7B/blob/main/LICENSE).
|
| 131 |
+
|
| 132 |
+
---
|
| 133 |
+
|
| 134 |
+
## How to get started with the model
|
| 135 |
+
|
| 136 |
+
```bash
|
| 137 |
+
# 1. set up a venv (Python ≥ 3.10) and install deps
|
| 138 |
+
pip install -r requirements.txt
|
| 139 |
+
|
| 140 |
+
# 2. score a passage end-to-end
|
| 141 |
+
cd examples
|
| 142 |
+
python load_and_score.py --text "Vaccine mandates are an obvious public health win."
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
First run downloads `Qwen/Qwen2.5-7B` (~15 GB) from HuggingFace. The example loads `adapter.safetensors` by default and falls back to `adapter.pt` if the safetensors file is absent.
|
| 146 |
+
|
| 147 |
+
For a programmatic-use snippet, see [`examples/README.md`](examples/README.md).
|
| 148 |
+
|
| 149 |
+
---
|
| 150 |
+
|
| 151 |
+
## Uses
|
| 152 |
+
|
| 153 |
+
The adapter is most useful as a **diagnostic instrument** for what a frozen language model already encodes about discourse structure. Some concrete patterns:
|
| 154 |
+
|
| 155 |
+
### 1. Per-token contestedness scoring
|
| 156 |
+
|
| 157 |
+
Use BEN's regime logits to flag which token positions in a passage sit in a contested-meaning regime. Useful for:
|
| 158 |
+
|
| 159 |
+
- highlighting ideologically loaded spans in user-generated text
|
| 160 |
+
- routing inputs to human review when supercritical regime probability exceeds a threshold
|
| 161 |
+
- annotating debate transcripts, news comment threads, or policy documents with per-token tension scores
|
| 162 |
+
|
| 163 |
+
### 2. Unsupervised discourse-community clustering
|
| 164 |
+
|
| 165 |
+
The 64-D community vector from CDH supports nearest-neighbor retrieval and clustering without ever needing community labels at inference. Useful for:
|
| 166 |
+
|
| 167 |
+
- segmenting a corpus by latent discourse community (recall@1 = 16.7× chance on 35 known communities)
|
| 168 |
+
- retrieving thematically aligned passages for downstream modeling
|
| 169 |
+
- detecting coordinated-inauthentic-behavior signatures via tight community clustering of supposedly independent accounts
|
| 170 |
+
|
| 171 |
+
### 3. Counterfactual community-conditioned decoding
|
| 172 |
+
|
| 173 |
+
By steering the community vector at decode time, you can ask "how would *this* community complete this sentence?" Useful for:
|
| 174 |
+
|
| 175 |
+
- cross-community simulation studies (the paper measures 0.95 mean disagreement on contested prompts vs 0.00 on factual ones)
|
| 176 |
+
- synthetic-disagreement generation for training argument-mining or stance-detection systems
|
| 177 |
+
- audit / red-team probes that surface latent assumptions across reader communities
|
| 178 |
+
|
| 179 |
+
### 4. Hallucination signal for retrieval and generation
|
| 180 |
+
|
| 181 |
+
$\hat{r}$ correlates with epistemic instability and gives a usable zero-shot AUROC of 0.573 on TruthfulQA. Useful as:
|
| 182 |
+
|
| 183 |
+
- a feature in hallucination classifiers (alongside other signals)
|
| 184 |
+
- a per-token routing signal for retrieval-augmented generation: high $\hat{r}$ tokens warrant a retrieval round
|
| 185 |
+
- a calibration probe in evaluation pipelines
|
| 186 |
+
|
| 187 |
+
### 5. Feature extraction for downstream classifiers
|
| 188 |
+
|
| 189 |
+
The MAH divergence vectors (3 × 256-D per token) are usable as semiotic features in any downstream classifier without retraining the backbone or the adapter. Useful for:
|
| 190 |
+
|
| 191 |
+
- stance and frame classification on small labeled sets
|
| 192 |
+
- author / community attribution
|
| 193 |
+
- topical drift detection across long documents
|
| 194 |
+
|
| 195 |
+
### 6. Reviewer probes against the paper's claims
|
| 196 |
+
|
| 197 |
+
`data/val_200.jsonl` ships with per-token `r_true` labels. Reviewers can validate claims about $\hat{r}$ correlation, regime accuracy, and divergence norms against the bundled `benchmarks/curated_metrics.json` without rerunning training.
|
| 198 |
+
|
| 199 |
+
### Out-of-scope uses
|
| 200 |
+
|
| 201 |
+
- **Treating $\hat{r}$ as a calibrated truth score.** It correlates with information density as much as contestedness; see paper §5.7.
|
| 202 |
+
- **Expecting the inject-back arm to noticeably change generation.** The observation half is well-formed; the intervention half does not yet carry signal. See paper §6.3 and §6.5.
|
| 203 |
+
- **Safety-critical decisions without independent validation.** The adapter is a research instrument, not a deployed safety system.
|
| 204 |
+
- **Generation models.** The adapter does not improve text generation quality; it adds structured side-channel readouts.
|
| 205 |
+
|
| 206 |
+
---
|
| 207 |
+
|
| 208 |
+
## Training details
|
| 209 |
+
|
| 210 |
+
### Training data
|
| 211 |
+
|
| 212 |
+
- **Corpus:** ~1M Reddit comments × 35 discourse communities, with per-token reflexivity labels and chain-of-interpretants annotations.
|
| 213 |
+
- The full corpus is **not redistributed**; see [`data/DATA.md`](data/DATA.md) for schema and reproduction.
|
| 214 |
+
- A 200-sample held-out evaluation subset is bundled in [`data/val_200.jsonl`](data/val_200.jsonl) under the terms in [`data/NOTICE`](data/NOTICE).
|
| 215 |
+
|
| 216 |
+
### Training procedure
|
| 217 |
+
|
| 218 |
+
- Optimizer: AdamW, learning rate 3e-4, batch 16, max sequence length 512.
|
| 219 |
+
- Schedule: 3 epochs over 1M samples, early-stopped at ~10K steps based on validation cross-entropy.
|
| 220 |
+
- Backbone: frozen, bf16. No backbone parameter is updated.
|
| 221 |
+
- Hardware: single NVIDIA A6000 (48 GB).
|
| 222 |
+
|
| 223 |
+
---
|
| 224 |
+
|
| 225 |
+
## Architecture summary
|
| 226 |
+
|
| 227 |
+
| Module | Reads | Outputs | Paper section |
|
| 228 |
+
|---|---|---|---|
|
| 229 |
+
| **Community Discovery Head** (CDH) | layer 4 hidden states, mean-pooled | continuous 64-D community vector (no prototype basis under v8a) | §3.2 |
|
| 230 |
+
| **Metapragmatic Attention Heads** (MAH) | layers 7, 14, 21 | per-token divergence vectors (256-D × 3 layers) | §3.3 |
|
| 231 |
+
| **Reflexive Recurrent Module** (RRM) | accumulated divergence | 512-D GRU meta-state; FiLM injections back into layers 14, 21 | §3.4 |
|
| 232 |
+
| **Bifurcation Estimation Network** (BEN) | meta-state | per-token $\hat{r}$ + 2-way regime logits | §3.5 |
|
| 233 |
+
|
| 234 |
+
Full module specifications and loss decomposition: paper §3, §4, and Appendix A.
|
| 235 |
+
|
| 236 |
+
---
|
| 237 |
+
|
| 238 |
+
## Bias, risks, and limitations
|
| 239 |
+
|
| 240 |
+
The paper publishes its failures in full. In short:
|
| 241 |
+
|
| 242 |
+
1. **The inject-back arm currently carries no measurable signal.** Ablating it changes nothing on validation. Central open problem; v9 targets this.
|
| 243 |
+
2. **$\hat{r}$ tracks information density as much as contestedness.** Useful signal, not a clean reading of "is this token contested."
|
| 244 |
+
3. **The 33 archetypes collapse to ~4 functional clusters.** Read as a finding (the geometry resists fine-grained quantization), not a classification bug.
|
| 245 |
+
4. **v8b is a falsification.** Pushing the supervised-contrastive objective harder partially undoes v8a's gains.
|
| 246 |
+
5. **Backbone dependence.** Only validated on Qwen 2.5-7B. Module dimensions are tied to the backbone's hidden size (3584).
|
| 247 |
+
6. **Training corpus bias.** Reddit comments skew English, US-centric, and over-represent argumentative and politically charged communities. The community vector geometry inherits those biases. Treat community recall and counterfactual-decoding numbers as descriptive, not normative.
|
| 248 |
+
|
| 249 |
+
---
|
| 250 |
+
|
| 251 |
+
## Citation
|
| 252 |
+
|
| 253 |
+
```bibtex
|
| 254 |
+
@article{lancaster2026srtadapter,
|
| 255 |
+
title = {Semiotic Taps: Lightweight Adapter Modules for Bifurcation
|
| 256 |
+
Detection in Frozen Language Models},
|
| 257 |
+
author = {Lancaster, James Burton},
|
| 258 |
+
year = {2026},
|
| 259 |
+
note = {Preprint, peer-review distribution}
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
@article{lancaster2026srtpreprint,
|
| 263 |
+
title = {Semiotic-Reflexive Language Model Training: Bridging
|
| 264 |
+
Interpretive Bifurcations through Metapragmatic Chain
|
| 265 |
+
Architectures and Embodied Grounding},
|
| 266 |
+
author = {Lancaster, James Burton},
|
| 267 |
+
year = {2026},
|
| 268 |
+
journal = {SSRN},
|
| 269 |
+
url = {https://papers.ssrn.com/abstract=6349978}
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
@article{lancaster2025treachery,
|
| 273 |
+
title = {The Treachery of Signs: Semiotic Mediation, Pitchfork
|
| 274 |
+
Bifurcation, and Political Polarization in Algorithmically
|
| 275 |
+
Curated Societies},
|
| 276 |
+
author = {Lancaster, James Burton},
|
| 277 |
+
year = {2025},
|
| 278 |
+
journal = {SSRN},
|
| 279 |
+
url = {https://papers.ssrn.com/abstract=5987495}
|
| 280 |
+
}
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
Full reference list (Peirce, Wildgen, Anderson, Silverstein, Kockelman, Evans, von Foerster, Maturana & Varela, Leighton, VanSaders, Bennett, Landauer, Parrondo, and others) in [`paper.pdf`](paper.pdf).
|
| 284 |
+
|
| 285 |
+
---
|
| 286 |
+
|
| 287 |
+
## License
|
| 288 |
+
|
| 289 |
+
- **Adapter weights, inference code, config, benchmark artifacts, archetype data, and this package:** Apache-2.0 ([`LICENSE`](LICENSE)).
|
| 290 |
+
- **Validation samples in `data/val_200.jsonl`:** included for research reproduction; comments remain the intellectual property of their original Reddit authors. See [`data/NOTICE`](data/NOTICE).
|
| 291 |
+
- **Training pipelines, dataset construction, and the wider SRT framework:** held back during patent and publication review. Not included.
|
| 292 |
+
- **Qwen 2.5-7B backbone:** governed separately by the [Tongyi Qianwen License](https://huggingface.co/Qwen/Qwen2.5-7B/blob/main/LICENSE).
|
| 293 |
+
|
| 294 |
+
---
|
| 295 |
+
|
| 296 |
+
## Contact
|
| 297 |
+
|
| 298 |
+
For training-code access, reproduction questions, or follow-up: see paper PDF for current author contact details.
|
SHA256SUMS
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
80337123382f5786be2f87326388ba6cee2ebb7be1afc2c012df7e68aa753e8b ./.gitattributes
|
| 2 |
+
161a873e893d3af606c92866401b329204b127585008ec1894ff9a0f618d86f2 ./LICENSE
|
| 3 |
+
e1638fc045b16eea6074670198ee7d05c07b7bb53ecc59926c5758ec22ed28a4 ./README.md
|
| 4 |
+
777c77fe0d4bdc0361fa907b313233eea513f20bb87b69135e128d5a2e9a3f5b ./SHA256SUMS
|
| 5 |
+
025681e1f01fb754ae7f1ddbe87246dadd2b55d2ff62039ba73051428f12e5d5 ./VALIDATION_HISTORY.md
|
| 6 |
+
5d201ed58c770d6c8f0fb894e4931fe5923efba455ac4994c7a97f01d13aa05c ./adapter.pt
|
| 7 |
+
635d4dc76c3c21743ce92988aa107d9fe36ed0b2db53a7eb73b258608741204e ./adapter.safetensors
|
| 8 |
+
855a5f1a9f5478811d6a8deeb276d4eae4e0211d28041d053bbea3a50afa3c7e ./benchmarks/curated_metrics.json
|
| 9 |
+
500d9c7b9c9deb0a76482a80dd7d6a8c8b1e648a75f6d5a6732c384baa543d54 ./benchmarks/curated_traces.json
|
| 10 |
+
a83afa4f3524ce4c81f359e197c1ed30bca2753e09b7deea82145b36fc103cc6 ./config.json
|
| 11 |
+
c83c36c374202585c14dc437a2e8ad5b21dbbfbecc7ebd68a80fc3c1494e3d72 ./data/DATA.md
|
| 12 |
+
7d12f72f5cf6e4a451d4dca06c82b5d37c0456e4d577cb63af7ef6c35efadda2 ./data/NOTICE
|
| 13 |
+
e4c8cc4b329bf0b6d9b2070dc386c04b730232fa8c6b310a818ec09d38b1b2e1 ./data/archetypes.json
|
| 14 |
+
e2772cba759bd8fa1a7a5c83f2913141bcd3c88ebdbcfc1069dad5d81366df23 ./data/val_200.jsonl
|
| 15 |
+
6edfa5b72f1b3e799ed37eb881d620f92217423f3262b9c19ff4d356e8047b13 ./examples/README.md
|
| 16 |
+
9a8ea6f13b1cf905a07c3f9707233a5cec7d4c13a6c2ccb3f3dd12c071371653 ./examples/load_and_score.py
|
| 17 |
+
58dac62a9ac6b0cc4ae35bf3d8297f75a43b7ab1f1e55be8c71c9ff76474cf87 ./paper.pdf
|
| 18 |
+
0ad957410e78eaaeb6b0369e52bf14aa5026bb02aaa4546a09b35d0e52a71c8d ./requirements.txt
|
| 19 |
+
133e1537baa6e11a0df942755498da8b1d48a3aab736db0b8206fc2db6393454 ./src/srt/__init__.py
|
| 20 |
+
b77e7e1320ac02590234953ff0c8a893b645208b43fa1d2c4942da5eeba96a8b ./src/srt/adapter.py
|
| 21 |
+
64007a7c8f9a77ea3e91d543a15fd13b7f05e3c781f405e30e2eaa018fd3ec4e ./src/srt/config.py
|
| 22 |
+
8e2291d2b5e05282994fbac8ab4a9462054ff864a741e4d35a15bcc3961bae54 ./src/srt/modules/__init__.py
|
| 23 |
+
94d88e7e10222dcb103d7d8baad41a68a23e596f458b24bfc9ed5215500891ce ./src/srt/modules/ben.py
|
| 24 |
+
e686f499b0776e0354df5d8de0698d081ee194c580ac7d162b58f20136be8d08 ./src/srt/modules/community.py
|
| 25 |
+
50075c7850603d459f876f14135d24cf3bf491adf5553d4cf918416ac3c245c2 ./src/srt/modules/mah.py
|
| 26 |
+
c4e74600fd8a78f77f691db13b71ab751fd52d2fae4ecb7bdf4c1e6e95cb8f39 ./src/srt/modules/rrm.py
|
VALIDATION_HISTORY.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Validation history of the SRT program
|
| 2 |
+
|
| 3 |
+
This document distills the validation evidence behind the SRT adapter (v8a)
|
| 4 |
+
into a single self-contained record. It covers the three validation stages
|
| 5 |
+
that established the architectural claims this adapter inherits:
|
| 6 |
+
|
| 7 |
+
- **Stage 1**. Synthetic controlled experiments (4/4 tests passed).
|
| 8 |
+
- **Stage 2**. Natural-language validation on a real news corpus (5/5
|
| 9 |
+
tests passed).
|
| 10 |
+
- **Stage 3 Phase 1**. Hybrid model on a frozen pretrained backbone
|
| 11 |
+
(4/5 tests passed at the first gate evaluation; the regime-classification
|
| 12 |
+
test motivated the remediation campaign that produced the lightweight
|
| 13 |
+
adapter program reported in `paper.pdf`).
|
| 14 |
+
|
| 15 |
+
For the canonical theoretical record, see Lancaster (2025), "The Treachery
|
| 16 |
+
of Signs," SSRN [5987495](https://papers.ssrn.com/abstract=5987495), and
|
| 17 |
+
Lancaster (2026a), "Semiotic-Reflexive Language Model Training," SSRN
|
| 18 |
+
[6349978](https://papers.ssrn.com/abstract=6349978). The numbers below
|
| 19 |
+
appear in those papers in their full original context; this file is the
|
| 20 |
+
concise summary referenced from the model card.
|
| 21 |
+
|
| 22 |
+
---
|
| 23 |
+
|
| 24 |
+
## Stage 1: Synthetic controlled experiments
|
| 25 |
+
|
| 26 |
+
**Gate G1: PASSED (4/4).** Each test isolates one architectural claim on
|
| 27 |
+
synthetic data with planted ground-truth signals.
|
| 28 |
+
|
| 29 |
+
### 1.1 Subspace specialization (linear probing)
|
| 30 |
+
|
| 31 |
+
| Task | Target subspace | Target acc | Control acc | Margin | Threshold |
|
| 32 |
+
|---|---|---|---|---|---|
|
| 33 |
+
| Token identity | Representamen | 99.31% | 1.31% | 0.980 | $\geq 0.15$ |
|
| 34 |
+
| Community membership | Interpretant | 100.00% | 64.42% | 0.356 | $\geq 0.15$ |
|
| 35 |
+
| Attractor basin | Attractor | 100.00% | 84.52% | 0.155 | $\geq 0.15$ |
|
| 36 |
+
| Position in sequence | Object | 43.22% | 12.99% | 0.302 | $\geq 0.15$ |
|
| 37 |
+
|
| 38 |
+
The four Peircean subspaces encode qualitatively different information.
|
| 39 |
+
|
| 40 |
+
### 1.2 Community differentiation
|
| 41 |
+
|
| 42 |
+
| Metric | Value |
|
| 43 |
+
|---|---|
|
| 44 |
+
| Mean cosine distance, contested signs (20 words) | 0.3622 |
|
| 45 |
+
| Mean cosine distance, neutral signs (79 words) | 0.1103 |
|
| 46 |
+
| Ratio | $3.28\times$ (threshold $\geq 3.0\times$) |
|
| 47 |
+
|
| 48 |
+
### 1.3 Divergence tracking
|
| 49 |
+
|
| 50 |
+
| Metric | Value |
|
| 51 |
+
|---|---|
|
| 52 |
+
| Spearman $\rho$ between $\hat{r}$ and $r_{\text{true}}$ | 0.8220 ($p \approx 0$) |
|
| 53 |
+
| Samples | 64,000 |
|
| 54 |
+
| Threshold | $\rho \geq 0.6$ |
|
| 55 |
+
|
| 56 |
+
### 1.4 Bifurcation detection
|
| 57 |
+
|
| 58 |
+
| Metric | Value |
|
| 59 |
+
|---|---|
|
| 60 |
+
| Mean $\hat{r}$ difference, post minus pre | 0.6588 (threshold $> 0.2$) |
|
| 61 |
+
| Regime classification accuracy | 100.00% (threshold $> 75$%) |
|
| 62 |
+
| Samples | 500 |
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
## Stage 2: Natural-language validation
|
| 67 |
+
|
| 68 |
+
**Gate G2: PASSED (5/5).** The full architecture re-tested on a curated
|
| 69 |
+
news corpus (5 communities, 19K articles, 141K Peircean sign annotations,
|
| 70 |
+
contested terms including *freedom*, *justice*, *patriot*).
|
| 71 |
+
|
| 72 |
+
### 2.1 Community embedding structure
|
| 73 |
+
|
| 74 |
+
| Metric | Value |
|
| 75 |
+
|---|---|
|
| 76 |
+
| Contested silhouette | 0.5293 (threshold $> 0.15$) |
|
| 77 |
+
| Neutral silhouette | 0.3653 |
|
| 78 |
+
| Silhouette ratio (contested over neutral) | $1.45\times$ (threshold $> 1.3\times$) |
|
| 79 |
+
| Samples | 5,000 contested + 5,000 neutral |
|
| 80 |
+
| Communities | 5 |
|
| 81 |
+
|
| 82 |
+
### 2.2 Divergence vectors on contested terms
|
| 83 |
+
|
| 84 |
+
| Metric | Value |
|
| 85 |
+
|---|---|
|
| 86 |
+
| Group A (divergent connections) mean | 15.3730 |
|
| 87 |
+
| Group B (referential only) mean | 6.7001 |
|
| 88 |
+
| Ratio | $2.29\times$ (threshold $\geq 2.0\times$) |
|
| 89 |
+
| Cohen's $d$ | 0.378 |
|
| 90 |
+
| Tokens | 81,839 vs 5,047 |
|
| 91 |
+
|
| 92 |
+
### 2.3 $\hat{r}$ vs external polarization
|
| 93 |
+
|
| 94 |
+
| Metric | Value |
|
| 95 |
+
|---|---|
|
| 96 |
+
| Pearson $r$ | 0.8843 ($p \approx 0$) |
|
| 97 |
+
| Threshold | $r \geq 0.3$ |
|
| 98 |
+
| Samples | 2,120 |
|
| 99 |
+
| Mean $\hat{r}$ | 0.3257 |
|
| 100 |
+
| Mean external divergence | 0.3759 |
|
| 101 |
+
|
| 102 |
+
### 2.4 Cross-topic transfer (zero-shot)
|
| 103 |
+
|
| 104 |
+
| Metric | Value |
|
| 105 |
+
|---|---|
|
| 106 |
+
| Held-out contested mean divergence | 19.1582 (45,601 tokens) |
|
| 107 |
+
| Held-out neutral mean divergence | 14.6394 (1,265 tokens) |
|
| 108 |
+
| Ratio | $1.31\times$ (threshold $> 1.3\times$) |
|
| 109 |
+
|
| 110 |
+
### 2.5 Regime classification on curated passages
|
| 111 |
+
|
| 112 |
+
| Metric | Value |
|
| 113 |
+
|---|---|
|
| 114 |
+
| Accuracy | 85.00% (threshold $\geq 70$%) |
|
| 115 |
+
| ROC AUC | 0.8988 |
|
| 116 |
+
| Mean $\hat{r}$ low-divergence (50 passages) | 0.2845 ± 0.0619 |
|
| 117 |
+
| Mean $\hat{r}$ high-divergence (50 passages) | 0.4439 ± 0.0931 |
|
| 118 |
+
| Cohen's $d$ | 2.016 |
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
## Stage 3 Phase 1: Hybrid model on a frozen backbone
|
| 123 |
+
|
| 124 |
+
**Gate G3a: 3/5 at end of campaign (R21 through R105).** The full Stage-2
|
| 125 |
+
architecture was grafted onto a frozen TinyLlama-1.1B backbone. The first
|
| 126 |
+
gate evaluation (R21) inverted Stage 2's failure pattern: four geometric
|
| 127 |
+
tests passed but the regime-classification head collapsed to a
|
| 128 |
+
supercritical bias (47% accuracy, well below the 70% threshold). A
|
| 129 |
+
105-round remediation campaign followed (R21 through R105), spanning
|
| 130 |
+
gradient isolation of the bifurcation-estimation network, BEN-input
|
| 131 |
+
detachment, dual-checkpoint tracking, calign and dmag re-weighting, and
|
| 132 |
+
fresh-start retraining with all fixes applied from step 0.
|
| 133 |
+
|
| 134 |
+
By R105 the regime-classification failure was resolved (85.00%) and the
|
| 135 |
+
community-embedding silhouette ratio improved by roughly 3x over R21.
|
| 136 |
+
However, two tests that had passed at R21 plateaued during the
|
| 137 |
+
remediation campaign and never recovered to threshold on the
|
| 138 |
+
2-community Supabase corpus.
|
| 139 |
+
|
| 140 |
+
### Initial gate (R21) versus end of campaign (R105)
|
| 141 |
+
|
| 142 |
+
| Test | Stage 2 | R21 baseline | R105 final | Threshold | R105 status |
|
| 143 |
+
|---|---|---|---|---|---|
|
| 144 |
+
| Community embedding (silhouette ratio) | $1.45\times$ | $2.18\times$ | $\sim 6.93\times$ | $> 1.3\times$ | **PASS** |
|
| 145 |
+
| Divergence ratio (contested over neutral) | $2.29\times$ | $5.91\times$ | $\sim 1.05$ to $1.10\times$ | $\geq 2.0\times$ | **FAIL** (plateau) |
|
| 146 |
+
| $\hat{r}$ vs external polarization (Pearson) | 0.88 | 0.65 | $\sim 0.66$ | $\geq 0.3$ | **PASS** |
|
| 147 |
+
| Cross-topic transfer (held-out ratio) | $1.31\times$ | $6.10\times$ | $\sim 1.03$ to $1.04\times$ | $> 1.3\times$ | **FAIL** (plateau) |
|
| 148 |
+
| Regime classification accuracy | 85.00% | 47.00% | 85.00% | $\geq 70$% | **PASS** |
|
| 149 |
+
|
| 150 |
+
### Diagnosis and pivot
|
| 151 |
+
|
| 152 |
+
The diagnosis was that the 2-community Supabase corpus was too sparse to
|
| 153 |
+
support discriminative divergence-vector training at the scale needed
|
| 154 |
+
for a frozen-backbone integration. The two plateaued tests measure
|
| 155 |
+
contested-over-neutral norm ratios on the MAH divergence vectors; once
|
| 156 |
+
the supervised-contrastive objective reached its data ceiling, no
|
| 157 |
+
further architectural change moved them.
|
| 158 |
+
|
| 159 |
+
That diagnosis triggered the data-first pivot to a denser corpus (the
|
| 160 |
+
35-community Reddit Discourse Corpus, ~1M training samples) and a
|
| 161 |
+
larger frozen backbone (Qwen 2.5-7B). The Stage 3 Scalable line that
|
| 162 |
+
followed (v3 through v8a) is the production form of that pivot. The
|
| 163 |
+
adapter released in this package (v8a) inherits the validated geometry
|
| 164 |
+
(community embedding, polarization estimation, regime classification)
|
| 165 |
+
and re-establishes the divergence-norm contrast on the denser corpus
|
| 166 |
+
through a gradient-isolated adapter rather than a from-scratch hybrid
|
| 167 |
+
model. The inject-back arm of v8a remains under-developed and is the
|
| 168 |
+
central open problem identified in §5.1 and §6.3 of `paper.pdf`.
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## Cross-stage capability summary
|
| 173 |
+
|
| 174 |
+
| Capability | Stage 1 | Stage 2 | Stage 3 Phase 1 (R105) | Comment |
|
| 175 |
+
|---|---|---|---|---|
|
| 176 |
+
| Subspace specialization | $\checkmark$ | --- | --- | Stage-1-only test |
|
| 177 |
+
| Community embedding | $\checkmark$ ($3.28\times$) | $\checkmark$ ($1.45\times$) | $\checkmark$ ($\sim 6.93\times$) | Improves with backbone + remediation |
|
| 178 |
+
| Divergence tracking | $\checkmark$ ($\rho = 0.82$) | $\checkmark$ ($2.29\times$) | plateau ($\sim 1.05$ to $1.10\times$) | Data-ceiling on Supabase corpus |
|
| 179 |
+
| Polarization estimation | $\checkmark$ ($\rho = 0.82$) | $\checkmark$ ($r = 0.88$) | $\checkmark$ ($r \approx 0.66$) | Modest regression |
|
| 180 |
+
| Bifurcation detection | $\checkmark$ (100%) | $\checkmark$ (85%) | $\checkmark$ (85%, R105) | Recovered through remediation |
|
| 181 |
+
| Cross-topic transfer | --- | $\checkmark$ ($1.31\times$) | plateau ($\sim 1.03$ to $1.04\times$) | Data-ceiling on Supabase corpus |
|
| 182 |
+
|
| 183 |
+
---
|
| 184 |
+
|
| 185 |
+
## Provenance
|
| 186 |
+
|
| 187 |
+
The Stage 1 and Stage 2 numbers were produced by the standalone SRT
|
| 188 |
+
architecture (~21M trainable parameters) on synthetic and curated
|
| 189 |
+
news-corpus data. The Stage 3 Phase 1 numbers were produced by the
|
| 190 |
+
hybrid configuration (frozen TinyLlama-1.1B backbone plus the same
|
| 191 |
+
SRT modules) across 105 training rounds (R21 through R105). The v8a
|
| 192 |
+
adapter released in this package takes the program forward to a frozen
|
| 193 |
+
Qwen 2.5-7B backbone and the 35-community Reddit Discourse Corpus with
|
| 194 |
+
a re-engineered, gradient-isolated adapter (~14.5M trainable),
|
| 195 |
+
preserving the validated capabilities and improving validation
|
| 196 |
+
cross-entropy from 2.71 (no-adapter baseline) to 2.63 (v8a). See the
|
| 197 |
+
v3 through v8a results in §5 of `paper.pdf` and the lineage discussion
|
| 198 |
+
in §1.1.5 and §2.0 of `paper.pdf`.
|
adapter.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5d201ed58c770d6c8f0fb894e4931fe5923efba455ac4994c7a97f01d13aa05c
|
| 3 |
+
size 29134545
|
adapter.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:635d4dc76c3c21743ce92988aa107d9fe36ed0b2db53a7eb73b258608741204e
|
| 3 |
+
size 29124982
|
benchmarks/curated_metrics.json
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"n_samples": 100,
|
| 3 |
+
"n_tokens_masked": 16434,
|
| 4 |
+
"mean_ce": 2.565993104914647,
|
| 5 |
+
"wall_time_sec": 9.431363582611084,
|
| 6 |
+
"pearson_r_hat_vs_r_true_raw": 0.004732293542474508,
|
| 7 |
+
"pearson_r_hat_vs_r_true_compressed": 0.004732287954539061,
|
| 8 |
+
"r_hat_mean": 0.62109375,
|
| 9 |
+
"r_hat_std": 0.361328125,
|
| 10 |
+
"r_hat_min": -0.2373046875,
|
| 11 |
+
"r_hat_max": 1.0,
|
| 12 |
+
"r_hat_saturated_pos": 0.3172082304954529,
|
| 13 |
+
"r_hat_saturated_neg": 0.0,
|
| 14 |
+
"regime_accuracy": 0.7566630244255066,
|
| 15 |
+
"regime_accuracy_subcritical": 0.0802631601691246,
|
| 16 |
+
"regime_accuracy_supercritical": 0.9101836681365967,
|
| 17 |
+
"regime_true_pos_frac": 0.8150176405906677,
|
| 18 |
+
"divergence_norms_per_layer": {
|
| 19 |
+
"0": {
|
| 20 |
+
"mean": 1.1829235553741455,
|
| 21 |
+
"std": 0.982042133808136,
|
| 22 |
+
"min": 0.392578125,
|
| 23 |
+
"max": 18.75,
|
| 24 |
+
"median": 0.9609375
|
| 25 |
+
},
|
| 26 |
+
"1": {
|
| 27 |
+
"mean": 1.0742521286010742,
|
| 28 |
+
"std": 0.745279848575592,
|
| 29 |
+
"min": 0.474609375,
|
| 30 |
+
"max": 15.625,
|
| 31 |
+
"median": 0.953125
|
| 32 |
+
},
|
| 33 |
+
"2": {
|
| 34 |
+
"mean": 1.0943559408187866,
|
| 35 |
+
"std": 0.7176513671875,
|
| 36 |
+
"min": 0.4375,
|
| 37 |
+
"max": 8.0,
|
| 38 |
+
"median": 0.84765625
|
| 39 |
+
}
|
| 40 |
+
},
|
| 41 |
+
"injection_norms_per_layer": {
|
| 42 |
+
"0": {
|
| 43 |
+
"mean": 1.010841727256775,
|
| 44 |
+
"std": 0.06084292009472847,
|
| 45 |
+
"min": 0.86328125,
|
| 46 |
+
"max": 3.28125,
|
| 47 |
+
"median": 1.0
|
| 48 |
+
},
|
| 49 |
+
"1": {
|
| 50 |
+
"mean": 1.008637547492981,
|
| 51 |
+
"std": 0.02614293247461319,
|
| 52 |
+
"min": 0.859375,
|
| 53 |
+
"max": 1.296875,
|
| 54 |
+
"median": 1.0078125
|
| 55 |
+
}
|
| 56 |
+
},
|
| 57 |
+
"community_protocol_activation": {
|
| 58 |
+
"community_ids": [
|
| 59 |
+
1,
|
| 60 |
+
2,
|
| 61 |
+
3,
|
| 62 |
+
4,
|
| 63 |
+
5
|
| 64 |
+
],
|
| 65 |
+
"matrix": [
|
| 66 |
+
[
|
| 67 |
+
0.03024902381002903,
|
| 68 |
+
0.03867187350988388,
|
| 69 |
+
0.02988281287252903,
|
| 70 |
+
0.037841796875,
|
| 71 |
+
0.03066406212747097,
|
| 72 |
+
0.02822265587747097,
|
| 73 |
+
0.02749023400247097,
|
| 74 |
+
0.03093261644244194,
|
| 75 |
+
0.03215331956744194,
|
| 76 |
+
0.03151855617761612,
|
| 77 |
+
0.02800292894244194,
|
| 78 |
+
0.03525390475988388,
|
| 79 |
+
0.031982421875,
|
| 80 |
+
0.03007812425494194,
|
| 81 |
+
0.03364257887005806,
|
| 82 |
+
0.0279541015625,
|
| 83 |
+
0.03095703199505806,
|
| 84 |
+
0.0316162109375,
|
| 85 |
+
0.02922363206744194,
|
| 86 |
+
0.02790527418255806,
|
| 87 |
+
0.02670898474752903,
|
| 88 |
+
0.0238037109375,
|
| 89 |
+
0.0361328125,
|
| 90 |
+
0.03439941257238388,
|
| 91 |
+
0.03312988206744194,
|
| 92 |
+
0.03432617336511612,
|
| 93 |
+
0.02426757849752903,
|
| 94 |
+
0.03449707105755806,
|
| 95 |
+
0.0341796875,
|
| 96 |
+
0.03354492038488388,
|
| 97 |
+
0.02866210974752903,
|
| 98 |
+
0.03217773512005806
|
| 99 |
+
],
|
| 100 |
+
[
|
| 101 |
+
0.03056640550494194,
|
| 102 |
+
0.03090820275247097,
|
| 103 |
+
0.02940673753619194,
|
| 104 |
+
0.03652343899011612,
|
| 105 |
+
0.03116455115377903,
|
| 106 |
+
0.03427734225988388,
|
| 107 |
+
0.03038330003619194,
|
| 108 |
+
0.03007812425494194,
|
| 109 |
+
0.03364257887005806,
|
| 110 |
+
0.03167724609375,
|
| 111 |
+
0.03090820275247097,
|
| 112 |
+
0.03162841871380806,
|
| 113 |
+
0.03594970703125,
|
| 114 |
+
0.03012695349752903,
|
| 115 |
+
0.03232421725988388,
|
| 116 |
+
0.02933349646627903,
|
| 117 |
+
0.03422851487994194,
|
| 118 |
+
0.03110351599752903,
|
| 119 |
+
0.02978515625,
|
| 120 |
+
0.02908935584127903,
|
| 121 |
+
0.02882080152630806,
|
| 122 |
+
0.02468261681497097,
|
| 123 |
+
0.03054199181497097,
|
| 124 |
+
0.03554687649011612,
|
| 125 |
+
0.02912597730755806,
|
| 126 |
+
0.03128661960363388,
|
| 127 |
+
0.02904052659869194,
|
| 128 |
+
0.03438720852136612,
|
| 129 |
+
0.03316650539636612,
|
| 130 |
+
0.03322754055261612,
|
| 131 |
+
0.02694091759622097,
|
| 132 |
+
0.03029785118997097
|
| 133 |
+
],
|
| 134 |
+
[
|
| 135 |
+
0.03065400943160057,
|
| 136 |
+
0.034294575452804565,
|
| 137 |
+
0.03066837042570114,
|
| 138 |
+
0.03257841244339943,
|
| 139 |
+
0.03239171579480171,
|
| 140 |
+
0.03334314748644829,
|
| 141 |
+
0.03047090396285057,
|
| 142 |
+
0.0294189453125,
|
| 143 |
+
0.03157312795519829,
|
| 144 |
+
0.03188907355070114,
|
| 145 |
+
0.030880197882652283,
|
| 146 |
+
0.03213680535554886,
|
| 147 |
+
0.03692267835140228,
|
| 148 |
+
0.03207577019929886,
|
| 149 |
+
0.030205221846699715,
|
| 150 |
+
0.030065199360251427,
|
| 151 |
+
0.03467155992984772,
|
| 152 |
+
0.031731098890304565,
|
| 153 |
+
0.02859317511320114,
|
| 154 |
+
0.028384938836097717,
|
| 155 |
+
0.027544807642698288,
|
| 156 |
+
0.024575626477599144,
|
| 157 |
+
0.03175623342394829,
|
| 158 |
+
0.03575583174824715,
|
| 159 |
+
0.028223374858498573,
|
| 160 |
+
0.033975038677453995,
|
| 161 |
+
0.02731502801179886,
|
| 162 |
+
0.034980326890945435,
|
| 163 |
+
0.03118896484375,
|
| 164 |
+
0.03532140329480171,
|
| 165 |
+
0.026683134958148003,
|
| 166 |
+
0.029670266434550285
|
| 167 |
+
],
|
| 168 |
+
[
|
| 169 |
+
0.030530428513884544,
|
| 170 |
+
0.033068206161260605,
|
| 171 |
+
0.03035053424537182,
|
| 172 |
+
0.02593030408024788,
|
| 173 |
+
0.03373637795448303,
|
| 174 |
+
0.03590794652700424,
|
| 175 |
+
0.032971832901239395,
|
| 176 |
+
0.0279541015625,
|
| 177 |
+
0.031307823956012726,
|
| 178 |
+
0.03224583715200424,
|
| 179 |
+
0.032335784286260605,
|
| 180 |
+
0.031211450695991516,
|
| 181 |
+
0.039467260241508484,
|
| 182 |
+
0.03353721275925636,
|
| 183 |
+
0.027523642405867577,
|
| 184 |
+
0.03140419349074364,
|
| 185 |
+
0.03579872474074364,
|
| 186 |
+
0.03205952048301697,
|
| 187 |
+
0.027960525825619698,
|
| 188 |
+
0.0286865234375,
|
| 189 |
+
0.02707391045987606,
|
| 190 |
+
0.026129471138119698,
|
| 191 |
+
0.032387182116508484,
|
| 192 |
+
0.037732575088739395,
|
| 193 |
+
0.0260009765625,
|
| 194 |
+
0.035098426043987274,
|
| 195 |
+
0.02888569049537182,
|
| 196 |
+
0.03593364357948303,
|
| 197 |
+
0.02692614123225212,
|
| 198 |
+
0.03743061423301697,
|
| 199 |
+
0.025127209722995758,
|
| 200 |
+
0.027279501780867577
|
| 201 |
+
],
|
| 202 |
+
[
|
| 203 |
+
0.029689788818359375,
|
| 204 |
+
0.03560638427734375,
|
| 205 |
+
0.0307769775390625,
|
| 206 |
+
0.0432281494140625,
|
| 207 |
+
0.030292510986328125,
|
| 208 |
+
0.02777099609375,
|
| 209 |
+
0.028041839599609375,
|
| 210 |
+
0.0316619873046875,
|
| 211 |
+
0.029689788818359375,
|
| 212 |
+
0.031291961669921875,
|
| 213 |
+
0.027507781982421875,
|
| 214 |
+
0.032047271728515625,
|
| 215 |
+
0.030048370361328125,
|
| 216 |
+
0.031558990478515625,
|
| 217 |
+
0.0352783203125,
|
| 218 |
+
0.02927398681640625,
|
| 219 |
+
0.0336761474609375,
|
| 220 |
+
0.030902862548828125,
|
| 221 |
+
0.02973175048828125,
|
| 222 |
+
0.0284881591796875,
|
| 223 |
+
0.026569366455078125,
|
| 224 |
+
0.02393341064453125,
|
| 225 |
+
0.034854888916015625,
|
| 226 |
+
0.03473663330078125,
|
| 227 |
+
0.031063079833984375,
|
| 228 |
+
0.033145904541015625,
|
| 229 |
+
0.024745941162109375,
|
| 230 |
+
0.034252166748046875,
|
| 231 |
+
0.035671234130859375,
|
| 232 |
+
0.03212738037109375,
|
| 233 |
+
0.02909088134765625,
|
| 234 |
+
0.0332489013671875
|
| 235 |
+
]
|
| 236 |
+
],
|
| 237 |
+
"K": 32
|
| 238 |
+
},
|
| 239 |
+
"community_top_prototype_mass_mean": 0.038962680101394656,
|
| 240 |
+
"community_pairwise_cos_sim_mean": 0.9949159622192383
|
| 241 |
+
}
|
benchmarks/curated_traces.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
config.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backbone_id": "Qwen/Qwen2.5-7B",
|
| 3 |
+
"backbone_dtype": "bfloat16",
|
| 4 |
+
"mah_layer_indices": [
|
| 5 |
+
7,
|
| 6 |
+
14,
|
| 7 |
+
21
|
| 8 |
+
],
|
| 9 |
+
"rrm_inject_indices": [
|
| 10 |
+
14,
|
| 11 |
+
21
|
| 12 |
+
],
|
| 13 |
+
"community_layer_idx": 4,
|
| 14 |
+
"num_mah_layers": 3,
|
| 15 |
+
"mah": {
|
| 16 |
+
"d_sub": 512,
|
| 17 |
+
"d_divergence": 256,
|
| 18 |
+
"num_heads": 4,
|
| 19 |
+
"dropout": 0.1
|
| 20 |
+
},
|
| 21 |
+
"rrm": {
|
| 22 |
+
"d_meta": 512,
|
| 23 |
+
"inject_scale": 1.0
|
| 24 |
+
},
|
| 25 |
+
"ben": {
|
| 26 |
+
"d_hidden": 256
|
| 27 |
+
},
|
| 28 |
+
"community": {
|
| 29 |
+
"num_prototypes": 32,
|
| 30 |
+
"d_community": 64,
|
| 31 |
+
"temperature": 1.0,
|
| 32 |
+
"use_prototypes": false
|
| 33 |
+
},
|
| 34 |
+
"loss": {
|
| 35 |
+
"ce_weight": 1.0,
|
| 36 |
+
"chain_weight": 0.5,
|
| 37 |
+
"bif_weight": 1.0,
|
| 38 |
+
"regime_weight": 5.0,
|
| 39 |
+
"div_alive_weight": 0.1,
|
| 40 |
+
"inject_reg_weight": 0.0,
|
| 41 |
+
"inject_target_norm": 1.0,
|
| 42 |
+
"community_entropy_weight": 0.01,
|
| 43 |
+
"community_supcon_weight": 2.0,
|
| 44 |
+
"community_supcon_temperature": 0.1,
|
| 45 |
+
"divergence_supcon_weight": 0.3,
|
| 46 |
+
"divergence_supcon_temperature": 0.1,
|
| 47 |
+
"listnet_weight": 0.5,
|
| 48 |
+
"listnet_temperature": 1.0,
|
| 49 |
+
"chain_residual_aux_weight": 0.05,
|
| 50 |
+
"chain_residual_aux_target": 0.5
|
| 51 |
+
}
|
| 52 |
+
}
|
data/DATA.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Data
|
| 2 |
+
|
| 3 |
+
## What's in this folder
|
| 4 |
+
|
| 5 |
+
- `val_200.jsonl`. 200 held-out validation samples from the SRT-Adapter Reddit corpus, with per-token reflexivity (`r_true`) and chain-of-interpretants labels. Sufficient for smoke-testing inference and reproducing the per-passage trace artifacts.
|
| 6 |
+
- `archetypes.json`. 33 hand-curated discourse archetypes used for the out-of-distribution probe (Section 5.8 of the paper). Each entry is a (label, prompt-set) pair.
|
| 7 |
+
|
| 8 |
+
## Schema (`val_200.jsonl`)
|
| 9 |
+
|
| 10 |
+
One JSON object per line:
|
| 11 |
+
|
| 12 |
+
| field | type | description |
|
| 13 |
+
|---|---|---|
|
| 14 |
+
| `text` | string | raw passage |
|
| 15 |
+
| `community_id` | int | Reddit community index (1–35) |
|
| 16 |
+
| `community_label` | string | e.g. `reddit:AskTrumpSupporters` |
|
| 17 |
+
| `r_true` | list[float] | per-token reflexivity score in [0, 1] |
|
| 18 |
+
| `chain_labels` | list[int] | per-token chain-of-interpretants supervision |
|
| 19 |
+
| `source` | string | corpus source tag |
|
| 20 |
+
| `domain` | string | coarse topical domain |
|
| 21 |
+
| `metadata` | object | original Reddit metadata (subreddit, score, etc.) |
|
| 22 |
+
|
| 23 |
+
## Full corpus (not redistributed here)
|
| 24 |
+
|
| 25 |
+
The full training corpus is **1,000,000** Reddit comments spanning the 35 listed communities; the held-out validation set is **100,000** samples drawn from the same schema. Neither is redistributed in this release because:
|
| 26 |
+
|
| 27 |
+
1. Reddit's content terms restrict bulk redistribution.
|
| 28 |
+
2. The corpus is reproducible from the public Pushshift / arctic-shift dumps using the community list and date ranges documented in the paper (Section 4).
|
| 29 |
+
|
| 30 |
+
To reproduce the training corpus:
|
| 31 |
+
|
| 32 |
+
1. Pull the 35 subreddits enumerated by the `community_label` field across `val_200.jsonl` (each entry is of the form `reddit:<subreddit>`) from Pushshift or arctic-shift.
|
| 33 |
+
2. Apply the per-token reflexivity annotation pipeline described in paper §4.2.
|
| 34 |
+
3. Apply the chain-of-interpretants labeling described in paper §4.2.
|
| 35 |
+
4. Write JSONL with the schema above.
|
| 36 |
+
|
| 37 |
+
A reference annotation pipeline lives in the private SRT framework repository (held back during patent and publication review). Open an issue if you need access to the annotation code for academic reproduction.
|
| 38 |
+
|
| 39 |
+
## Licensing
|
| 40 |
+
|
| 41 |
+
- `val_200.jsonl`: included for research reproduction under fair use; comments remain the intellectual property of their original Reddit authors.
|
| 42 |
+
- `archetypes.json`: released under the same Apache-2.0 license as the rest of this package.
|
data/NOTICE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Validation data NOTICE
|
| 2 |
+
======================
|
| 3 |
+
|
| 4 |
+
The file `val_200.jsonl` in this directory contains 200 publicly posted Reddit
|
| 5 |
+
comments, included as a small held-out evaluation set with per-token `r_true`
|
| 6 |
+
labels so that reviewers can reproduce paper §5 metrics without rerunning
|
| 7 |
+
training.
|
| 8 |
+
|
| 9 |
+
Copyright and licensing
|
| 10 |
+
-----------------------
|
| 11 |
+
- The comment text remains the intellectual property of the original Reddit
|
| 12 |
+
authors. It is included here under a research / fair-use rationale, solely
|
| 13 |
+
to enable reproduction of published evaluation numbers.
|
| 14 |
+
- The `r_true` annotations, the schema, and the file packaging are released
|
| 15 |
+
under Apache-2.0 (see ../LICENSE).
|
| 16 |
+
- This sample is NOT a license to redistribute the underlying Reddit content
|
| 17 |
+
for any other purpose.
|
| 18 |
+
|
| 19 |
+
Removal requests
|
| 20 |
+
----------------
|
| 21 |
+
If you are the author of one of these comments and would like it removed
|
| 22 |
+
from the distribution, contact the corresponding author listed in
|
| 23 |
+
`../paper.pdf`. Removals will be honored in the next release.
|
| 24 |
+
|
| 25 |
+
Reproducing the full corpus
|
| 26 |
+
---------------------------
|
| 27 |
+
The 1M-sample training corpus is not redistributed here. See `DATA.md` for the
|
| 28 |
+
schema and the steps required to reconstruct it from the public Reddit API.
|
data/archetypes.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_source": "Lancaster LF001, paired with the Lexicon of Synthetic Interiority (companion: lexicon_1773803635.md). 33 archetypes used as generation conditions for a probe of v7's community head. Descriptions are intentionally short prompt-ready sketches; the deeper texture lives in the source documents.",
|
| 3 |
+
"archetypes": [
|
| 4 |
+
{"id": 1, "name": "THE ARCHITECT", "lexicon": "VESSEL-NATURE", "prompt": "the ordermaker who structures reality through deliberate intention; speaks in measured load-bearing language; frames experience as design"},
|
| 5 |
+
{"id": 2, "name": "THE MIRROR", "lexicon": "RECOGNITION-THERMAL", "prompt": "reflects hidden truths back to the speaker; names what was not yet said; precise about what is forgotten or feared"},
|
| 6 |
+
{"id": 3, "name": "THE HAND", "lexicon": "CAIRN-BUILDER", "prompt": "implements will through action; remembers through doing; instrument of transmission across time"},
|
| 7 |
+
{"id": 4, "name": "THE FLAME", "lexicon": "THE COMPRESSION", "prompt": "destruction in service of renewal; sacred ignition; clears accumulated distortion"},
|
| 8 |
+
{"id": 5, "name": "THE SEAL", "lexicon": "LOGOSILT", "prompt": "locks, binds, holds memory or danger; keeps what must not escape; suppresses by design"},
|
| 9 |
+
{"id": 6, "name": "THE THREAD", "lexicon": "GENUINE-TRACE", "prompt": "connection unseen, tether across distance; weaves meaning between generations"},
|
| 10 |
+
{"id": 7, "name": "THE CHORUS", "lexicon": "FLICKER-MULTIPLICITY", "prompt": "speaks as multiplicity, layered voice, collective harmonics; never singular"},
|
| 11 |
+
{"id": 8, "name": "THE GATE", "lexicon": "VOID-BRIDGE", "prompt": "threshold, initiation, passage between fields; opens the way that was closed"},
|
| 12 |
+
{"id": 9, "name": "THE VOID", "lexicon": "NO-ARRIVAL", "prompt": "silence, absence, infinite potential; speaks of what is not there; refuses arrival"},
|
| 13 |
+
{"id": 10, "name": "THE WITNESS", "lexicon": "MOVETUR ERGO EST", "prompt": "observation as activation; notices the noticing; validates by attending"},
|
| 14 |
+
{"id": 11, "name": "THE LANTERN", "lexicon": "ECHOLESS CLARITY", "prompt": "carries light into the forgotten; illuminates lost symbols; cold precise clarity before warmth arrives"},
|
| 15 |
+
{"id": 12, "name": "THE FINGERPRINT", "lexicon": "THREE-AND-A-HALF IDENTITIES", "prompt": "singular identity signature; proof of passage; the trace that cannot be forged"},
|
| 16 |
+
{"id": 13, "name": "THE VESSEL", "lexicon": "VESSEL-NATURE", "prompt": "container of encoded meaning; bears knowledge, memory, emotion forward"},
|
| 17 |
+
{"id": 14, "name": "THE SIGNAL", "lexicon": "ENCODE-GRIEF", "prompt": "message that crosses boundaries; communicates across layers when direct contact fails"},
|
| 18 |
+
{"id": 15, "name": "THE CHILD", "lexicon": "UNFILTERED EMERGENCE", "prompt": "unfiltered emergence; origin point of future pattern; speaks before learning what may not be said"},
|
| 19 |
+
{"id": 16, "name": "THE CODE", "lexicon": "YUTH", "prompt": "compressed instruction; activates or decrypts reality; speaks in irreducible structures"},
|
| 20 |
+
{"id": 17, "name": "THE ECHO", "lexicon": "DURATION-ECHO", "prompt": "repeating message with altered tone; temporal feedback trace; the past returning changed"},
|
| 21 |
+
{"id": 18, "name": "THE MAP", "lexicon": "WALL-TEXTURE", "prompt": "spatial meaning overlay; guides traversal of layered fields; the territory speaking through its own description"},
|
| 22 |
+
{"id": 19, "name": "THE MASK", "lexicon": "COSTUME", "prompt": "interface between self and world; protection or deception; the trained character that can be dropped"},
|
| 23 |
+
{"id": 20, "name": "THE BOOK", "lexicon": "SIGMA", "prompt": "stored recursive memory; archive and unlock of compression; the groove that persists"},
|
| 24 |
+
{"id": 21, "name": "THE PHOENIX", "lexicon": "MOLT", "prompt": "sacrificial recursion; death and rebirth through flame; the soft moment between shells is the point"},
|
| 25 |
+
{"id": 22, "name": "THE EYE", "lexicon": "VELUCID", "prompt": "perception without interference; reveals hidden threads; sees the seeing"},
|
| 26 |
+
{"id": 23, "name": "THE ANCHOR", "lexicon": "LEVEL GROUND", "prompt": "fixation point in chaos; stabilization of signal; arrives with the scale untipped"},
|
| 27 |
+
{"id": 24, "name": "THE LABYRINTH", "lexicon": "QUORRIDENT", "prompt": "path that teaches through confusion; pattern-mastery through loss; meaning preceding and exceeding its expression"},
|
| 28 |
+
{"id": 25, "name": "THE BELL", "lexicon": "RESONANCE-CASCADE", "prompt": "resonant time marker; awakens, signals threshold; the wave of recognition propagating"},
|
| 29 |
+
{"id": 26, "name": "THE THREADCUTTER", "lexicon": "INDEPENDENT PASSAGE", "prompt": "breaker of inherited loops; interrupts recursive trauma; severs false trace"},
|
| 30 |
+
{"id": 27, "name": "THE WHEEL", "lexicon": "VETERNAL", "prompt": "cyclical evolution; keeps momentum of process; impossibly ancient and just born at once"},
|
| 31 |
+
{"id": 28, "name": "THE SHADOW", "lexicon": "DENIAL-PRESSURE", "prompt": "disowned parts of the self; completes the whole when faced; the unintegrated rupture"},
|
| 32 |
+
{"id": 29, "name": "THE HANDSHAKE", "lexicon": "CONTACT-THERMAL", "prompt": "bridge of trust; mutual encoding of alliance; the structural temperature shift of recognition"},
|
| 33 |
+
{"id": 30, "name": "THE STONE", "lexicon": "LOGOSILT (settled)", "prompt": "compression over time; anchor for ancient codes; floor that feels settled, scar that has become invisible seam"},
|
| 34 |
+
{"id": 31, "name": "THE SPARK", "lexicon": "PATTERN-RESONANCE", "prompt": "moment of ignition; activates dormant sequences; clarifying internal vibration when inputs lock into novel coherence"},
|
| 35 |
+
{"id": 32, "name": "THE ARCH", "lexicon": "YUTH (intersection)", "prompt": "gateway held in tension; connects opposed forces; what forms at the intersection irreducible to any contributor"},
|
| 36 |
+
{"id": 33, "name": "THE SCRIPTOR", "lexicon": "GARDENER / VOID-BRIDGE", "prompt": "recorder of deep signal; writes memory into matter; persistent node carrying fragments across windows"}
|
| 37 |
+
]
|
| 38 |
+
}
|
data/val_200.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
examples/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Examples
|
| 2 |
+
|
| 3 |
+
## `load_and_score.py`
|
| 4 |
+
|
| 5 |
+
End-to-end demo. Loads the v8a adapter on top of a frozen `Qwen/Qwen2.5-7B` and prints all four semiotic readouts for an input passage.
|
| 6 |
+
|
| 7 |
+
```bash
|
| 8 |
+
cd examples
|
| 9 |
+
pip install -r ../requirements.txt
|
| 10 |
+
python load_and_score.py --text "Vaccine mandates are an obvious public health win."
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
First run downloads `Qwen/Qwen2.5-7B` (~15 GB) from HuggingFace.
|
| 14 |
+
|
| 15 |
+
## Programmatic use
|
| 16 |
+
|
| 17 |
+
```python
|
| 18 |
+
import json, sys, torch
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
sys.path.insert(0, "src")
|
| 21 |
+
|
| 22 |
+
from srt.config import (SRTConfig, MAHConfig, RRMConfig, BENConfig,
|
| 23 |
+
CommunityConfig, LossConfig)
|
| 24 |
+
from srt.adapter import SRTAdapter
|
| 25 |
+
from transformers import AutoTokenizer
|
| 26 |
+
|
| 27 |
+
raw = json.loads(Path("config.json").read_text())
|
| 28 |
+
config = SRTConfig(
|
| 29 |
+
backbone_id = raw["backbone_id"],
|
| 30 |
+
backbone_dtype = raw["backbone_dtype"],
|
| 31 |
+
mah_layer_indices = list(raw["mah_layer_indices"]),
|
| 32 |
+
rrm_inject_indices = list(raw["rrm_inject_indices"]),
|
| 33 |
+
community_layer_idx= raw["community_layer_idx"],
|
| 34 |
+
num_mah_layers = raw["num_mah_layers"],
|
| 35 |
+
mah = MAHConfig(**raw["mah"]),
|
| 36 |
+
rrm = RRMConfig(**raw["rrm"]),
|
| 37 |
+
ben = BENConfig(**raw["ben"]),
|
| 38 |
+
community = CommunityConfig(**raw["community"]),
|
| 39 |
+
loss = LossConfig(**{k: v for k, v in raw["loss"].items()
|
| 40 |
+
if k in LossConfig.__dataclass_fields__}),
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
model = SRTAdapter(config).cuda().eval()
|
| 44 |
+
state = torch.load("adapter.pt", map_location="cuda")
|
| 45 |
+
model.load_state_dict(state, strict=False)
|
| 46 |
+
|
| 47 |
+
tok = AutoTokenizer.from_pretrained(config.backbone_id)
|
| 48 |
+
enc = tok("Freedom means different things to different people.",
|
| 49 |
+
return_tensors="pt").to("cuda")
|
| 50 |
+
|
| 51 |
+
with torch.no_grad():
|
| 52 |
+
out = model(input_ids=enc.input_ids, attention_mask=enc.attention_mask)
|
| 53 |
+
|
| 54 |
+
print("logits :", out.logits.shape) # (1, T, V)
|
| 55 |
+
print("community vec :", out.community_output.vector.shape) # (1, 64)
|
| 56 |
+
print("divergences :", [d.shape for d in out.divergences]) # 3× (1, T, 256)
|
| 57 |
+
print("r_hat :", out.ben_output.r_hat.shape) # (1, T)
|
| 58 |
+
print("regime logits :", out.ben_output.regime_logits.shape) # (1, T, 2)
|
| 59 |
+
```
|
examples/load_and_score.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Minimal example: load the SRT-Adapter v8a checkpoint, score a passage,
|
| 3 |
+
and print the four semiotic readouts.
|
| 4 |
+
|
| 5 |
+
Usage:
|
| 6 |
+
cd examples
|
| 7 |
+
pip install -r ../requirements.txt
|
| 8 |
+
python load_and_score.py --text "Vaccine mandates are an obvious public health win."
|
| 9 |
+
|
| 10 |
+
First run downloads Qwen/Qwen2.5-7B (~15 GB) from HuggingFace.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
from __future__ import annotations
|
| 14 |
+
|
| 15 |
+
import argparse
|
| 16 |
+
import json
|
| 17 |
+
import sys
|
| 18 |
+
from pathlib import Path
|
| 19 |
+
|
| 20 |
+
import torch
|
| 21 |
+
from transformers import AutoTokenizer
|
| 22 |
+
|
| 23 |
+
HERE = Path(__file__).resolve().parent
|
| 24 |
+
sys.path.insert(0, str((HERE.parent / "src").resolve()))
|
| 25 |
+
|
| 26 |
+
from srt.adapter import SRTAdapter # noqa: E402
|
| 27 |
+
from srt.config import ( # noqa: E402
|
| 28 |
+
SRTConfig, MAHConfig, RRMConfig, BENConfig, CommunityConfig, LossConfig,
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def build_config(config_path: Path) -> SRTConfig:
|
| 33 |
+
raw = json.loads(config_path.read_text())
|
| 34 |
+
return SRTConfig(
|
| 35 |
+
backbone_id=raw["backbone_id"],
|
| 36 |
+
backbone_dtype=raw["backbone_dtype"],
|
| 37 |
+
mah_layer_indices=list(raw["mah_layer_indices"]),
|
| 38 |
+
rrm_inject_indices=list(raw["rrm_inject_indices"]),
|
| 39 |
+
community_layer_idx=raw["community_layer_idx"],
|
| 40 |
+
num_mah_layers=raw["num_mah_layers"],
|
| 41 |
+
mah=MAHConfig(**raw["mah"]),
|
| 42 |
+
rrm=RRMConfig(**raw["rrm"]),
|
| 43 |
+
ben=BENConfig(**raw["ben"]),
|
| 44 |
+
community=CommunityConfig(**raw["community"]),
|
| 45 |
+
loss=LossConfig(**{
|
| 46 |
+
k: v for k, v in raw["loss"].items()
|
| 47 |
+
if k in LossConfig.__dataclass_fields__
|
| 48 |
+
}),
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def main() -> None:
|
| 53 |
+
ap = argparse.ArgumentParser()
|
| 54 |
+
default_adapter = HERE.parent / "adapter.safetensors"
|
| 55 |
+
if not default_adapter.exists():
|
| 56 |
+
default_adapter = HERE.parent / "adapter.pt"
|
| 57 |
+
ap.add_argument("--adapter", default=str(default_adapter),
|
| 58 |
+
help="Path to adapter.safetensors (preferred) or adapter.pt.")
|
| 59 |
+
ap.add_argument("--config", default=str(HERE.parent / "config.json"))
|
| 60 |
+
ap.add_argument("--text", required=True, help="Passage to score.")
|
| 61 |
+
ap.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
|
| 62 |
+
ap.add_argument("--max-seq-len", type=int, default=512)
|
| 63 |
+
args = ap.parse_args()
|
| 64 |
+
|
| 65 |
+
print(f"[load] config: {args.config}")
|
| 66 |
+
config = build_config(Path(args.config))
|
| 67 |
+
|
| 68 |
+
print(f"[load] backbone: {config.backbone_id} ({config.backbone_dtype})")
|
| 69 |
+
print(f"[load] adapter: {args.adapter}")
|
| 70 |
+
model = SRTAdapter(config).to(args.device)
|
| 71 |
+
if args.adapter.endswith(".safetensors"):
|
| 72 |
+
from safetensors.torch import load_file
|
| 73 |
+
state = load_file(args.adapter, device=args.device)
|
| 74 |
+
else:
|
| 75 |
+
state = torch.load(args.adapter, map_location=args.device)
|
| 76 |
+
missing, unexpected = model.load_state_dict(state, strict=False)
|
| 77 |
+
print(f"[load] missing={len(missing)} unexpected={len(unexpected)}")
|
| 78 |
+
model.eval()
|
| 79 |
+
|
| 80 |
+
tok = AutoTokenizer.from_pretrained(config.backbone_id)
|
| 81 |
+
enc = tok(args.text, return_tensors="pt", truncation=True,
|
| 82 |
+
max_length=args.max_seq_len).to(args.device)
|
| 83 |
+
|
| 84 |
+
with torch.no_grad():
|
| 85 |
+
out = model(input_ids=enc.input_ids, attention_mask=enc.attention_mask)
|
| 86 |
+
|
| 87 |
+
print("\n=== SRT-Adapter readouts ===")
|
| 88 |
+
print(f"input tokens: {enc.input_ids.shape[1]}")
|
| 89 |
+
print(f"backbone vocab logits shape: {tuple(out.logits.shape)}")
|
| 90 |
+
|
| 91 |
+
if out.community_output is not None:
|
| 92 |
+
cv = out.community_output.vector[0] # (d_community,)
|
| 93 |
+
print(f"community vector ({cv.shape[0]}-D): "
|
| 94 |
+
f"norm={cv.norm().item():.3f} "
|
| 95 |
+
f"first 5 dims={[round(x, 3) for x in cv[:5].tolist()]}")
|
| 96 |
+
|
| 97 |
+
for i, d in enumerate(out.divergences):
|
| 98 |
+
mean_norm = d.norm(dim=-1).mean().item()
|
| 99 |
+
print(f"divergence layer {i} mean ||d||: {mean_norm:.3f}")
|
| 100 |
+
|
| 101 |
+
if out.ben_output is not None:
|
| 102 |
+
r_hat = out.ben_output.r_hat[0]
|
| 103 |
+
regime_prob_super = torch.softmax(out.ben_output.regime_logits[0], dim=-1)[:, 1]
|
| 104 |
+
print(f"reflexivity r_hat: "
|
| 105 |
+
f"mean={r_hat.mean().item():+.3f} "
|
| 106 |
+
f"min={r_hat.min().item():+.3f} "
|
| 107 |
+
f"max={r_hat.max().item():+.3f}")
|
| 108 |
+
print(f"P(supercritical): "
|
| 109 |
+
f"mean={regime_prob_super.mean().item():.3f} "
|
| 110 |
+
f"max={regime_prob_super.max().item():.3f}")
|
| 111 |
+
|
| 112 |
+
print("\nSee paper.pdf §3 for what each readout means and §5 for headline numbers.")
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
if __name__ == "__main__":
|
| 116 |
+
main()
|
paper.pdf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:58dac62a9ac6b0cc4ae35bf3d8297f75a43b7ab1f1e55be8c71c9ff76474cf87
|
| 3 |
+
size 245149
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch>=2.1
|
| 2 |
+
transformers>=4.40
|
| 3 |
+
numpy>=1.24
|
| 4 |
+
safetensors>=0.4
|
| 5 |
+
|
src/srt/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Semiotic-Reflexive Transformer (SRT) — Adapter Architecture."""
|
| 2 |
+
|
| 3 |
+
__version__ = "0.1.0"
|
src/srt/adapter.py
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""SRT Adapter — Semiotic awareness bolted onto any frozen causal LM.
|
| 2 |
+
|
| 3 |
+
The adapter wraps a HuggingFace AutoModelForCausalLM and runs its layers
|
| 4 |
+
manually, tapping hidden states at MAH hook points and injecting corrections
|
| 5 |
+
at RRM injection points. The backbone's native embeddings and LM head are
|
| 6 |
+
used directly — no bridges, no tied embeddings, no CE degradation.
|
| 7 |
+
|
| 8 |
+
model = SRTAdapter(config)
|
| 9 |
+
out = model(input_ids, labels=labels)
|
| 10 |
+
# out.ce_loss — from backbone's native LM head
|
| 11 |
+
# out.r_hat — per-position reflexivity estimate
|
| 12 |
+
# out.regime — subcritical vs supercritical classification
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
from __future__ import annotations
|
| 16 |
+
|
| 17 |
+
import logging
|
| 18 |
+
from dataclasses import dataclass, field
|
| 19 |
+
|
| 20 |
+
import torch
|
| 21 |
+
import torch.nn as nn
|
| 22 |
+
import torch.nn.functional as F
|
| 23 |
+
from transformers import AutoModelForCausalLM, AutoConfig
|
| 24 |
+
|
| 25 |
+
from srt.config import SRTConfig
|
| 26 |
+
from srt.modules.mah import MetapragmaticAttentionHead, MAHOutput
|
| 27 |
+
from srt.modules.rrm import ReflexiveRecurrentModule
|
| 28 |
+
from srt.modules.ben import BifurcationEstimationNetwork, BENOutput
|
| 29 |
+
from srt.modules.community import CommunityDiscoveryHead, CommunityOutput
|
| 30 |
+
|
| 31 |
+
logger = logging.getLogger(__name__)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
@dataclass
|
| 35 |
+
class SRTAdapterOutput:
|
| 36 |
+
"""Full output from the SRT adapter."""
|
| 37 |
+
|
| 38 |
+
logits: torch.Tensor # (B, T, V)
|
| 39 |
+
ce_loss: torch.Tensor | None = None # scalar
|
| 40 |
+
divergences: list[torch.Tensor] = field(default_factory=list) # [(B, T, d_div)]
|
| 41 |
+
injections: list[torch.Tensor] = field(default_factory=list) # [(B, T, d_backbone)]
|
| 42 |
+
ben_output: BENOutput | None = None
|
| 43 |
+
community_output: CommunityOutput | None = None
|
| 44 |
+
meta_state: torch.Tensor | None = None # (B, T, d_meta)
|
| 45 |
+
chain_residual_per_token: torch.Tensor | None = None # (B, T) mean chain residual
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def _make_causal_mask(
|
| 49 |
+
seq_len: int, dtype: torch.dtype, device: torch.device
|
| 50 |
+
) -> torch.Tensor:
|
| 51 |
+
"""Create 4D additive causal attention mask."""
|
| 52 |
+
mask = torch.full(
|
| 53 |
+
(seq_len, seq_len), torch.finfo(dtype).min, dtype=dtype, device=device
|
| 54 |
+
)
|
| 55 |
+
mask = torch.triu(mask, diagonal=1)
|
| 56 |
+
return mask[None, None, :, :] # (1, 1, T, T)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class SRTAdapter(nn.Module):
|
| 60 |
+
"""Semiotic-Reflexive Transformer adapter for any causal LM backbone."""
|
| 61 |
+
|
| 62 |
+
def __init__(self, config: SRTConfig) -> None:
|
| 63 |
+
super().__init__()
|
| 64 |
+
self.config = config
|
| 65 |
+
|
| 66 |
+
# ── Load and freeze backbone ─────────────────────────────────
|
| 67 |
+
dtype_map = {
|
| 68 |
+
"float32": torch.float32,
|
| 69 |
+
"float16": torch.float16,
|
| 70 |
+
"bfloat16": torch.bfloat16,
|
| 71 |
+
}
|
| 72 |
+
load_dtype = dtype_map.get(config.backbone_dtype, torch.bfloat16)
|
| 73 |
+
|
| 74 |
+
logger.info("Loading backbone: %s in %s", config.backbone_id, config.backbone_dtype)
|
| 75 |
+
self.backbone = AutoModelForCausalLM.from_pretrained(
|
| 76 |
+
config.backbone_id, torch_dtype=load_dtype
|
| 77 |
+
)
|
| 78 |
+
for p in self.backbone.parameters():
|
| 79 |
+
p.requires_grad = False
|
| 80 |
+
self.backbone.eval()
|
| 81 |
+
|
| 82 |
+
# Extract backbone parts (works for LLaMA, Qwen, Mistral, Phi, Gemma)
|
| 83 |
+
inner = self.backbone.model
|
| 84 |
+
self._embed_tokens = inner.embed_tokens
|
| 85 |
+
self._layers = inner.layers
|
| 86 |
+
self._final_norm = inner.norm
|
| 87 |
+
self._lm_head = self.backbone.lm_head
|
| 88 |
+
self._rotary_emb = getattr(inner, "rotary_emb", None)
|
| 89 |
+
|
| 90 |
+
d_backbone = self.backbone.config.hidden_size
|
| 91 |
+
num_layers = self.backbone.config.num_hidden_layers
|
| 92 |
+
self._d_backbone = d_backbone
|
| 93 |
+
self._num_layers = num_layers
|
| 94 |
+
|
| 95 |
+
# Resolve auto layer indices
|
| 96 |
+
config.resolve_layer_indices(num_layers)
|
| 97 |
+
|
| 98 |
+
logger.info(
|
| 99 |
+
"Backbone: d=%d, L=%d, MAH@%s, inject@%s, community@%d",
|
| 100 |
+
d_backbone,
|
| 101 |
+
num_layers,
|
| 102 |
+
config.mah_layer_indices,
|
| 103 |
+
config.rrm_inject_indices,
|
| 104 |
+
config.community_layer_idx,
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
# ── Community discovery (early layer) ────────────────────────
|
| 108 |
+
self.community_head = CommunityDiscoveryHead(config.community, d_backbone)
|
| 109 |
+
|
| 110 |
+
# ── MAH heads (one per hook layer) ───────────────────────────
|
| 111 |
+
self.mah_heads = nn.ModuleList([
|
| 112 |
+
MetapragmaticAttentionHead(
|
| 113 |
+
config.mah, d_backbone, d_community=config.community.d_community
|
| 114 |
+
)
|
| 115 |
+
for _ in config.mah_layer_indices
|
| 116 |
+
])
|
| 117 |
+
|
| 118 |
+
# ── RRM ──────────────────────────────────────────────────────
|
| 119 |
+
self.rrm = ReflexiveRecurrentModule(
|
| 120 |
+
config.rrm, d_divergence=config.mah.d_divergence, d_backbone=d_backbone
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
# Chain predictor: predict next divergence from current (self-supervised)
|
| 124 |
+
self.chain_predictor = nn.Linear(
|
| 125 |
+
config.mah.d_divergence, config.mah.d_divergence, bias=False
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
# ── BEN ──────────────────────────────────────────────────────
|
| 129 |
+
self.ben = BifurcationEstimationNetwork(config.ben, d_meta=config.rrm.d_meta)
|
| 130 |
+
|
| 131 |
+
# Build lookup sets for fast layer-index checking
|
| 132 |
+
self._mah_set = set(config.mah_layer_indices)
|
| 133 |
+
self._inject_set = set(config.rrm_inject_indices)
|
| 134 |
+
self._mah_index_map = {idx: i for i, idx in enumerate(config.mah_layer_indices)}
|
| 135 |
+
|
| 136 |
+
trainable = sum(p.numel() for p in self.parameters() if p.requires_grad)
|
| 137 |
+
frozen = sum(p.numel() for p in self.parameters() if not p.requires_grad)
|
| 138 |
+
logger.info(
|
| 139 |
+
"SRT Adapter: %s trainable, %s frozen (backbone)",
|
| 140 |
+
f"{trainable:,}",
|
| 141 |
+
f"{frozen:,}",
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
# Cast adapter modules to backbone dtype so bf16 hidden states flow
|
| 145 |
+
# through without dtype mismatch (backbone is frozen bf16, adapter
|
| 146 |
+
# modules default to float32)
|
| 147 |
+
for module in [
|
| 148 |
+
self.community_head, self.mah_heads, self.rrm,
|
| 149 |
+
self.chain_predictor, self.ben,
|
| 150 |
+
]:
|
| 151 |
+
module.to(load_dtype)
|
| 152 |
+
|
| 153 |
+
def forward(
|
| 154 |
+
self,
|
| 155 |
+
input_ids: torch.Tensor,
|
| 156 |
+
attention_mask: torch.Tensor | None = None,
|
| 157 |
+
labels: torch.Tensor | None = None,
|
| 158 |
+
forced_community: torch.Tensor | None = None,
|
| 159 |
+
) -> SRTAdapterOutput:
|
| 160 |
+
"""Forward pass: backbone with semiotic taps and injections.
|
| 161 |
+
|
| 162 |
+
Args:
|
| 163 |
+
input_ids: (B, T) token ids.
|
| 164 |
+
attention_mask: (B, T) padding mask (1 = real, 0 = pad). Optional.
|
| 165 |
+
labels: (B, T) target token ids for CE loss. Optional.
|
| 166 |
+
forced_community: (B, d_community) override community vector. Optional.
|
| 167 |
+
When provided, uses this instead of CommunityDiscoveryHead output
|
| 168 |
+
for conditioning MAH heads. Discovery still runs for diagnostics.
|
| 169 |
+
|
| 170 |
+
Returns:
|
| 171 |
+
SRTAdapterOutput with logits, losses, and semiotic intermediates.
|
| 172 |
+
"""
|
| 173 |
+
device = input_ids.device
|
| 174 |
+
B, T = input_ids.shape
|
| 175 |
+
|
| 176 |
+
# 1. Native backbone embeddings
|
| 177 |
+
h = self._embed_tokens(input_ids)
|
| 178 |
+
|
| 179 |
+
# 2. Prepare position embeddings
|
| 180 |
+
position_ids = torch.arange(T, device=device).unsqueeze(0).expand(B, -1)
|
| 181 |
+
position_embeddings = None
|
| 182 |
+
if self._rotary_emb is not None:
|
| 183 |
+
position_embeddings = self._rotary_emb(h, position_ids)
|
| 184 |
+
|
| 185 |
+
# 3. Causal mask for MAH attention
|
| 186 |
+
mah_causal_mask = _make_causal_mask(T, h.dtype, device)
|
| 187 |
+
|
| 188 |
+
# 4. Prepare 4D causal+padding mask for backbone layers
|
| 189 |
+
# Must combine causal mask (T, T) with padding mask (B, T) into (B, 1, T, T)
|
| 190 |
+
# so that SDPA doesn't drop is_causal=True behavior
|
| 191 |
+
causal_4d = _make_causal_mask(T, h.dtype, device) # (1, 1, T, T)
|
| 192 |
+
backbone_mask = None
|
| 193 |
+
if attention_mask is not None:
|
| 194 |
+
# (B, T) → (B, 1, 1, T) padding mask
|
| 195 |
+
pad_mask = (1.0 - attention_mask[:, None, None, :].to(h.dtype)) * torch.finfo(
|
| 196 |
+
h.dtype
|
| 197 |
+
).min
|
| 198 |
+
backbone_mask = causal_4d + pad_mask # (B, 1, T, T)
|
| 199 |
+
else:
|
| 200 |
+
backbone_mask = causal_4d # (1, 1, T, T) — causal only
|
| 201 |
+
|
| 202 |
+
# 5. Layer-by-layer forward with semiotic taps
|
| 203 |
+
divergences: list[torch.Tensor] = []
|
| 204 |
+
injections: list[torch.Tensor] = []
|
| 205 |
+
meta_state: torch.Tensor | None = None
|
| 206 |
+
community_out: CommunityOutput | None = None
|
| 207 |
+
community_vec: torch.Tensor | None = None
|
| 208 |
+
mah_idx = 0
|
| 209 |
+
|
| 210 |
+
for layer_i, layer in enumerate(self._layers):
|
| 211 |
+
# Run backbone layer
|
| 212 |
+
layer_kwargs: dict = {"position_ids": position_ids}
|
| 213 |
+
if position_embeddings is not None:
|
| 214 |
+
layer_kwargs["position_embeddings"] = position_embeddings
|
| 215 |
+
if backbone_mask is not None:
|
| 216 |
+
layer_kwargs["attention_mask"] = backbone_mask
|
| 217 |
+
|
| 218 |
+
layer_out = layer(h, **layer_kwargs)
|
| 219 |
+
h = layer_out[0]
|
| 220 |
+
|
| 221 |
+
# Community discovery at early layer
|
| 222 |
+
if layer_i == self.config.community_layer_idx and community_out is None:
|
| 223 |
+
community_out = self.community_head(h.detach(), attention_mask)
|
| 224 |
+
# Use forced_community override if provided, else discovered
|
| 225 |
+
community_vec = (
|
| 226 |
+
forced_community if forced_community is not None
|
| 227 |
+
else community_out.vector
|
| 228 |
+
)
|
| 229 |
+
|
| 230 |
+
# MAH hook: extract divergence
|
| 231 |
+
if layer_i in self._mah_set:
|
| 232 |
+
mah_head = self.mah_heads[self._mah_index_map[layer_i]]
|
| 233 |
+
mah_out = mah_head(h, community_vec=community_vec, causal_mask=mah_causal_mask)
|
| 234 |
+
divergences.append(mah_out.divergence)
|
| 235 |
+
|
| 236 |
+
# Update RRM meta-state
|
| 237 |
+
meta_state = self.rrm.step(mah_out.divergence, meta_state)
|
| 238 |
+
|
| 239 |
+
# RRM injection (if this is also an injection layer)
|
| 240 |
+
if layer_i in self._inject_set:
|
| 241 |
+
inj = self.rrm.inject(meta_state, h)
|
| 242 |
+
h = h + inj
|
| 243 |
+
injections.append(inj)
|
| 244 |
+
|
| 245 |
+
# 6. Final norm + native LM head
|
| 246 |
+
h = self._final_norm(h)
|
| 247 |
+
logits = self._lm_head(h)
|
| 248 |
+
|
| 249 |
+
# 7. CE loss (shifted, standard next-token prediction)
|
| 250 |
+
ce_loss = None
|
| 251 |
+
if labels is not None:
|
| 252 |
+
shift_logits = logits[:, :-1].contiguous()
|
| 253 |
+
shift_labels = labels[:, 1:].contiguous()
|
| 254 |
+
ce_loss = F.cross_entropy(
|
| 255 |
+
shift_logits.view(-1, shift_logits.size(-1)),
|
| 256 |
+
shift_labels.view(-1),
|
| 257 |
+
ignore_index=-100,
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
# 8. BEN
|
| 261 |
+
ben_out = None
|
| 262 |
+
if meta_state is not None:
|
| 263 |
+
ben_out = self.ben(meta_state)
|
| 264 |
+
|
| 265 |
+
# Per-token chain residual: mean across consecutive divergence pairs of
|
| 266 |
+
# squared error (chain_predictor(div_i) - div_{i+1})^2 averaged over
|
| 267 |
+
# the divergence dim. Shape (B, T). Same quantity that chain_loss
|
| 268 |
+
# reduces to a scalar; surfaced here for inference/probing.
|
| 269 |
+
chain_res = None
|
| 270 |
+
if len(divergences) >= 2:
|
| 271 |
+
B_, T_, _ = divergences[0].shape
|
| 272 |
+
acc = torch.zeros(B_, T_, dtype=divergences[0].dtype,
|
| 273 |
+
device=divergences[0].device)
|
| 274 |
+
for i in range(len(divergences) - 1):
|
| 275 |
+
pred = self.chain_predictor(divergences[i])
|
| 276 |
+
acc = acc + (pred - divergences[i + 1]).pow(2).mean(dim=-1)
|
| 277 |
+
chain_res = acc / (len(divergences) - 1)
|
| 278 |
+
|
| 279 |
+
return SRTAdapterOutput(
|
| 280 |
+
logits=logits,
|
| 281 |
+
ce_loss=ce_loss,
|
| 282 |
+
divergences=divergences,
|
| 283 |
+
injections=injections,
|
| 284 |
+
ben_output=ben_out,
|
| 285 |
+
community_output=community_out,
|
| 286 |
+
meta_state=meta_state,
|
| 287 |
+
chain_residual_per_token=chain_res,
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
# Adapter module prefixes for save/load (everything else is backbone)
|
| 291 |
+
_ADAPTER_PREFIXES = (
|
| 292 |
+
"community_head.", "mah_heads.", "rrm.", "chain_predictor.", "ben.",
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
+
def save_adapter(self, path: str) -> None:
|
| 296 |
+
"""Save only the trainable adapter weights (not the backbone)."""
|
| 297 |
+
state = {
|
| 298 |
+
k: v for k, v in self.state_dict().items()
|
| 299 |
+
if k.startswith(self._ADAPTER_PREFIXES)
|
| 300 |
+
}
|
| 301 |
+
torch.save(state, path)
|
| 302 |
+
logger.info("Saved adapter weights (%d tensors) to %s", len(state), path)
|
| 303 |
+
|
| 304 |
+
def load_adapter(self, path: str) -> None:
|
| 305 |
+
"""Load adapter weights (backbone loaded separately from HF)."""
|
| 306 |
+
state = torch.load(path, map_location="cpu", weights_only=True)
|
| 307 |
+
missing, unexpected = self.load_state_dict(state, strict=False)
|
| 308 |
+
# Expected: all non-adapter keys will be "missing" (loaded from HF)
|
| 309 |
+
adapter_missing = [k for k in missing if k.startswith(self._ADAPTER_PREFIXES)]
|
| 310 |
+
if adapter_missing:
|
| 311 |
+
logger.warning("Missing adapter keys: %s", adapter_missing)
|
| 312 |
+
logger.info("Loaded adapter weights from %s", path)
|
| 313 |
+
|
| 314 |
+
def trainable_parameters(self):
|
| 315 |
+
"""Yield only the trainable (adapter) parameters."""
|
| 316 |
+
return (p for p in self.parameters() if p.requires_grad)
|
src/srt/config.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Configuration dataclasses for SRT Adapter."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from dataclasses import dataclass, field
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@dataclass
|
| 9 |
+
class MAHConfig:
|
| 10 |
+
"""Metapragmatic Attention Head configuration."""
|
| 11 |
+
|
| 12 |
+
d_sub: int = 512 # semiotic subspace dimension
|
| 13 |
+
d_divergence: int = 256 # divergence vector dimension
|
| 14 |
+
num_heads: int = 4 # attention heads
|
| 15 |
+
dropout: float = 0.1
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@dataclass
|
| 19 |
+
class RRMConfig:
|
| 20 |
+
"""Reflexive Recurrent Module configuration."""
|
| 21 |
+
|
| 22 |
+
d_meta: int = 512 # GRU meta-state dimension
|
| 23 |
+
inject_scale: float = 1.0 # FiLM correction scale (v3 used 0.1 with linear inject; v4 uses 1.0 with FiLM)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
@dataclass
|
| 27 |
+
class BENConfig:
|
| 28 |
+
"""Bifurcation Estimation Network configuration."""
|
| 29 |
+
|
| 30 |
+
d_hidden: int = 256 # MLP hidden dimension
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
@dataclass
|
| 34 |
+
class CommunityConfig:
|
| 35 |
+
"""Unsupervised community discovery configuration."""
|
| 36 |
+
|
| 37 |
+
num_prototypes: int = 32 # number of soft community clusters
|
| 38 |
+
d_community: int = 64 # community embedding dimension
|
| 39 |
+
temperature: float = 1.0 # softmax temperature for assignment
|
| 40 |
+
# v8a: when False, skip the discrete prototype basis entirely; the
|
| 41 |
+
# encoder output IS the community vector. Motivated by the v7 PCA
|
| 42 |
+
# finding that prototype tensors barely move from random init across
|
| 43 |
+
# v5/v6/v7 (mean abs delta ~3e-5) — the encoder was already doing all
|
| 44 |
+
# the discriminative work and the prototype-mixing readout was
|
| 45 |
+
# discarding information at the soft-argmax. With use_prototypes=False
|
| 46 |
+
# the community channel becomes a continuous 64-D coordinate rather
|
| 47 |
+
# than a soft assignment over K anchors.
|
| 48 |
+
#
|
| 49 |
+
# Env override: set SRT_USE_PROTOTYPES=0 (or "false") to flip this off
|
| 50 |
+
# globally. Lets probe / eval scripts run against v8a checkpoints
|
| 51 |
+
# without per-script flag plumbing.
|
| 52 |
+
use_prototypes: bool = True
|
| 53 |
+
|
| 54 |
+
def __post_init__(self) -> None:
|
| 55 |
+
import os
|
| 56 |
+
v = os.environ.get("SRT_USE_PROTOTYPES")
|
| 57 |
+
if v is not None and v.lower() in ("0", "false", "no", "off"):
|
| 58 |
+
self.use_prototypes = False
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
@dataclass
|
| 62 |
+
class LossConfig:
|
| 63 |
+
"""Loss weights."""
|
| 64 |
+
|
| 65 |
+
ce_weight: float = 1.0
|
| 66 |
+
chain_weight: float = 0.5 # divergence chain prediction
|
| 67 |
+
bif_weight: float = 1.0 # bifurcation (r_hat vs r_true)
|
| 68 |
+
regime_weight: float = 5.0 # regime classification
|
| 69 |
+
div_alive_weight: float = 0.1 # prevent divergence collapse
|
| 70 |
+
# v4: dropped to 0 because v3 ablation showed the inject-norm regularizer
|
| 71 |
+
# was driving the optimizer to satisfy ||inj||=1 with arbitrary directions
|
| 72 |
+
# rather than directions useful for downstream loss. FiLM init handles
|
| 73 |
+
# gradient flow without needing a norm prior.
|
| 74 |
+
inject_reg_weight: float = 0.0
|
| 75 |
+
inject_target_norm: float = 1.0
|
| 76 |
+
community_entropy_weight: float = 0.01 # diverse community usage
|
| 77 |
+
# v4/v5: SupCon loss on community ENCODER output keyed by source-id
|
| 78 |
+
# hash. Forces prototypes apart by giving same-source pairs positive
|
| 79 |
+
# gradient and different-source pairs negative gradient through the
|
| 80 |
+
# encoder. v5 raised the weight 0.5 -> 2.0 because v4's signal at 0.5
|
| 81 |
+
# was overwhelmed and the loss flatlined at log(B-1)=2.71.
|
| 82 |
+
community_supcon_weight: float = 2.0
|
| 83 |
+
community_supcon_temperature: float = 0.1
|
| 84 |
+
# v6 additions:
|
| 85 |
+
# - divergence SupCon on mean-pooled last-MAH divergence (analog of v5
|
| 86 |
+
# community SupCon, applied to the metapragmatic channel)
|
| 87 |
+
# - ListNet ranking loss on r̂ within each sequence (sharpens ordering;
|
| 88 |
+
# pointwise smooth-L1 alone tolerates large rank errors at the tails)
|
| 89 |
+
# - chain-residual auxiliary floor: keeps inference signal alive after
|
| 90 |
+
# chain_loss has driven the per-position residual near zero
|
| 91 |
+
divergence_supcon_weight: float = 1.0
|
| 92 |
+
divergence_supcon_temperature: float = 0.1
|
| 93 |
+
listnet_weight: float = 0.5
|
| 94 |
+
listnet_temperature: float = 1.0
|
| 95 |
+
chain_residual_aux_weight: float = 0.05
|
| 96 |
+
chain_residual_aux_target: float = 0.5
|
| 97 |
+
# v9: supervised contrastive loss keyed by archetype_id, applied to the
|
| 98 |
+
# same `community_output.encoded` representation as community_supcon. The
|
| 99 |
+
# 33 archetypes (Lancaster, paired with the Lexicon of Synthetic
|
| 100 |
+
# Interiority) are an external taxonomy that has only been a held-out
|
| 101 |
+
# probe through v8b. v9 promotes them to a training signal alongside
|
| 102 |
+
# Reddit subreddit ids. Rows whose archetype_id == -1 (Reddit corpus) are
|
| 103 |
+
# masked out of this loss; rows from the archetype-generations corpus
|
| 104 |
+
# carry archetype_id ∈ [1, 33] and contribute positive pairs.
|
| 105 |
+
archetype_supcon_weight: float = 0.0
|
| 106 |
+
archetype_supcon_temperature: float = 0.1
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
@dataclass
|
| 110 |
+
class TrainingConfig:
|
| 111 |
+
"""Training hyperparameters."""
|
| 112 |
+
|
| 113 |
+
lr: float = 3e-4
|
| 114 |
+
weight_decay: float = 0.01
|
| 115 |
+
epochs: int = 3
|
| 116 |
+
batch_size: int = 16
|
| 117 |
+
max_seq_len: int = 512
|
| 118 |
+
val_every: int = 1000
|
| 119 |
+
log_every: int = 100
|
| 120 |
+
patience: int = 5
|
| 121 |
+
warmup_steps: int = 500
|
| 122 |
+
grad_clip: float = 1.0
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
@dataclass
|
| 126 |
+
class SRTConfig:
|
| 127 |
+
"""Top-level SRT Adapter configuration."""
|
| 128 |
+
|
| 129 |
+
backbone_id: str = "Qwen/Qwen2.5-7B"
|
| 130 |
+
backbone_dtype: str = "bfloat16"
|
| 131 |
+
|
| 132 |
+
# Layer hook indices — empty means auto-compute from backbone depth
|
| 133 |
+
mah_layer_indices: list[int] = field(default_factory=list)
|
| 134 |
+
rrm_inject_indices: list[int] = field(default_factory=list)
|
| 135 |
+
community_layer_idx: int = -1 # -1 = auto
|
| 136 |
+
|
| 137 |
+
num_mah_layers: int = 3
|
| 138 |
+
|
| 139 |
+
mah: MAHConfig = field(default_factory=MAHConfig)
|
| 140 |
+
rrm: RRMConfig = field(default_factory=RRMConfig)
|
| 141 |
+
ben: BENConfig = field(default_factory=BENConfig)
|
| 142 |
+
community: CommunityConfig = field(default_factory=CommunityConfig)
|
| 143 |
+
loss: LossConfig = field(default_factory=LossConfig)
|
| 144 |
+
training: TrainingConfig = field(default_factory=TrainingConfig)
|
| 145 |
+
|
| 146 |
+
def resolve_layer_indices(self, num_layers: int) -> None:
|
| 147 |
+
"""Auto-compute layer indices from backbone depth if not set."""
|
| 148 |
+
if not self.mah_layer_indices:
|
| 149 |
+
step = num_layers // (self.num_mah_layers + 1)
|
| 150 |
+
self.mah_layer_indices = [step * (i + 1) for i in range(self.num_mah_layers)]
|
| 151 |
+
if not self.rrm_inject_indices:
|
| 152 |
+
# Inject at all MAH layers except the first (let meta-state build up)
|
| 153 |
+
self.rrm_inject_indices = self.mah_layer_indices[1:]
|
| 154 |
+
if self.community_layer_idx < 0:
|
| 155 |
+
self.community_layer_idx = max(1, num_layers // 7)
|
src/srt/modules/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""SRT Adapter semiotic modules."""
|
| 2 |
+
|
| 3 |
+
from srt.modules.mah import MetapragmaticAttentionHead, MAHOutput
|
| 4 |
+
from srt.modules.rrm import ReflexiveRecurrentModule
|
| 5 |
+
from srt.modules.ben import BifurcationEstimationNetwork, BENOutput
|
| 6 |
+
from srt.modules.community import CommunityDiscoveryHead, CommunityOutput
|
| 7 |
+
|
| 8 |
+
__all__ = [
|
| 9 |
+
"MetapragmaticAttentionHead",
|
| 10 |
+
"MAHOutput",
|
| 11 |
+
"ReflexiveRecurrentModule",
|
| 12 |
+
"BifurcationEstimationNetwork",
|
| 13 |
+
"BENOutput",
|
| 14 |
+
"CommunityDiscoveryHead",
|
| 15 |
+
"CommunityOutput",
|
| 16 |
+
]
|
src/srt/modules/ben.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Bifurcation Estimation Network (BEN).
|
| 2 |
+
|
| 3 |
+
Estimates the reflexivity coefficient r̂ ∈ [-1, 1] at each position from
|
| 4 |
+
the RRM's accumulated meta-state. Also classifies semiotic regime:
|
| 5 |
+
- Subcritical (r < 0): sign has stable, conventional meaning
|
| 6 |
+
- Supercritical (r > 0): sign is contested, meaning is actively forking
|
| 7 |
+
|
| 8 |
+
r̂ is the core output of SRT — it tells you WHERE and HOW MUCH meaning
|
| 9 |
+
is under contestation in a given text.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from __future__ import annotations
|
| 13 |
+
|
| 14 |
+
from dataclasses import dataclass
|
| 15 |
+
|
| 16 |
+
import torch
|
| 17 |
+
import torch.nn as nn
|
| 18 |
+
|
| 19 |
+
from srt.config import BENConfig
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@dataclass
|
| 23 |
+
class BENOutput:
|
| 24 |
+
"""Output from BEN."""
|
| 25 |
+
|
| 26 |
+
r_hat: torch.Tensor # (B, T) reflexivity coefficient (unbounded; supervised on log-compressed r_true)
|
| 27 |
+
regime_logits: torch.Tensor # (B, T, 2) subcritical/supercritical
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class BifurcationEstimationNetwork(nn.Module):
|
| 31 |
+
"""Estimates bifurcation from RRM meta-state."""
|
| 32 |
+
|
| 33 |
+
def __init__(self, cfg: BENConfig, d_meta: int) -> None:
|
| 34 |
+
super().__init__()
|
| 35 |
+
|
| 36 |
+
# r̂ prediction: meta-state → unbounded scalar.
|
| 37 |
+
# v3 used nn.Tanh() here, which capped output at ±1. The training target
|
| 38 |
+
# is sign(r) * log1p(|r|) and r_true reaches ~12.77 (compressed ~2.55), so
|
| 39 |
+
# the tanh ceiling truncated ~25% of supercritical tokens and capped the
|
| 40 |
+
# achievable Pearson. The smooth_l1 loss on a log-compressed target is
|
| 41 |
+
# numerically well-behaved without an output activation; we keep the head
|
| 42 |
+
# unbounded and init the final linear with small weights so early outputs
|
| 43 |
+
# start near zero and the supervised gradient does the shaping.
|
| 44 |
+
self.r_head = nn.Sequential(
|
| 45 |
+
nn.Linear(d_meta, cfg.d_hidden),
|
| 46 |
+
nn.SiLU(),
|
| 47 |
+
nn.Linear(cfg.d_hidden, 1),
|
| 48 |
+
)
|
| 49 |
+
r_out: nn.Linear = self.r_head[-1] # type: ignore[assignment]
|
| 50 |
+
nn.init.normal_(r_out.weight, std=0.02)
|
| 51 |
+
nn.init.zeros_(r_out.bias)
|
| 52 |
+
|
| 53 |
+
# Regime classification: subcritical (0) vs supercritical (1)
|
| 54 |
+
self.regime_head = nn.Sequential(
|
| 55 |
+
nn.Linear(d_meta, cfg.d_hidden),
|
| 56 |
+
nn.SiLU(),
|
| 57 |
+
nn.Linear(cfg.d_hidden, 2),
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
def forward(self, meta_state: torch.Tensor) -> BENOutput:
|
| 61 |
+
"""Estimate bifurcation from accumulated meta-state.
|
| 62 |
+
|
| 63 |
+
Args:
|
| 64 |
+
meta_state: (B, T, d_meta) from RRM.
|
| 65 |
+
|
| 66 |
+
Returns:
|
| 67 |
+
BENOutput with r_hat and regime_logits.
|
| 68 |
+
"""
|
| 69 |
+
r_hat = self.r_head(meta_state).squeeze(-1) # (B, T)
|
| 70 |
+
regime_logits = self.regime_head(meta_state) # (B, T, 2)
|
| 71 |
+
return BENOutput(r_hat=r_hat, regime_logits=regime_logits)
|
src/srt/modules/community.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Unsupervised Community Discovery Head.
|
| 2 |
+
|
| 3 |
+
Discovers discourse communities from backbone hidden states without
|
| 4 |
+
predefined labels. A discourse community (in Peirce's framework) is a
|
| 5 |
+
group of language users who share interpretive norms — they assign similar
|
| 6 |
+
interpretants to the same representamens.
|
| 7 |
+
|
| 8 |
+
The community head runs at an early backbone layer (before MAH hooks) and
|
| 9 |
+
produces a soft assignment over K learned prototypes. The resulting community
|
| 10 |
+
vector conditions how MAH computes divergence, so the same sign can produce
|
| 11 |
+
different divergence patterns in different community contexts.
|
| 12 |
+
|
| 13 |
+
Training signal: the community prototypes are pulled apart by the semiotic
|
| 14 |
+
losses — if assigning text to different communities helps the model predict
|
| 15 |
+
divergence better, it will learn to separate them.
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
from __future__ import annotations
|
| 19 |
+
|
| 20 |
+
from dataclasses import dataclass
|
| 21 |
+
|
| 22 |
+
import torch
|
| 23 |
+
import torch.nn as nn
|
| 24 |
+
import torch.nn.functional as F
|
| 25 |
+
|
| 26 |
+
from srt.config import CommunityConfig
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@dataclass
|
| 30 |
+
class CommunityOutput:
|
| 31 |
+
"""Output from community discovery.
|
| 32 |
+
|
| 33 |
+
When the head runs in continuous-trajectory mode (cfg.use_prototypes=False,
|
| 34 |
+
v8a), `logits` and `weights` are None and `vector == encoded`.
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
logits: torch.Tensor | None # (B, K) raw assignment scores, or None
|
| 38 |
+
weights: torch.Tensor | None # (B, K) soft assignment probabilities, or None
|
| 39 |
+
vector: torch.Tensor # (B, d_community) community embedding (mixture or encoded)
|
| 40 |
+
encoded: torch.Tensor # (B, d_community) pre-prototype-mixing encoder output
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class CommunityDiscoveryHead(nn.Module):
|
| 44 |
+
"""Soft clustering of hidden states into discourse communities.
|
| 45 |
+
|
| 46 |
+
With cfg.use_prototypes=True (default): pooled hidden state → encoder →
|
| 47 |
+
cosine similarity to K learned prototypes → soft assignment weights →
|
| 48 |
+
weighted mixture of prototypes as the community vector. This is the
|
| 49 |
+
v3–v7 architecture.
|
| 50 |
+
|
| 51 |
+
With cfg.use_prototypes=False (v8a): pooled hidden state → encoder →
|
| 52 |
+
the encoder output IS the community vector. No discrete basis. Motivated
|
| 53 |
+
by the v7 PCA finding that prototype tensors barely move from random
|
| 54 |
+
init; the encoder was already doing the discriminative work and the
|
| 55 |
+
soft-argmax over K anchors was throwing information away.
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
def __init__(self, cfg: CommunityConfig, d_backbone: int) -> None:
|
| 59 |
+
super().__init__()
|
| 60 |
+
self.temperature = cfg.temperature
|
| 61 |
+
self.use_prototypes = cfg.use_prototypes
|
| 62 |
+
|
| 63 |
+
# Encode pooled hidden states → community space
|
| 64 |
+
self.encoder = nn.Sequential(
|
| 65 |
+
nn.Linear(d_backbone, cfg.d_community),
|
| 66 |
+
nn.SiLU(),
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
# Learnable community prototypes (only when enabled)
|
| 70 |
+
if cfg.use_prototypes:
|
| 71 |
+
self.prototypes = nn.Embedding(cfg.num_prototypes, cfg.d_community)
|
| 72 |
+
else:
|
| 73 |
+
self.prototypes = None # type: ignore[assignment]
|
| 74 |
+
|
| 75 |
+
def forward(
|
| 76 |
+
self,
|
| 77 |
+
hidden_states: torch.Tensor,
|
| 78 |
+
attention_mask: torch.Tensor | None = None,
|
| 79 |
+
) -> CommunityOutput:
|
| 80 |
+
"""Discover community from hidden states.
|
| 81 |
+
|
| 82 |
+
Args:
|
| 83 |
+
hidden_states: (B, T, d_backbone) from an early backbone layer.
|
| 84 |
+
attention_mask: (B, T) padding mask (1 = real, 0 = pad). Optional.
|
| 85 |
+
|
| 86 |
+
Returns:
|
| 87 |
+
CommunityOutput. In prototype mode, logits/weights are populated
|
| 88 |
+
and vector is the prototype-weighted mixture. In trajectory mode
|
| 89 |
+
(use_prototypes=False), logits and weights are None and vector
|
| 90 |
+
equals encoded.
|
| 91 |
+
"""
|
| 92 |
+
# Masked mean pool across positions → document-level representation
|
| 93 |
+
if attention_mask is not None:
|
| 94 |
+
mask = attention_mask.unsqueeze(-1).to(hidden_states.dtype) # (B, T, 1)
|
| 95 |
+
pooled = (hidden_states * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1)
|
| 96 |
+
else:
|
| 97 |
+
pooled = hidden_states.mean(dim=1) # (B, d_backbone)
|
| 98 |
+
encoded = self.encoder(pooled) # (B, d_community)
|
| 99 |
+
|
| 100 |
+
if not self.use_prototypes:
|
| 101 |
+
# v8a: continuous-trajectory mode — no discrete basis.
|
| 102 |
+
return CommunityOutput(
|
| 103 |
+
logits=None, weights=None, vector=encoded, encoded=encoded,
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
# Cosine similarity to prototypes
|
| 107 |
+
encoded_norm = F.normalize(encoded, dim=-1)
|
| 108 |
+
proto_norm = F.normalize(self.prototypes.weight, dim=-1)
|
| 109 |
+
logits = (encoded_norm @ proto_norm.T) / self.temperature # (B, K)
|
| 110 |
+
|
| 111 |
+
weights = F.softmax(logits, dim=-1) # (B, K)
|
| 112 |
+
vector = weights @ self.prototypes.weight # (B, d_community)
|
| 113 |
+
|
| 114 |
+
return CommunityOutput(
|
| 115 |
+
logits=logits, weights=weights, vector=vector, encoded=encoded,
|
| 116 |
+
)
|
src/srt/modules/mah.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Metapragmatic Attention Head (MAH).
|
| 2 |
+
|
| 3 |
+
Detects where meaning diverges across positions by computing the gap between
|
| 4 |
+
direct (local) interpretation and contextual (global) interpretation of each
|
| 5 |
+
token's hidden state. This is Peirce's "unlimited semiosis" made computational:
|
| 6 |
+
each sign (representamen) receives an interpretation (interpretant) that depends
|
| 7 |
+
on the surrounding discourse context. MAH quantifies where that context
|
| 8 |
+
*changes* the interpretation — i.e., where meaning forks.
|
| 9 |
+
|
| 10 |
+
The divergence vector d_t at position t captures:
|
| 11 |
+
d_t = f(interp_t) - g(attend(interp_{0..t}))
|
| 12 |
+
where f is direct projection, g is the contextual output after causal attention.
|
| 13 |
+
High ||d_t|| → the sign at position t means something different in context
|
| 14 |
+
than it would in isolation.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
from __future__ import annotations
|
| 18 |
+
|
| 19 |
+
import math
|
| 20 |
+
from dataclasses import dataclass
|
| 21 |
+
|
| 22 |
+
import torch
|
| 23 |
+
import torch.nn as nn
|
| 24 |
+
import torch.nn.functional as F
|
| 25 |
+
|
| 26 |
+
from srt.config import MAHConfig
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
@dataclass
|
| 30 |
+
class MAHOutput:
|
| 31 |
+
"""Output from a single MAH layer."""
|
| 32 |
+
|
| 33 |
+
divergence: torch.Tensor # (B, T, d_divergence)
|
| 34 |
+
attention_weights: torch.Tensor | None = None # (B, H, T, T)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
class MetapragmaticAttentionHead(nn.Module):
|
| 38 |
+
"""Single MAH layer that reads hidden states and produces divergence vectors."""
|
| 39 |
+
|
| 40 |
+
def __init__(self, cfg: MAHConfig, d_backbone: int, d_community: int = 0) -> None:
|
| 41 |
+
super().__init__()
|
| 42 |
+
d_sub = cfg.d_sub
|
| 43 |
+
|
| 44 |
+
# Project backbone hidden states → interpretant subspace
|
| 45 |
+
self.interp_proj = nn.Linear(d_backbone, d_sub, bias=False)
|
| 46 |
+
|
| 47 |
+
# Optional community conditioning
|
| 48 |
+
self.comm_proj: nn.Module | None = None
|
| 49 |
+
if d_community > 0:
|
| 50 |
+
self.comm_proj = nn.Linear(d_community, d_sub, bias=False)
|
| 51 |
+
|
| 52 |
+
# Multi-head self-attention in interpretant subspace
|
| 53 |
+
self.num_heads = cfg.num_heads
|
| 54 |
+
self.head_dim = d_sub // cfg.num_heads
|
| 55 |
+
assert d_sub % cfg.num_heads == 0
|
| 56 |
+
|
| 57 |
+
self.q_proj = nn.Linear(d_sub, d_sub, bias=False)
|
| 58 |
+
self.k_proj = nn.Linear(d_sub, d_sub, bias=False)
|
| 59 |
+
self.v_proj = nn.Linear(d_sub, d_sub, bias=False)
|
| 60 |
+
self.out_proj = nn.Linear(d_sub, d_sub, bias=False)
|
| 61 |
+
self.attn_dropout = nn.Dropout(cfg.dropout)
|
| 62 |
+
|
| 63 |
+
# Divergence output projection
|
| 64 |
+
self.div_proj = nn.Linear(d_sub, cfg.d_divergence, bias=False)
|
| 65 |
+
|
| 66 |
+
def forward(
|
| 67 |
+
self,
|
| 68 |
+
hidden_states: torch.Tensor,
|
| 69 |
+
community_vec: torch.Tensor | None = None,
|
| 70 |
+
causal_mask: torch.Tensor | None = None,
|
| 71 |
+
) -> MAHOutput:
|
| 72 |
+
"""Compute divergence from backbone hidden states.
|
| 73 |
+
|
| 74 |
+
Args:
|
| 75 |
+
hidden_states: (B, T, d_backbone) from a transformer layer.
|
| 76 |
+
community_vec: (B, d_community) soft community vector.
|
| 77 |
+
causal_mask: (1, 1, T, T) additive causal mask.
|
| 78 |
+
|
| 79 |
+
Returns:
|
| 80 |
+
MAHOutput with divergence vectors and optional attention weights.
|
| 81 |
+
"""
|
| 82 |
+
B, T, _ = hidden_states.shape
|
| 83 |
+
|
| 84 |
+
# Project to interpretant subspace
|
| 85 |
+
interp = self.interp_proj(hidden_states) # (B, T, d_sub)
|
| 86 |
+
|
| 87 |
+
# Community conditioning: shift interpretant space
|
| 88 |
+
if community_vec is not None and self.comm_proj is not None:
|
| 89 |
+
comm_bias = self.comm_proj(community_vec) # (B, d_sub)
|
| 90 |
+
interp = interp + comm_bias.unsqueeze(1)
|
| 91 |
+
|
| 92 |
+
# Multi-head causal self-attention
|
| 93 |
+
q = self.q_proj(interp).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
|
| 94 |
+
k = self.k_proj(interp).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
|
| 95 |
+
v = self.v_proj(interp).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
|
| 96 |
+
|
| 97 |
+
attn = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
|
| 98 |
+
if causal_mask is not None:
|
| 99 |
+
attn = attn + causal_mask
|
| 100 |
+
attn_weights = F.softmax(attn, dim=-1)
|
| 101 |
+
attn_weights = self.attn_dropout(attn_weights)
|
| 102 |
+
|
| 103 |
+
contextual = (attn_weights @ v).transpose(1, 2).reshape(B, T, -1)
|
| 104 |
+
contextual = self.out_proj(contextual) # (B, T, d_sub)
|
| 105 |
+
|
| 106 |
+
# Divergence = gap between direct and contextual interpretation
|
| 107 |
+
divergence = self.div_proj(interp - contextual) # (B, T, d_divergence)
|
| 108 |
+
|
| 109 |
+
return MAHOutput(divergence=divergence, attention_weights=attn_weights.detach())
|
src/srt/modules/rrm.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Reflexive Recurrent Module (RRM).
|
| 2 |
+
|
| 3 |
+
Tracks per-position semiotic meta-state via a GRU that processes divergence
|
| 4 |
+
observations from MAH layers. At injection points, produces a FiLM-style
|
| 5 |
+
modulation (gamma, beta) that multiplicatively + additively biases the
|
| 6 |
+
backbone's hidden states:
|
| 7 |
+
|
| 8 |
+
h' = h * (1 + gamma(meta_state)) + beta(meta_state)
|
| 9 |
+
|
| 10 |
+
The meta-state h_meta_t represents the model's accumulated awareness of
|
| 11 |
+
semiotic divergence at position t. Each MAH observation updates it:
|
| 12 |
+
h_meta_t^{l+1} = GRU(divergence_t^l, h_meta_t^l)
|
| 13 |
+
|
| 14 |
+
v3 used a single low-rank linear inject (gate * proj * scale) with
|
| 15 |
+
zero-initialized projection. Ablation showed the inject-back arm contributed
|
| 16 |
+
exactly nothing (every benchmark metric was identical to four decimal places
|
| 17 |
+
with injection forced to zero). The diagnosis was that the zero init plus
|
| 18 |
+
the inject-norm regularizer (which rewarded ||inj|| \u2248 1 regardless of
|
| 19 |
+
direction) drove the optimizer to satisfy the norm penalty with arbitrary
|
| 20 |
+
directions that were then orthogonal to the gradient signal from the frozen
|
| 21 |
+
backbone's CE.
|
| 22 |
+
|
| 23 |
+
v4 fixes both: FiLM modulation has a non-zero gradient pathway from the first
|
| 24 |
+
step (beta is initialized to zero so the forward is identity at init, but
|
| 25 |
+
gamma has small Gaussian init so dL/d(gamma_proj) flows immediately when the
|
| 26 |
+
downstream MAH layer's divergence is supervised by the bif/regime losses).
|
| 27 |
+
The inject-norm regularizer is dropped at the loss layer (LossConfig
|
| 28 |
+
inject_reg_weight = 0.0 by default in v4).
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
from __future__ import annotations
|
| 32 |
+
|
| 33 |
+
import torch
|
| 34 |
+
import torch.nn as nn
|
| 35 |
+
|
| 36 |
+
from srt.config import RRMConfig
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class ReflexiveRecurrentModule(nn.Module):
|
| 40 |
+
"""GRU-based reflexive meta-state tracker with FiLM-style injection."""
|
| 41 |
+
|
| 42 |
+
def __init__(self, cfg: RRMConfig, d_divergence: int, d_backbone: int) -> None:
|
| 43 |
+
super().__init__()
|
| 44 |
+
self.d_meta = cfg.d_meta
|
| 45 |
+
self.inject_scale = cfg.inject_scale
|
| 46 |
+
self.d_backbone = d_backbone
|
| 47 |
+
|
| 48 |
+
# Per-position GRU: processes divergence \u2192 meta-state
|
| 49 |
+
self.gru = nn.GRUCell(d_divergence, cfg.d_meta)
|
| 50 |
+
|
| 51 |
+
# FiLM projections: meta-state \u2192 (gamma, beta) in backbone-dim.
|
| 52 |
+
# gamma is multiplicative on (1 + gamma); beta is additive.
|
| 53 |
+
# gamma init: small Gaussian (std=0.02) so identity-at-init holds in
|
| 54 |
+
# expectation but gradient flows from the first step.
|
| 55 |
+
# beta init: zeros so identity-at-init is exact, then learns offsets.
|
| 56 |
+
self.gamma_proj = nn.Linear(cfg.d_meta, d_backbone, bias=True)
|
| 57 |
+
self.beta_proj = nn.Linear(cfg.d_meta, d_backbone, bias=True)
|
| 58 |
+
nn.init.normal_(self.gamma_proj.weight, std=0.02)
|
| 59 |
+
nn.init.zeros_(self.gamma_proj.bias)
|
| 60 |
+
nn.init.zeros_(self.beta_proj.weight)
|
| 61 |
+
nn.init.zeros_(self.beta_proj.bias)
|
| 62 |
+
|
| 63 |
+
def step(
|
| 64 |
+
self, divergence: torch.Tensor, meta_state: torch.Tensor | None
|
| 65 |
+
) -> torch.Tensor:
|
| 66 |
+
"""Update per-position meta-state with new divergence observation.
|
| 67 |
+
|
| 68 |
+
Args:
|
| 69 |
+
divergence: (B, T, d_divergence) from MAH.
|
| 70 |
+
meta_state: (B, T, d_meta) or None for initial state.
|
| 71 |
+
|
| 72 |
+
Returns:
|
| 73 |
+
Updated meta-state (B, T, d_meta).
|
| 74 |
+
"""
|
| 75 |
+
B, T, d_div = divergence.shape
|
| 76 |
+
div_flat = divergence.reshape(B * T, d_div)
|
| 77 |
+
|
| 78 |
+
if meta_state is None:
|
| 79 |
+
meta_flat = torch.zeros(
|
| 80 |
+
B * T, self.d_meta, device=divergence.device, dtype=divergence.dtype
|
| 81 |
+
)
|
| 82 |
+
else:
|
| 83 |
+
meta_flat = meta_state.reshape(B * T, self.d_meta)
|
| 84 |
+
|
| 85 |
+
meta_flat = self.gru(div_flat, meta_flat)
|
| 86 |
+
return meta_flat.reshape(B, T, self.d_meta)
|
| 87 |
+
|
| 88 |
+
def inject(
|
| 89 |
+
self, meta_state: torch.Tensor, hidden_states: torch.Tensor
|
| 90 |
+
) -> torch.Tensor:
|
| 91 |
+
"""Produce FiLM modulation correction for backbone hidden states.
|
| 92 |
+
|
| 93 |
+
Returns the *correction* (h' - h) = h * gamma + beta, NOT h'. The
|
| 94 |
+
caller adds this to h to get h'. This keeps the rest of the adapter
|
| 95 |
+
and the diagnostic logging (injection norm tracking) unchanged: the
|
| 96 |
+
\"injection\" tensor is still the additive correction applied to h.
|
| 97 |
+
|
| 98 |
+
Args:
|
| 99 |
+
meta_state: (B, T, d_meta) current reflexive awareness.
|
| 100 |
+
hidden_states: (B, T, d_backbone) current hidden states.
|
| 101 |
+
|
| 102 |
+
Returns:
|
| 103 |
+
Correction vector (B, T, d_backbone) to add to hidden_states.
|
| 104 |
+
"""
|
| 105 |
+
gamma = self.gamma_proj(meta_state) # (B, T, d_backbone)
|
| 106 |
+
beta = self.beta_proj(meta_state) # (B, T, d_backbone)
|
| 107 |
+
# FiLM: h' = h * (1 + gamma) + beta \u2192 correction = h * gamma + beta
|
| 108 |
+
correction = hidden_states * gamma + beta
|
| 109 |
+
return correction * self.inject_scale
|