fintfm 0.5.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. fintfm-0.5.5/LICENSE +202 -0
  2. fintfm-0.5.5/PKG-INFO +407 -0
  3. fintfm-0.5.5/README.md +367 -0
  4. fintfm-0.5.5/pyproject.toml +81 -0
  5. fintfm-0.5.5/pyproject.toml.orig +96 -0
  6. fintfm-0.5.5/src/fintfm/__init__.py +33 -0
  7. fintfm-0.5.5/src/fintfm/config.py +329 -0
  8. fintfm-0.5.5/src/fintfm/configs/default.yaml +87 -0
  9. fintfm-0.5.5/src/fintfm/evaluation/__init__.py +24 -0
  10. fintfm-0.5.5/src/fintfm/evaluation/bench.py +259 -0
  11. fintfm-0.5.5/src/fintfm/evaluation/boosting.py +109 -0
  12. fintfm-0.5.5/src/fintfm/evaluation/datasets.py +376 -0
  13. fintfm-0.5.5/src/fintfm/evaluation/fetch.py +115 -0
  14. fintfm-0.5.5/src/fintfm/evaluation/metrics.py +311 -0
  15. fintfm-0.5.5/src/fintfm/experiments/__init__.py +5 -0
  16. fintfm-0.5.5/src/fintfm/experiments/capability.py +1074 -0
  17. fintfm-0.5.5/src/fintfm/experiments/context_sweep.py +245 -0
  18. fintfm-0.5.5/src/fintfm/experiments/openml_breadth.py +227 -0
  19. fintfm-0.5.5/src/fintfm/experiments/prior_ablation.py +621 -0
  20. fintfm-0.5.5/src/fintfm/experiments/prior_score.py +302 -0
  21. fintfm-0.5.5/src/fintfm/experiments/retrieval_grouping.py +279 -0
  22. fintfm-0.5.5/src/fintfm/experiments/term_structure.py +279 -0
  23. fintfm-0.5.5/src/fintfm/experiments/v4_out_of_time.py +362 -0
  24. fintfm-0.5.5/src/fintfm/experiments/v4_protocol.py +600 -0
  25. fintfm-0.5.5/src/fintfm/inference/__init__.py +6 -0
  26. fintfm-0.5.5/src/fintfm/inference/binning.py +248 -0
  27. fintfm-0.5.5/src/fintfm/inference/categorical.py +259 -0
  28. fintfm-0.5.5/src/fintfm/inference/classifier.py +661 -0
  29. fintfm-0.5.5/src/fintfm/inference/preprocess.py +114 -0
  30. fintfm-0.5.5/src/fintfm/inference/regressor.py +190 -0
  31. fintfm-0.5.5/src/fintfm/inference/retrieval.py +247 -0
  32. fintfm-0.5.5/src/fintfm/modeling/__init__.py +6 -0
  33. fintfm-0.5.5/src/fintfm/modeling/hazard.py +222 -0
  34. fintfm-0.5.5/src/fintfm/modeling/model.py +671 -0
  35. fintfm-0.5.5/src/fintfm/modeling/train.py +536 -0
  36. fintfm-0.5.5/src/fintfm/prior/__init__.py +16 -0
  37. fintfm-0.5.5/src/fintfm/prior/base.py +139 -0
  38. fintfm-0.5.5/src/fintfm/prior/crossed.py +180 -0
  39. fintfm-0.5.5/src/fintfm/prior/financial.py +634 -0
  40. fintfm-0.5.5/src/fintfm/prior/mixture.py +242 -0
  41. fintfm-0.5.5/src/fintfm/prior/scm.py +353 -0
  42. fintfm-0.5.5/src/fintfm/prior/tree.py +169 -0
  43. fintfm-0.5.5/src/fintfm/prior/trivial.py +79 -0
  44. fintfm-0.5.5/src/fintfm/py.typed +0 -0
fintfm-0.5.5/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
fintfm-0.5.5/PKG-INFO ADDED
@@ -0,0 +1,407 @@
1
+ Metadata-Version: 2.4
2
+ Name: fintfm
3
+ Version: 0.5.5
4
+ Summary: A tabular foundation model for financial risk — pretrained on synthetic company financials, so it predicts credit default with no training on your data
5
+ Author: Mukharbek Organokov
6
+ Author-email: Mukharbek Organokov <mukharbek.organokov@gmail.com>
7
+ License-Expression: Apache-2.0
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Financial and Insurance Industry
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Classifier: Typing :: Typed
16
+ Requires-Dist: numpy>=2.0
17
+ Requires-Dist: pandas>=2.2
18
+ Requires-Dist: scikit-learn>=1.5
19
+ Requires-Dist: pyyaml>=6.0
20
+ Requires-Dist: scipy>=1.18.1
21
+ Requires-Dist: torch>=2.4
22
+ Requires-Dist: catboost>=1.2 ; extra == 'bench'
23
+ Requires-Dist: lightgbm>=4.0 ; extra == 'bench'
24
+ Requires-Dist: xgboost>=2.0 ; extra == 'bench'
25
+ Requires-Dist: pyarrow>=17 ; extra == 'bench'
26
+ Requires-Dist: huggingface-hub>=0.34 ; extra == 'hf'
27
+ Requires-Dist: kaggle>=1.6 ; extra == 'kaggle'
28
+ Requires-Dist: kagglehub>=0.3 ; extra == 'kaggle'
29
+ Requires-Dist: pyarrow>=17 ; extra == 'kaggle'
30
+ Requires-Python: >=3.12
31
+ Project-URL: Homepage, https://github.com/kabartay/fintfm
32
+ Project-URL: Repository, https://github.com/kabartay/fintfm
33
+ Project-URL: Changelog, https://github.com/kabartay/fintfm/blob/main/docs/CHANGELOG.md
34
+ Project-URL: Checkpoint, https://huggingface.co/kabartay/fintfm-binary
35
+ Project-URL: Measurement log, https://github.com/kabartay/fintfm/blob/main/docs/results/FINDINGS.md
36
+ Provides-Extra: bench
37
+ Provides-Extra: hf
38
+ Provides-Extra: kaggle
39
+ Description-Content-Type: text/markdown
40
+
41
+ # FinTFM
42
+
43
+ [![CI](https://github.com/kabartay/fintfm/actions/workflows/ci.yml/badge.svg)](https://github.com/kabartay/fintfm/actions/workflows/ci.yml)
44
+ [![License](https://img.shields.io/badge/license-Apache--2.0-green.svg)](LICENSE)
45
+ [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](pyproject.toml)
46
+ [![Checkpoint](https://img.shields.io/badge/%F0%9F%A4%97%20weights-fintfm--binary-yellow)](https://huggingface.co/kabartay/fintfm-binary)
47
+ [![TabArena](https://img.shields.io/badge/TabArena-93rd%20of%2095-critical)](docs/results/TABARENA.md)
48
+
49
+ **A tabular foundation model for corporate credit risk, built from scratch and measured in
50
+ public.**
51
+
52
+ Given a table of labelled rows, FinTFM predicts new rows in a **single forward pass**, with your
53
+ data supplied as context rather than trained on. There are no gradient steps at fit time and no
54
+ per-dataset tuning — the model is pretrained once, on **synthetic data only**, and never sees a
55
+ real table during training.
56
+
57
+ That last property is the point. A model that provably never saw your benchmark cannot have
58
+ memorised it, and in a regulated domain the ability to *demonstrate* that is worth more than a
59
+ few points of accuracy.
60
+
61
+ ```python
62
+ from huggingface_hub import hf_hub_download
63
+ from fintfm.inference import FinancialTFMClassifier
64
+
65
+ ckpt = hf_hub_download("kabartay/fintfm-binary", "v4-cellattn-labels.pt")
66
+ clf = FinancialTFMClassifier(ckpt, device="cpu")
67
+ clf.fit(X_train, y_train) # stores the table as context; no training happens
68
+ pd_estimates = clf.predict_proba(X_test)[:, 1]
69
+ ```
70
+
71
+ The checkpoint is on Hugging Face at
72
+ [**kabartay/fintfm-binary**](https://huggingface.co/kabartay/fintfm-binary) — 885K parameters,
73
+ binary, up to 136 features, **Apache-2.0**. It is the checkpoint every published binary number
74
+ below was measured on, so those results are reproducible against this file rather than a
75
+ variant of it.
76
+
77
+ ## Status, stated plainly
78
+
79
+ **FinTFM is a research codebase with a public claims ledger, not a product.** It exists to find
80
+ out whether in-context tabular learning can be made competitive with gradient-boosted trees on
81
+ financial tables, and to say honestly where it currently is not.
82
+
83
+ | | |
84
+ | --- | --- |
85
+ | **External benchmark** | [TabArena](https://tabarena.ai), 27 binary datasets against 94 other methods: **rank 93 of 95** |
86
+ | **On real credit panels** | calibration consistently among the best measured; discrimination consistently loses to tuned gradient boosting — both, on every panel tried |
87
+ | **Licence** | Apache-2.0, **code and weights** — chosen separately, not inherited (see [Licensing](#licensing--provenance)) |
88
+ | **Checkpoint** | [kabartay/fintfm-binary](https://huggingface.co/kabartay/fintfm-binary) — 885K, binary, ≤136 features |
89
+ | **Tests** | 246, plus `ruff`, the openspec validator, a dependency-licence check and a documentation-link check — all in CI |
90
+ | **Measurement log** | 121 numbered findings, each declaring how its numbers were produced |
91
+ | **Problem types** | binary declared; multiclass and regression implemented but **not** declared (§121) |
92
+
93
+ **Read [`docs/paper/CLAIMS.md`](docs/paper/CLAIMS.md) before anything else.** Every claim this
94
+ project could make is tagged SURVIVES / SINGLE DRAW / SUPERSEDED / RETRACTED / OPEN against its
95
+ evidence. That file, not this one, is the source of truth — and it records what stopped being
96
+ true as prominently as what holds.
97
+
98
+ > Throughout this repository, **§N** refers to entry N in
99
+ > [`docs/results/FINDINGS.md`](docs/results/FINDINGS.md), a measurement log in which every number states how it
100
+ > was produced (MEASURED, SMOKE-TEST, SIMULATED or ESTIMATED) and negative results are kept
101
+ > deliberately, because they are what stops the same wrong conclusion being reached twice.
102
+
103
+ ## Results, as measured
104
+
105
+ TabArena, 27 binary datasets, one fold each, against 94 other methods:
106
+
107
+ | change | mean ROC-AUC | Elo | rank |
108
+ | --- | --- | --- | --- |
109
+ | label encoding (§98) | 0.7642 | 662 | 93 / 95 |
110
+ | **+ out-of-fold target statistics** (§101) | **0.7823** | 765 | 93 / 95 |
111
+ | + multiclass-capable prior (§105) | 0.7817 | **813** | 93 / 95 |
112
+ | + 5.0M parameters, matched task count (§114) | 0.7774 | 751 | 93 / 95 |
113
+ | + tree-structured prior (§115), two seeds | 0.7926 / 0.7913 | 842 / 826 | 93 / 95 |
114
+
115
+ **One change has moved the number on the benchmark that matters, and it was preprocessing
116
+ rather than architecture.** The tree prior adds a further +0.0094 here and replicates across two
117
+ seeds — but costs **−0.0221 average precision on credit data** (§116), negative on 5 of 5 folds
118
+ with three surviving multiple-comparison correction at p < 0.001, so it ships off by default.
119
+ Everything else tried — parameter scale at matched task volume, training volume, a widened
120
+ structural-causal prior — has been null or negative. **The rank has never moved.**
121
+
122
+ ## What this project does that others do not
123
+
124
+ Three things, stated at their true weight:
125
+
126
+ **Incoherent PD term structures are impossible by construction.** The field's standard
127
+ per-horizon construction produces non-monotone cumulative default curves for **39% of firms** on
128
+ real data — a firm whose 3-year default probability is below its 2-year. A hazard head makes
129
+ that unrepresentable, at zero measured accuracy cost.
130
+
131
+ **A severe capacity defect was found by measurement, not review.** The original architecture had
132
+ capped discrimination regardless of true task difficulty, caught against an exactly-known
133
+ Bayes-optimal AUC. Its cause was isolated to the architecture rather than the prior after
134
+ eliminating seven other candidates one at a time, then closed by a two-way cell-attention change
135
+ worth +0.042 average precision on real data.
136
+
137
+ **The record corrects itself in public.** This README has been wrong about its own results at
138
+ least twice (§107, §112). Both are retracted in place, with the reasoning kept. No peer project
139
+ publishes a document that tags its own claims RETRACTED as prominently as its wins, and in a
140
+ domain where a model must arrive with its own validation evidence, that is the differentiator.
141
+
142
+ ## How it works
143
+
144
+ 1. **Priors** (`src/fintfm/prior/`) — synthetic task generators, sampled and mixed per batch
145
+ (`mixture.py`).
146
+ - `financial.py` — a structural generative story for company balance sheets, P&L and
147
+ default labels: accounting identities, sector and macro effects, a wide derived-ratio
148
+ family, missingness, a sharpness (signal-to-noise) knob, and a default-rate envelope that
149
+ can reach real low-default-portfolio rates (~0.2%).
150
+ - `scm.py` — a generic random-graph structural-causal-model prior (the TabPFN/TabICL-style
151
+ idea): random layered functions with several nonlinearities, for general nonlinear and
152
+ multiclass structure the financial prior does not cover.
153
+ - `tree.py` — ensembles of oblivious decision trees, generating the **axis-aligned,
154
+ piecewise-constant** structure real tabular data is full of and the other priors do not.
155
+ Added on *distinctiveness* grounds after `fintfm-priorscore` measured it as the only
156
+ member of the mixture with a positive tree-versus-linear gap (§112). Off by default
157
+ (`p_tree=0.0`).
158
+ - `trivial.py`, `crossed.py` — diagnostic-only priors used to isolate specific hypotheses
159
+ (whether the architecture can learn at all; whether a prior's features or its label
160
+ mechanism carries a measured effect). Not part of the default training mixture.
161
+ 2. **Model** (`src/fintfm/modeling/model.py`) — a from-scratch Transformer. Cells are embedded
162
+ individually and carry a random per-task column identity (so the model can tell columns
163
+ apart without a positional embedding, which would break invariance to column order).
164
+ Columns attend to each other within a row; optionally — `ModelConfig.n_cell_blocks`,
165
+ currently experimental — cells also attend across rows *within one feature* before that,
166
+ giving each column a distribution-derived identity rather than only a random tag. Rows are
167
+ then pooled and attend to context rows to perform in-context learning. An optional hazard
168
+ head (`modeling/hazard.py`) produces a cumulative PD term structure that is monotone by
169
+ construction. Independent implementation of ideas described in the public TabPFN / TabICL
170
+ literature — no code or weights from any existing project (see Licensing below).
171
+ 3. **Training** (`src/fintfm/modeling/train.py`, `fintfm-train`) — infinite synthetic data, one
172
+ gradient step per fresh batch, cosine LR schedule, checkpointing, a held-out quality metric
173
+ that reports per-task AUC (not the pooled-across-tasks number, which is inflated whenever
174
+ task base rates differ) and Brier skill against a base-rate-only predictor.
175
+ 4. **Inference** (`src/fintfm/inference/`) — an sklearn-compatible `FinancialTFMClassifier`:
176
+ `fit()` stores the table as context, `predict_proba()` runs the frozen network. Several
177
+ context-construction strategies (uniform, balanced, hybrid, retrieval, prototype) and a
178
+ base-rate correction, plus ensembling over column-identity draws to recover the
179
+ distributional column-order invariance a random identity trades for expressiveness.
180
+ `inference/categorical.py` encodes categorical columns as **out-of-fold** smoothed target
181
+ statistics, because the model reads every cell as an ordered scalar and label encoding's
182
+ arbitrary order is measurably worse than no order at all (§100). The out-of-fold step is
183
+ not a refinement: the naive form puts a row's own label into its own encoding, which makes
184
+ the context self-predictive and the feature absent at query time — it harms the model
185
+ rather than flattering the score, so it survives careless validation.
186
+ `inference/regressor.py` adds a `FinancialTFMRegressor` on the same frozen network and no
187
+ new architecture: a continuous target cut into K quantile bins is an integer index over K
188
+ outcomes, so the existing classification head regresses as-is, and the output is natively
189
+ **distributional** — quantiles and prediction intervals come free, and the predicted
190
+ density can be bimodal, which is what loss given default actually is and what a Gaussian
191
+ head cannot represent.
192
+ 5. **Evaluation** (`src/fintfm/evaluation/`, `src/fintfm/experiments/`) — real corporate-default
193
+ panels (V4FinBench via its published protocol, `fintfm-v4protocol`; Polish and Taiwan
194
+ bankruptcy, `fintfm-bench`), an out-of-time harness, a synthetic capability suite
195
+ (`fintfm-capability`, including a class-count sweep for multiclass, §99) with probes of a
196
+ *known* ceiling — some with a closed-form
197
+ Bayes-optimal AUC — specifically built to catch a model that looks fine on average while
198
+ capped in a way an aggregate score cannot see. Average precision is reported alongside
199
+ ROC-AUC everywhere, and read first at low base rates (ROC-AUC's chance floor is 0.5
200
+ regardless of prevalence; AP's floor is the prevalence itself, so it stays legible at the
201
+ base rates this project's target segment actually has).
202
+ `fintfm-priorscore` scores a *prior* rather than a model, on the three criteria the
203
+ literature converged on — performance, diversity, distinctiveness — using **fitted**
204
+ baselines only, so it cannot confuse "the prior lacks this structure" with "our model cannot
205
+ learn it". Its first version could, and §112 is the record of what that cost.
206
+
207
+ ## Quickstart
208
+
209
+ ```bash
210
+ uv sync --extra bench --extra hf # naming one extra uninstalls the others
211
+ uv run pytest # 246 tests; 1 skip is expected, more means look
212
+ ```
213
+
214
+ ### Using a checkpoint
215
+
216
+ The estimators are scikit-learn compatible. `fit()` **stores** the table as context — it takes
217
+ no gradient steps — and `predict_proba()` runs the frozen network once.
218
+
219
+ ```python
220
+ from fintfm.inference import FinancialTFMClassifier, FinancialTFMRegressor
221
+
222
+ clf = FinancialTFMClassifier(ckpt, device="mps") # ckpt from hf_hub_download, above
223
+ clf.fit(X_train, y_train) # stores context; no training happens
224
+ proba = clf.predict_proba(X_test)[:, 1]
225
+
226
+ reg = FinancialTFMRegressor("runs/v4-regression.pt", n_bins=10)
227
+ reg.fit(X_train, y_cont)
228
+ point = reg.predict(X_test) # distribution mean
229
+ lo, hi = reg.predict_interval(X_test, 0.8) # 80% interval, free from the same head
230
+ ```
231
+
232
+ Categorical columns need encoding before they reach the model — it reads every cell as an
233
+ ordered scalar, and label encoding is measurably worse than no order at all (§100). Use
234
+ `fintfm.inference.categorical.CategoricalTargetEncoder`, which is out-of-fold on the context
235
+ rows for reasons that are **not** optional; see [How it works](#how-it-works).
236
+
237
+ ### Training a checkpoint
238
+
239
+ ```bash
240
+ uv run fintfm-train --steps 300 --d-model 32 --d-cell 16 --n-layers 2 --max-features 16 \
241
+ --max-classes 2 --device cpu --out runs/v0-smoke.pt # pipeline check, a couple of minutes
242
+ uv run fintfm-bench --model runs/v0-smoke.pt --credit # real corporate-default panels
243
+ ```
244
+
245
+ That smoke config exists to check the pipeline runs, not to produce a usable checkpoint — see
246
+ [`docs/infra/COMPUTE.md`](docs/infra/COMPUTE.md) for measured step costs at real scale. A real pretraining
247
+ run (thousands of steps, `--d-model 128`+, `--max-features` matching your data) takes
248
+ hours-to-a-day and needs a GPU: `--device mps` on Apple Silicon, `--device cuda`, or see
249
+ [`docs/infra/HF_JOBS.md`](docs/infra/HF_JOBS.md) for the Hugging Face Jobs recipe this project actually
250
+ uses for training runs. **Check `uptime` before running anything heavy locally** — see
251
+ [`CLAUDE.md`](CLAUDE.md) for why.
252
+
253
+ Both `fintfm-bench --credit` (Polish/Taiwan need 64/95 features) and `fintfm-v4protocol`
254
+ (V4FinBench needs 136) will print `SKIPPED for fintfm: model takes 16 features, data has N` —
255
+ correct, expected behaviour for the smoke checkpoint above, not a bug. Baselines still run and
256
+ score normally; only the FinTFM arm needs a checkpoint pretrained with a matching
257
+ `--max-features` to be evaluated.
258
+
259
+ ## Configuration
260
+
261
+ The numbers experiments use — split years, context sizes, strategies, seeds, scoring
262
+ thresholds, the prior's default-rate and sharpness envelope — live in
263
+ [`src/fintfm/configs/default.yaml`](src/fintfm/configs/default.yaml), not scattered through
264
+ the code. Every entry point takes `--config` with a file that is **deep-merged** over that
265
+ default, so an override carries only what it changes:
266
+
267
+ ```bash
268
+ uv run fintfm-ctxsweep --model runs/m.pt --config configs/context-sweep-3seed.yaml
269
+ uv run fintfm-v4oot --model runs/m.pt --config configs/retrieval-best.yaml
270
+ ```
271
+
272
+ Resolution order is packaged default → `--config` (or `$FINTFM_CONFIG`) → explicit CLI flag.
273
+ Runs print the layers they used and record them as `config_sources` in their output JSON.
274
+ Unknown keys are refused by name rather than ignored, and an overlapping train/test split is
275
+ rejected before the run starts. [`configs/README.md`](configs/README.md) explains what
276
+ belongs in configuration and what deliberately stays in code; several files under
277
+ [`configs/`](configs/) are **deliberately diagnostic, not production** (their own headers say
278
+ so), used to isolate a single variable while chasing a specific finding.
279
+
280
+ ## Licensing / provenance
281
+
282
+ Everything here — the prior, the architecture, the training loop — is original code written
283
+ for this project. **No weights, datasets, or source from Neuralk (Seldon), Fundamental
284
+ (NEXUS), Google TabFM, TabPFN, TabICL, TabDPT, or any other tabular-foundation-model product
285
+ are used or may be added.** Those are cited in project discussion purely as public
286
+ research/product context. Every third-party dataset or dependency's licence is checked before
287
+ use, and a *weight* licence is checked separately from its *code* licence, every time — never
288
+ assumed from a prior check. Direct dependencies are all permissive — numpy, pandas and
289
+ scikit-learn BSD-3, scipy BSD-3, torch BSD-3, PyYAML MIT, and the optional benchmark extras
290
+ lightgbm MIT, xgboost Apache-2.0, catboost Apache-2.0, pyarrow Apache-2.0 — and
291
+ `scripts/check_licences.py` enforces that in CI rather than leaving it to this paragraph.
292
+
293
+ **One honest exception, which CI found and this paragraph previously did not mention.** On
294
+ **Linux**, `torch` pulls in around fifteen NVIDIA CUDA runtime packages that are **NVIDIA
295
+ Proprietary**, not permissive. They are a transitive runtime dependency rather than a choice
296
+ made here, this project does **not redistribute them** — `uv build` produces a pure-Python
297
+ wheel and pip fetches them from PyPI under NVIDIA's own terms — and they are absent on macOS,
298
+ which is why a check run only on a developer's Mac reported everything permissive while CI did
299
+ not. **Anyone shipping this in a product must read NVIDIA's EULA themselves**; it is not
300
+ something this repository can assert on their behalf.
301
+
302
+ ## What would change the picture
303
+
304
+ Stated so the project is falsifiable rather than open-ended. The ~0.035 deficit to the field
305
+ has no measured axis of variation, and these are the remaining candidates:
306
+
307
+ | still open | why it is a candidate | status |
308
+ | --- | --- | --- |
309
+ | **factorized attention** | the encoder is memory-bound at every turn, and three peers independently chose the cheaper form | proposed (44.x), prior art recorded |
310
+ | **a joint objective** | `p(x, y \| D)` rather than `p(y \| x, D)` makes every column a training signal, not just the target | proposed (48.15), scoped as a measurement before a rewrite |
311
+ | **prior design** | the only lever a peer's own ablations identify as decisive | instrument built and partly falsified — see below |
312
+
313
+ ### Closed by measurement
314
+
315
+ Not abandoned — **tested and ruled out**, which is the more useful half of the record and the
316
+ reason the list above is short:
317
+
318
+ | candidate | what the measurement said |
319
+ | --- | --- |
320
+ | parameter scale | **−0.0049** at 5.7× the parameters on *matched* task volume (§114). A peer's published curve returns +0.0049 R² for 16.7×, against a 0.035 deficit. |
321
+ | training volume | null at 5× (§93); **+0.0028** at 2× (§114). |
322
+ | depth over width | **could not be scored at all** — the harness's per-dataset time limit, after 8 of 27 datasets (§114). Depth costs inference time and this model is already slow. |
323
+ | `column_id_dim` | peaks at the value chosen by accident; all four non-peak arms below it on all five folds (§104). |
324
+ | a widened structural-causal prior | **p = 1.000** against its own matched control. |
325
+ | a tree-structured prior | +0.0094 on general tabular data, replicated across two seeds (§115) — and **−0.0221 average precision on credit** (§116). Ships off by default. |
326
+
327
+ **The prior-scoring instrument is half-confirmed and half-falsified.** It predicted the
328
+ general-tabular gain above before it was measured (§112 → §115). A second arm, added to ask the
329
+ credit question, then predicted the wrong direction on its first real test — raising the
330
+ structural-causal prior's share cost **−0.0339 AP**, 0 of 5 folds, all five significant (§118).
331
+ So it predicts **breadth, not fit**, and no claim rests on its credit arm.
332
+
333
+ ## Reproducing the measurements
334
+
335
+ Every number in [`docs/results/FINDINGS.md`](docs/results/FINDINGS.md) names the command that produced it.
336
+ The entry points:
337
+
338
+ | command | what it measures |
339
+ | --- | --- |
340
+ | `fintfm-v4protocol` | V4FinBench under its **published** five-fold protocol — the benchmark this project's claims rest on |
341
+ | `fintfm-bench --credit` | Polish and Taiwan bankruptcy panels |
342
+ | `fintfm-v4oot` | out-of-time split, which the published protocol is not |
343
+ | `fintfm-capability` | synthetic probes with a **known** ceiling, some with a closed-form Bayes-optimal AUC |
344
+ | `fintfm-priorscore` | scores a *prior*, not a model, on performance / diversity / distinctiveness |
345
+ | `fintfm-ctxsweep` | context construction, which explains more variance than model family (§5) |
346
+
347
+ Two conventions worth knowing before reading any of it. **Every number declares how it was
348
+ produced** — SMOKE-TEST, MEASURED, SIMULATED or ESTIMATED — because in an ML repository a wrong
349
+ number does not crash, it looks like a result. And **negative and superseded results are kept**,
350
+ because they are what stops the same wrong conclusion being reached twice.
351
+
352
+ ## Where this is going
353
+
354
+ [`docs/`](docs/) holds the project's reasoning, indexed in [`docs/README.md`](docs/README.md).
355
+
356
+ - [`docs/paper/CLAIMS.md`](docs/paper/CLAIMS.md) — **start here.** Every claim this project
357
+ could make, tagged by status, newest evidence wins.
358
+ - [`docs/results/FINDINGS.md`](docs/results/FINDINGS.md) — the full measurement log, numbered sequentially
359
+ (121 entries and counting), each declaring how its numbers were produced.
360
+ - [`docs/design/DECISIONS.md`](docs/design/DECISIONS.md) — why the project is built the way it is, and what
361
+ would reverse each choice.
362
+ - [`docs/roadmap/STRATEGY.md`](docs/roadmap/STRATEGY.md) — the plan of record.
363
+ - [`docs/design/ARCHITECTURE.md`](docs/design/ARCHITECTURE.md) — how the model works, in more depth than
364
+ this file.
365
+ - [`docs/results/TABARENA.md`](docs/results/TABARENA.md) — the external-evaluation recipe, the coverage
366
+ fraction any score must carry, and four silent failure modes including a results cache that
367
+ returns stale numbers after a preprocessing change.
368
+ - [`docs/paper/RELATED_WORK.md`](docs/paper/RELATED_WORK.md) — the competing models, read from
369
+ primary sources, with what each costs this project's positioning. Its digest is the shortest
370
+ useful summary of why the remaining lever is the prior.
371
+ - [`docs/results/POSTMORTEM.md`](docs/results/POSTMORTEM.md) — wrong diagnoses, each caught by measurement
372
+ rather than review, kept on the record deliberately.
373
+ - [`openspec/changes/`](openspec/changes/) — the live roadmap as structured proposals with
374
+ verifiable tasks, not prose. `uv run python openspec/tools/validate.py` checks every
375
+ proposal is well-formed and every finding declares its provenance.
376
+
377
+ Short version: the mechanism claims ("no training on your data", "no feature engineering") are
378
+ already owned by better-funded competitors, so the thesis is not the mechanism. It is a credit
379
+ model that arrives with its own validation evidence — calibrated, auditably free of benchmark
380
+ contamination, and eventually backed by a pre-registered forward track record that cannot be
381
+ bought — plus a public, self-correcting record of what has and has not been shown to be true.
382
+
383
+ ## Citing
384
+
385
+ A `CITATION.cff` is in the repository root, so GitHub's **"Cite this repository"** button
386
+ renders BibTeX and APA directly.
387
+
388
+ Cite the **repository** for the method, the measurement log or any finding; cite the
389
+ **checkpoint** ([kabartay/fintfm-binary](https://huggingface.co/kabartay/fintfm-binary)) when
390
+ the specific weights matter to what you are reporting. They are different artifacts and a
391
+ reader can only check the one you name.
392
+
393
+ ## Contributing, and what cannot come in
394
+
395
+ Issues and discussion are welcome. Two hard boundaries, both of which protect the only claim
396
+ this project has that competitors do not:
397
+
398
+ **No code, weights, or training data from any tabular-foundation-model product** — TabPFN,
399
+ TabICL, TabDPT, LimiX, Nori, MITRA, or any other — may enter this repository. Their published
400
+ papers are legitimate to read and cite, and [`docs/paper/RELATED_WORK.md`](docs/paper/RELATED_WORK.md)
401
+ does exactly that for ten of them. Ingesting any of it would destroy the provenance argument
402
+ above, and nothing would warn us.
403
+
404
+ **Check a weights licence separately from its code licence, every time.** Four of the ten peer
405
+ projects read for this release ship permissive code with **non-commercial weights**, a split
406
+ invisible from a repository's headline licence badge. One of them restricts commercial use of
407
+ the model's *output*, not merely the weights.